From 5fd16a17af067e0742f9abe79d6cfb1de34def4c Mon Sep 17 00:00:00 2001 From: Wadeck Follonier Date: Sun, 16 Oct 2022 22:34:37 +0200 Subject: [PATCH 01/15] [JENKINS-69869] Categorize the user properties --- core/src/main/java/hudson/model/User.java | 34 ++++ .../main/java/hudson/model/UserProperty.java | 29 +++ .../hudson/model/UserPropertyDescriptor.java | 54 +++++ .../userproperty/UserPropertyCategory.java | 186 ++++++++++++++++++ .../UserPropertyCategoryAccountAction.java | 153 ++++++++++++++ ...UserPropertyCategoryPreferencesAction.java | 126 ++++++++++++ .../UserPropertyCategorySecurityAction.java | 127 ++++++++++++ .../hudson/model/User/configure.jelly | 1 + .../hudson/model/User/sidepanel.jelly | 3 +- .../model/userproperty/Messages.properties | 44 +++++ .../index.jelly | 72 +++++++ .../index.properties | 25 +++ .../index.jelly | 74 +++++++ .../index.properties | 24 +++ .../index.jelly | 75 +++++++ .../index.properties | 24 +++ 16 files changed, 1050 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/hudson/model/userproperty/UserPropertyCategory.java create mode 100644 core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAccountAction.java create mode 100644 core/src/main/java/hudson/model/userproperty/UserPropertyCategoryPreferencesAction.java create mode 100644 core/src/main/java/hudson/model/userproperty/UserPropertyCategorySecurityAction.java create mode 100644 core/src/main/resources/hudson/model/userproperty/Messages.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index.jelly create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryPreferencesAction/index.jelly create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryPreferencesAction/index.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategorySecurityAction/index.jelly create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategorySecurityAction/index.properties diff --git a/core/src/main/java/hudson/model/User.java b/core/src/main/java/hudson/model/User.java index 8f9ca606dca9..b3be4e7bb040 100644 --- a/core/src/main/java/hudson/model/User.java +++ b/core/src/main/java/hudson/model/User.java @@ -41,12 +41,14 @@ import hudson.init.Initializer; import hudson.model.Descriptor.FormException; import hudson.model.listeners.SaveableListener; +import hudson.model.userproperty.UserPreferencesProperty; import hudson.security.ACL; import hudson.security.AccessControlled; import hudson.security.SecurityRealm; import hudson.security.UserMayOrMayNotExistException2; import hudson.util.FormApply; import hudson.util.FormValidation; +import hudson.util.HttpResponses; import hudson.util.RunList; import hudson.util.XStream2; import java.io.File; @@ -336,6 +338,29 @@ public synchronized void addProperty(@NonNull UserProperty p) throws IOException properties = ps; save(); } + + /** + * Expand {@link #addProperty(UserProperty)} for multiple properties to be done at once. + * Expected to be used by the categorized configuration pages to update part of the properties. + * The properties not included in the list will be let untouched. + * It will call the {@link UserProperty#setUser(User)} method and at the end, {@link #save()} once. + * + * @since TODO + */ + public synchronized void addProperties(@NonNull List multipleProperties) throws IOException { + List newProperties = new ArrayList<>(this.properties); + for (UserProperty property : multipleProperties) { + UserProperty oldProp = getProperty(property.getClass()); + if (oldProp != null) { + newProperties.remove(oldProp); + } + newProperties.add(property); + property.setUser(this); + } + + this.properties = newProperties; + this.save(); + } /** * List of all {@link UserProperty}s exposed primarily for the remoting API. @@ -859,6 +884,15 @@ public Api getApi() { */ @POST public void doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, FormException { + // FIXME DRAFT system property + if (true) { + LOGGER.warning(() -> + "Attempt to use the legacy /configSubmit endpoint of user login=" + this.id + + ". The global configuration page has been deprecated in favor of categorized pages. For more details, see JENKINS-69869." + ); + throw HttpResponses.error(400, "The user global configuration page was split into categorized individual pages. See JENKINS-69869."); + } + checkPermission(Jenkins.ADMINISTER); JSONObject json = req.getSubmittedForm(); diff --git a/core/src/main/java/hudson/model/UserProperty.java b/core/src/main/java/hudson/model/UserProperty.java index a9b9dbae7acd..694679e12e12 100644 --- a/core/src/main/java/hudson/model/UserProperty.java +++ b/core/src/main/java/hudson/model/UserProperty.java @@ -24,14 +24,21 @@ package hudson.model; +import edu.umd.cs.findbugs.annotations.NonNull; import hudson.DescriptorExtensionList; import hudson.ExtensionPoint; import hudson.model.Descriptor.FormException; +import hudson.model.userproperty.UserPropertyCategory; import jenkins.model.Jenkins; import net.sf.json.JSONObject; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.export.ExportedBean; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + /** * Extensible property of {@link User}. * @@ -58,6 +65,10 @@ public abstract class UserProperty implements ReconfigurableDescribable all( return Jenkins.get().getDescriptorList(UserProperty.class); } + /** + * Returns all the registered {@link UserPropertyCategory} descriptors for a given category. + * + * @since TODO + */ + public static List allByCategoryClass(@NonNull Class categoryClass) { + DescriptorExtensionList all = all(); + + List onlyForTheCategory = new ArrayList<>(all.size()); + for (UserPropertyDescriptor descriptor : all) { + if (descriptor.getUserPropertyCategory().getClass().equals(categoryClass)) { + onlyForTheCategory.add(descriptor); + } + } + + return onlyForTheCategory; + } + @Override public UserProperty reconfigure(StaplerRequest req, JSONObject form) throws FormException { return form == null ? null : getDescriptor().newInstance(req, form); diff --git a/core/src/main/java/hudson/model/UserPropertyDescriptor.java b/core/src/main/java/hudson/model/UserPropertyDescriptor.java index 22e05ea59aff..34652d2e7c34 100644 --- a/core/src/main/java/hudson/model/UserPropertyDescriptor.java +++ b/core/src/main/java/hudson/model/UserPropertyDescriptor.java @@ -24,6 +24,13 @@ package hudson.model; +import edu.umd.cs.findbugs.annotations.CheckForNull; +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.model.userproperty.UserPropertyCategory; +import org.jenkinsci.Symbol; + +import java.util.Optional; + /** * {@link Descriptor} for {@link UserProperty}. * @@ -73,4 +80,51 @@ protected UserPropertyDescriptor() { public boolean isEnabled() { return true; } + + /** + * Define the category for this user property descriptor. + * + * @return never null, always the same value for a given instance of {@link Descriptor}. + * + * @since TODO + */ + public @NonNull UserPropertyCategory getUserPropertyCategory() { + // As this method is expected to be overloaded by subclasses + // the logic here is just done to support plugins with older core version + String categoryAsString = this.getUserPropertyCategoryAsString(); + if (categoryAsString != null) { + Optional firstIfFound = UserPropertyCategory.all().stream() + .filter(cat -> { + Symbol symbolAnnotation = cat.getClass().getAnnotation(Symbol.class); + if (symbolAnnotation != null) { + for (String symbolValue : symbolAnnotation.value()) { + if (symbolValue.equalsIgnoreCase(categoryAsString)) { + return true; + } + } + } + return false; + }) + .findFirst(); + if (firstIfFound.isPresent()) { + return firstIfFound.get(); + } + } + return UserPropertyCategory.get(UserPropertyCategory.Unclassified.class); + } + + /** + * Method proposed to prevent plugins to rely on too recent core version + * while keeping the possibility to use the categories. + * + * @deprecated This should only be used when the core requirement is below the version this method was added + * + * @return String name corresponding to the symbol of {@link #getUserPropertyCategory()} + * + * @since TODO + */ + @Deprecated + protected @CheckForNull String getUserPropertyCategoryAsString() { + return null; + } } diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategory.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategory.java new file mode 100644 index 000000000000..428b640919a5 --- /dev/null +++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategory.java @@ -0,0 +1,186 @@ +/* + * The MIT License + * + * Copyright (c) 2022, 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.userproperty; + +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.Extension; +import hudson.ExtensionList; +import hudson.ExtensionPoint; +import hudson.model.ModelObject; +import hudson.model.UserProperty; +import hudson.model.UserPropertyDescriptor; +import org.jenkinsci.Symbol; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.DoNotUse; + +/** + * Grouping of related {@link UserProperty}s. + * + *

+ * To facilitate the separation of the user properties into multiple pages, tabs, and so on, + * {@link UserProperty}s are classified into categories (such as "security", "preferences", as well + * as the catch all "unclassified".) Categories themselves are extensible — plugins may introduce + * its own category as well, although that should only happen if you are creating a big enough subsystem. + * + *

+ * The primary purpose of this is to enable future UIs to split the global configurations to + * smaller pieces that can be individually looked at and updated. + * + * @since TODO + * @see UserProperty + */ +public abstract class UserPropertyCategory implements ExtensionPoint, ModelObject { + /** + * One-line plain text message that explains what this category is about. + * This can be used in the UI to help the user pick the right category. + * + * The text should be longer than {@link #getDisplayName()} + */ + public abstract String getShortDescription(); + + /** + * Returns all the registered {@link UserPropertyCategory} descriptors. + */ + public static ExtensionList all() { + return ExtensionList.lookup(UserPropertyCategory.class); + } + + public static @NonNull T get(Class type) { + T category = all().get(type); if (category == null) { + throw new AssertionError("Category not found. It seems the " + type + " is not annotated with @Extension and so not registered"); + } return category; + } + + /** + * This category is used when the {@link hudson.model.UserPropertyDescriptor} has not implemented + * the {@link UserPropertyDescriptor#getUserPropertyCategory()} method + * (or the getUserPropertyCategoryAsString method for compatibility reason). + * + * If you do not know what to use, choose the {@link Account} instead of this one. + */ + @Extension + @Symbol("unclassified") + @Restricted(DoNotUse.class) + public static class Unclassified extends UserPropertyCategory { + @Override + public String getDisplayName() { + return Messages.UserPropertyCategory_Unclassified_DisplayName(); + } + + @Override + public String getShortDescription() { + return Messages.UserPropertyCategory_Unclassified_ShortDescription(); + } + } + + /** + * User property related to account settings (e.g. timezone, email, ...). + * + * It could be seen as the default choice for {@link UserProperty} that are defining their category. + * Currently it has the same effect as {@link Unclassified} but the behavior could change in the future. + */ + @Extension + @Symbol("account") + public static class Account extends UserPropertyCategory { + @Override + public String getDisplayName() { + return Messages.UserPropertyCategory_Account_DisplayName(); + } + + @Override + public String getShortDescription() { + return Messages.UserPropertyCategory_Account_ShortDescription(); + } + } + + /** + * Preferences related configurations (e.g. notification type, default view, ...). + */ + @Extension + @Symbol("preferences") + public static class Preferences extends UserPropertyCategory { + @Override + public String getDisplayName() { + return Messages.UserPropertyCategory_Preferences_DisplayName(); + } + + @Override + public String getShortDescription() { + return Messages.UserPropertyCategory_Preferences_ShortDescription(); + } + } + + /** + * Per user feature flags (e.g. new design, ...). + */ + @Extension + @Symbol("experimental") + public static class Experimental extends UserPropertyCategory { + @Override + public String getDisplayName() { + return Messages.UserPropertyCategory_Experimental_DisplayName(); + } + + @Override + public String getShortDescription() { + return Messages.UserPropertyCategory_Experimental_ShortDescription(); + } + } + + /** + * Security related configurations (e.g. API Token, SSH keys, ...). + * With this separation, we can more easily add control on their modifications. + */ + @Extension + @Symbol("security") + public static class Security extends UserPropertyCategory { + @Override + public String getDisplayName() { + return Messages.UserPropertyCategory_Security_DisplayName(); + } + + @Override + public String getShortDescription() { + return Messages.UserPropertyCategory_Security_ShortDescription(); + } + } + + /** + * For user properties that are not expected to be displayed, + * typically automatically configured by automated behavior, without direct user interaction. + */ + @Extension + @Symbol("invisible") + public static class Invisible extends UserPropertyCategory { + @Override + public String getDisplayName() { + return Messages.UserPropertyCategory_Invisible_DisplayName(); + } + + @Override + public String getShortDescription() { + return Messages.UserPropertyCategory_Invisible_ShortDescription(); + } + } +} \ No newline at end of file diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAccountAction.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAccountAction.java new file mode 100644 index 000000000000..69acd9ec92d1 --- /dev/null +++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAccountAction.java @@ -0,0 +1,153 @@ +/* + * The MIT License + * + * Copyright (c) 2022, 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.userproperty; + +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.DescriptorExtensionList; +import hudson.Extension; +import hudson.model.Action; +import hudson.model.Descriptor; +import hudson.model.TransientUserActionFactory; +import hudson.model.User; +import hudson.model.UserProperty; +import hudson.model.UserPropertyDescriptor; +import hudson.util.FormApply; +import jenkins.model.Jenkins; +import jenkins.security.UserDetailsCache; +import net.sf.json.JSONObject; +import org.jenkinsci.Symbol; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.verb.POST; + +import javax.servlet.ServletException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +@Restricted(NoExternalUse.class) +public class UserPropertyCategoryAccountAction implements Action { + private final @NonNull User targetUser; + + public UserPropertyCategoryAccountAction(@NonNull User user) { + this.targetUser = user; + } + + @SuppressWarnings("unused") // Jelly use + public @NonNull User getTargetUser() { + return targetUser; + } + + @Override + public String getDisplayName() { + return Messages.UserPropertyCategoryAccountAction_DisplayName(); + } + + @Override + public String getIconFileName() { + return "symbol-settings"; + } + + @Override + public String getUrlName() { + return "account"; + } + + public @NonNull List getMyCategoryDescriptors() { + return allByTwoCategoryClasses(UserPropertyCategory.Unclassified.class, UserPropertyCategory.Account.class); + } + + private static List allByTwoCategoryClasses( + @NonNull Class categoryClass1, + @NonNull Class categoryClass2 + ) { + DescriptorExtensionList all = UserProperty.all(); + + List filteredList = new ArrayList<>(all.size()); + for (UserPropertyDescriptor descriptor : all) { + Class currClass = descriptor.getUserPropertyCategory().getClass(); + if (currClass.equals(categoryClass1) || currClass.equals(categoryClass2)) { + filteredList.add(descriptor); + } + } + + return filteredList; + } + + @POST + public void doAccountConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException { + this.targetUser.checkPermission(Jenkins.ADMINISTER); + + JSONObject json = req.getSubmittedForm(); + + String oldFullName = this.targetUser.getFullName(); + this.targetUser.setFullName(json.getString("fullName")); + this.targetUser.setDescription(json.getString("description")); + + List props = new ArrayList<>(); + List myCategoryDescriptors = getMyCategoryDescriptors(); + int i = 0; + for (UserPropertyDescriptor d : myCategoryDescriptors) { + UserProperty p = this.targetUser.getProperty(d.clazz); + + JSONObject o = json.optJSONObject("userProperty" + i++); + if (o != null) { + if (p != null) { + p = p.reconfigure(req, o); + } else { + p = d.newInstance(req, o); + } + } + + if (p != null) { + props.add(p); + } + } + this.targetUser.addProperties(props); + + this.targetUser.save(); + + if (oldFullName != null && !oldFullName.equals(this.targetUser.getFullName())) { + UserDetailsCache.get().invalidate(oldFullName); + } + + // we are in /user//account/, going to /user// + FormApply.success("..").generateResponse(req, rsp, this); + } + + /** + * Inject the outer class configuration page into the sidenav and the request routing of the user + */ + @Extension(ordinal = 400) + @Symbol("account") + public static class AccountActionFactory extends TransientUserActionFactory { + public Collection createFor(User target) { + return Collections.singleton(new UserPropertyCategoryAccountAction(target)); + } + } +} diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryPreferencesAction.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryPreferencesAction.java new file mode 100644 index 000000000000..7061ab615e51 --- /dev/null +++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryPreferencesAction.java @@ -0,0 +1,126 @@ +/* + * The MIT License + * + * Copyright (c) 2022, 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.userproperty; + +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.Extension; +import hudson.model.Action; +import hudson.model.Descriptor; +import hudson.model.TransientUserActionFactory; +import hudson.model.User; +import hudson.model.UserProperty; +import hudson.model.UserPropertyDescriptor; +import hudson.util.FormApply; +import jenkins.model.Jenkins; +import net.sf.json.JSONObject; +import org.jenkinsci.Symbol; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.verb.POST; + +import javax.servlet.ServletException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +@Restricted(NoExternalUse.class) +public class UserPropertyCategoryPreferencesAction implements Action { + private final @NonNull User targetUser; + + public UserPropertyCategoryPreferencesAction(@NonNull User user) { + this.targetUser = user; + } + + @SuppressWarnings("unused") // Jelly use + public @NonNull User getTargetUser() { + return targetUser; + } + + @Override + public String getDisplayName() { + return Messages.UserPropertyCategoryPreferencesAction_DisplayName(); + } + + @Override + public String getIconFileName() { + return "symbol-parameters"; + } + + @Override + public String getUrlName() { + return "preferences"; + } + + public @NonNull List getMyCategoryDescriptors() { + return UserProperty.allByCategoryClass(UserPropertyCategory.Preferences.class); + } + + @POST + public void doPreferencesConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException { + this.targetUser.checkPermission(Jenkins.ADMINISTER); + + JSONObject json = req.getSubmittedForm(); + + List props = new ArrayList<>(); + List myCategoryDescriptors = getMyCategoryDescriptors(); + int i = 0; + for (UserPropertyDescriptor d : myCategoryDescriptors) { + UserProperty p = this.targetUser.getProperty(d.clazz); + + JSONObject o = json.optJSONObject("userProperty" + i++); + if (o != null) { + if (p != null) { + p = p.reconfigure(req, o); + } else { + p = d.newInstance(req, o); + } + } + + if (p != null) { + props.add(p); + } + } + this.targetUser.addProperties(props); + + this.targetUser.save(); + + // we are in /user//experimental/, going to /user// + FormApply.success("..").generateResponse(req, rsp, this); + } + + /** + * Inject the outer class configuration page into the sidenav and the request routing of the user + */ + @Extension(ordinal = 300) + @Symbol("preferences") + public static class PreferencesActionFactory extends TransientUserActionFactory { + public Collection createFor(User target) { + return Collections.singleton(new UserPropertyCategoryPreferencesAction(target)); + } + } +} diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategorySecurityAction.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategorySecurityAction.java new file mode 100644 index 000000000000..ed6188c61f3d --- /dev/null +++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategorySecurityAction.java @@ -0,0 +1,127 @@ +/* + * The MIT License + * + * Copyright (c) 2022, 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.userproperty; + + +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.Extension; +import hudson.model.Action; +import hudson.model.Descriptor; +import hudson.model.TransientUserActionFactory; +import hudson.model.User; +import hudson.model.UserProperty; +import hudson.model.UserPropertyDescriptor; +import hudson.util.FormApply; +import jenkins.model.Jenkins; +import net.sf.json.JSONObject; +import org.jenkinsci.Symbol; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.verb.POST; + +import javax.servlet.ServletException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +@Restricted(NoExternalUse.class) +public class UserPropertyCategorySecurityAction implements Action { + private final @NonNull User targetUser; + + public UserPropertyCategorySecurityAction(@NonNull User user) { + this.targetUser = user; + } + + @SuppressWarnings("unused") // Jelly use + public @NonNull User getTargetUser() { + return targetUser; + } + + @Override + public String getDisplayName() { + return Messages.UserPropertyCategorySecurityAction_DisplayName(); + } + + @Override + public String getIconFileName() { + return "symbol-lock-closed"; + } + + @Override + public String getUrlName() { + return "security"; + } + + public @NonNull List getMyCategoryDescriptors() { + return UserProperty.allByCategoryClass(UserPropertyCategory.Security.class); + } + + @POST + public void doSecurityConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException { + this.targetUser.checkPermission(Jenkins.ADMINISTER); + + JSONObject json = req.getSubmittedForm(); + + List props = new ArrayList<>(); + List myCategoryDescriptors = getMyCategoryDescriptors(); + int i = 0; + for (UserPropertyDescriptor d : myCategoryDescriptors) { + UserProperty p = this.targetUser.getProperty(d.clazz); + + JSONObject o = json.optJSONObject("userProperty" + i++); + if (o != null) { + if (p != null) { + p = p.reconfigure(req, o); + } else { + p = d.newInstance(req, o); + } + } + + if (p != null) { + props.add(p); + } + } + this.targetUser.addProperties(props); + + this.targetUser.save(); + + // we are in /user//security/, going to /user// + FormApply.success("..").generateResponse(req, rsp, this); + } + + /** + * Inject the outer class configuration page into the sidenav and the request routing of the user + */ + @Extension(ordinal = 200) + @Symbol("security") + public static class SecurityActionFactory extends TransientUserActionFactory { + public Collection createFor(User target) { + return Collections.singleton(new UserPropertyCategorySecurityAction(target)); + } + } +} diff --git a/core/src/main/resources/hudson/model/User/configure.jelly b/core/src/main/resources/hudson/model/User/configure.jelly index 0909cedd383e..888d24e6b7f9 100644 --- a/core/src/main/resources/hudson/model/User/configure.jelly +++ b/core/src/main/resources/hudson/model/User/configure.jelly @@ -25,6 +25,7 @@ THE SOFTWARE. + diff --git a/core/src/main/resources/hudson/model/User/sidepanel.jelly b/core/src/main/resources/hudson/model/User/sidepanel.jelly index c92a0f5f228c..d34062b3a98c 100644 --- a/core/src/main/resources/hudson/model/User/sidepanel.jelly +++ b/core/src/main/resources/hudson/model/User/sidepanel.jelly @@ -34,7 +34,8 @@ THE SOFTWARE. - + + diff --git a/core/src/main/resources/hudson/model/userproperty/Messages.properties b/core/src/main/resources/hudson/model/userproperty/Messages.properties new file mode 100644 index 000000000000..b0d4ea87b0bc --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/Messages.properties @@ -0,0 +1,44 @@ +# The MIT License +# +# Copyright (c) 2022, 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. + +UserPropertyCategory.Unclassified.DisplayName=Unclassified +UserPropertyCategory.Unclassified.ShortDescription=User properties without a category yet + +UserPropertyCategory.Account.DisplayName=Account settings +UserPropertyCategory.Account.ShortDescription=User properties related to the user account configuration (e.g. timezone, email, ...) + +UserPropertyCategory.Preferences.DisplayName=Preferences +UserPropertyCategory.Preferences.ShortDescription=User properties related to the user preferences (e.g. notification type, default view, ...) + +UserPropertyCategory.Experimental.DisplayName=Experimental flags +UserPropertyCategory.Experimental.ShortDescription=Per user flags to enable/disable experimental features (e.g. new design, ...) + +UserPropertyCategory.Security.DisplayName=Security +UserPropertyCategory.Security.ShortDescription=User properties related to the security of the user account (e.g. API token, SSH keys, ...) + +UserPropertyCategory.Invisible.DisplayName=Invisible +UserPropertyCategory.Invisible.ShortDescription=User properties that do not require a configuration page + +UserPropertyCategoryAccountAction.DisplayName=Account settings +UserPropertyCategoryExperimentalAction.DisplayName=Experimental flags +UserPropertyCategoryPreferencesAction.DisplayName=Preferences +UserPropertyCategorySecurityAction.DisplayName=Security diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index.jelly b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index.jelly new file mode 100644 index 000000000000..2ab9bb0158fe --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index.jelly @@ -0,0 +1,72 @@ + + + + + + + + + +

+ ${%title(it.targetUser.fullName)} +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index.properties new file mode 100644 index 000000000000..7b0b3046473f --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index.properties @@ -0,0 +1,25 @@ +# The MIT License +# +# Copyright (c) 2022, 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. + +title=Account settings for ‘{0}’ +Full\ name=Full Name +Description=Description diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryPreferencesAction/index.jelly b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryPreferencesAction/index.jelly new file mode 100644 index 000000000000..44220bd14461 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryPreferencesAction/index.jelly @@ -0,0 +1,74 @@ + + + + + + + + + +

+ ${%title(it.targetUser.fullName)} +

+ + + + + + + + + + + + + + + + + + + + + + + +
+ ${%warningNoItems} +
+
+
+ + + + + +
+ +
+
+
diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryPreferencesAction/index.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryPreferencesAction/index.properties new file mode 100644 index 000000000000..21a13047b521 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryPreferencesAction/index.properties @@ -0,0 +1,24 @@ +# The MIT License +# +# Copyright (c) 2022, 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. + +title=Preferences configuration for ‘{0}’ +warningNoItems=Currently no properties with a Preference category. diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategorySecurityAction/index.jelly b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategorySecurityAction/index.jelly new file mode 100644 index 000000000000..743a73d892d5 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategorySecurityAction/index.jelly @@ -0,0 +1,75 @@ + + + + + + + + + +

+ ${%title(it.targetUser.fullName)} +

+ + + + + + + + + + + + + + + + + + + + + + + + +
+ ${%warningNoItems} +
+
+
+ + + + + +
+ +
+
+
diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategorySecurityAction/index.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategorySecurityAction/index.properties new file mode 100644 index 000000000000..922c3e94ae75 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategorySecurityAction/index.properties @@ -0,0 +1,24 @@ +# The MIT License +# +# Copyright (c) 2022, 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. + +title=Security configuration for ‘{0}’ +warningNoItems=Currently no properties with a Security category. From 156bc51497fc97393d887d00d746f5cd8cd125e1 Mon Sep 17 00:00:00 2001 From: Wadeck Follonier Date: Sun, 16 Oct 2022 22:34:51 +0200 Subject: [PATCH 02/15] Update existing properties --- core/src/main/java/hudson/model/MyViewsProperty.java | 6 ++++++ core/src/main/java/hudson/model/PaneStatusProperties.java | 6 ++++++ core/src/main/java/hudson/model/TimeZoneProperty.java | 5 +++++ core/src/main/java/hudson/search/UserSearchProperty.java | 5 +++++ .../java/hudson/security/HudsonPrivateSecurityRealm.java | 7 ++++++- core/src/main/java/jenkins/security/ApiTokenProperty.java | 6 ++++++ .../jenkins/security/LastGrantedAuthoritiesProperty.java | 6 ++++++ .../main/java/jenkins/security/seed/UserSeedProperty.java | 6 ++++++ 8 files changed, 46 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/model/MyViewsProperty.java b/core/src/main/java/hudson/model/MyViewsProperty.java index 9d7b8b651d1c..71809d788eae 100644 --- a/core/src/main/java/hudson/model/MyViewsProperty.java +++ b/core/src/main/java/hudson/model/MyViewsProperty.java @@ -29,6 +29,7 @@ import hudson.Extension; import hudson.Util; import hudson.model.Descriptor.FormException; +import hudson.model.userproperty.UserPropertyCategory; import hudson.security.ACL; import hudson.util.FormValidation; import hudson.views.MyViewsTabBar; @@ -246,6 +247,11 @@ public String getDisplayName() { public UserProperty newInstance(User user) { return new MyViewsProperty(); } + + @Override + public @NonNull UserPropertyCategory getUserPropertyCategory() { + return UserPropertyCategory.get(UserPropertyCategory.Preferences.class); + } } @Override diff --git a/core/src/main/java/hudson/model/PaneStatusProperties.java b/core/src/main/java/hudson/model/PaneStatusProperties.java index 29a460349440..4807020ca714 100644 --- a/core/src/main/java/hudson/model/PaneStatusProperties.java +++ b/core/src/main/java/hudson/model/PaneStatusProperties.java @@ -2,7 +2,9 @@ import static java.lang.String.format; +import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; +import hudson.model.userproperty.UserPropertyCategory; import hudson.util.PersistedList; import java.io.IOException; import javax.servlet.http.HttpSession; @@ -56,6 +58,10 @@ public boolean isEnabled() { return false; } + @Override + public @NonNull UserPropertyCategory getUserPropertyCategory() { + return UserPropertyCategory.get(UserPropertyCategory.Invisible.class); + } } private static class PaneStatusPropertiesSessionFallback extends PaneStatusProperties { diff --git a/core/src/main/java/hudson/model/TimeZoneProperty.java b/core/src/main/java/hudson/model/TimeZoneProperty.java index bdf39c58527e..2675448dad80 100644 --- a/core/src/main/java/hudson/model/TimeZoneProperty.java +++ b/core/src/main/java/hudson/model/TimeZoneProperty.java @@ -4,6 +4,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; import hudson.Util; +import hudson.model.userproperty.UserPropertyCategory; import hudson.util.FormValidation; import hudson.util.ListBoxModel; import hudson.util.ListBoxModel.Option; @@ -106,6 +107,10 @@ public FormValidation doCheckTimeZoneName(@QueryParameter String timeZoneName) { } } + @Override + public @NonNull UserPropertyCategory getUserPropertyCategory() { + return UserPropertyCategory.get(UserPropertyCategory.Account.class); + } } @CheckForNull diff --git a/core/src/main/java/hudson/search/UserSearchProperty.java b/core/src/main/java/hudson/search/UserSearchProperty.java index 7e9836944c0b..a3515dd08874 100644 --- a/core/src/main/java/hudson/search/UserSearchProperty.java +++ b/core/src/main/java/hudson/search/UserSearchProperty.java @@ -5,6 +5,7 @@ import hudson.model.User; import hudson.model.UserProperty; import hudson.model.UserPropertyDescriptor; +import hudson.model.userproperty.UserPropertyCategory; import net.sf.json.JSONObject; import org.jenkinsci.Symbol; import org.kohsuke.stapler.StaplerRequest; @@ -54,6 +55,10 @@ public UserProperty newInstance(StaplerRequest req, JSONObject formData) throws return new UserSearchProperty(formData.optBoolean("insensitiveSearch")); } + @Override + public @NonNull UserPropertyCategory getUserPropertyCategory() { + return UserPropertyCategory.get(UserPropertyCategory.Preferences.class); + } } } diff --git a/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java b/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java index d25b01c02035..27b2d6948d74 100644 --- a/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java +++ b/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java @@ -39,6 +39,7 @@ import hudson.model.User; import hudson.model.UserProperty; import hudson.model.UserPropertyDescriptor; +import hudson.model.userproperty.UserPropertyCategory; import hudson.security.FederatedLoginService.FederatedIdentity; import hudson.security.captcha.CaptchaSupport; import hudson.util.FormValidation; @@ -761,7 +762,6 @@ public boolean equals(Object o) { public int hashCode() { return getUsername().hashCode(); } - } public static class ConverterImpl extends XStream2.PassthruConverter
{ @@ -844,6 +844,11 @@ public boolean isEnabled() { public UserProperty newInstance(User user) { return null; } + + @Override + public @NonNull UserPropertyCategory getUserPropertyCategory() { + return UserPropertyCategory.get(UserPropertyCategory.Security.class); + } } } diff --git a/core/src/main/java/jenkins/security/ApiTokenProperty.java b/core/src/main/java/jenkins/security/ApiTokenProperty.java index 3e200b25fa2f..9106830ace92 100644 --- a/core/src/main/java/jenkins/security/ApiTokenProperty.java +++ b/core/src/main/java/jenkins/security/ApiTokenProperty.java @@ -32,6 +32,7 @@ import hudson.model.Descriptor.FormException; import hudson.model.User; import hudson.model.UserProperty; +import hudson.model.userproperty.UserPropertyCategory; import hudson.model.UserPropertyDescriptor; import hudson.security.ACL; import hudson.util.HttpResponses; @@ -658,6 +659,11 @@ public HttpResponse doRevokeAllExcept(@AncestorInPath User u, return HttpResponses.ok(); } + + @Override + public @NonNull UserPropertyCategory getUserPropertyCategory() { + return UserPropertyCategory.get(UserPropertyCategory.Security.class); + } } /** diff --git a/core/src/main/java/jenkins/security/LastGrantedAuthoritiesProperty.java b/core/src/main/java/jenkins/security/LastGrantedAuthoritiesProperty.java index 52f74d452ffa..cb8b8accf295 100644 --- a/core/src/main/java/jenkins/security/LastGrantedAuthoritiesProperty.java +++ b/core/src/main/java/jenkins/security/LastGrantedAuthoritiesProperty.java @@ -6,6 +6,7 @@ import hudson.model.User; import hudson.model.UserProperty; import hudson.model.UserPropertyDescriptor; +import hudson.model.userproperty.UserPropertyCategory; import hudson.security.SecurityRealm; import java.io.IOException; import java.util.ArrayList; @@ -171,6 +172,11 @@ public boolean isEnabled() { public UserProperty newInstance(User user) { return null; } + + @Override + public @NonNull UserPropertyCategory getUserPropertyCategory() { + return UserPropertyCategory.get(UserPropertyCategory.Invisible.class); + } } private static final Logger LOGGER = Logger.getLogger(LastGrantedAuthoritiesProperty.class.getName()); diff --git a/core/src/main/java/jenkins/security/seed/UserSeedProperty.java b/core/src/main/java/jenkins/security/seed/UserSeedProperty.java index d7420910cb64..e323d87932f4 100644 --- a/core/src/main/java/jenkins/security/seed/UserSeedProperty.java +++ b/core/src/main/java/jenkins/security/seed/UserSeedProperty.java @@ -30,6 +30,7 @@ import hudson.Extension; import hudson.model.User; import hudson.model.UserProperty; +import hudson.model.userproperty.UserPropertyCategory; import hudson.model.UserPropertyDescriptor; import hudson.util.HttpResponses; import java.io.IOException; @@ -153,5 +154,10 @@ public synchronized HttpResponse doRenewSessionSeed(@AncestorInPath @NonNull Use public boolean isEnabled() { return !DISABLE_USER_SEED && !HIDE_USER_SEED_SECTION; } + + @Override + public @NonNull UserPropertyCategory getUserPropertyCategory() { + return UserPropertyCategory.get(UserPropertyCategory.Security.class); + } } } From 3086ed8aca753f06391d5c79dfc6b33431396c48 Mon Sep 17 00:00:00 2001 From: Wadeck Follonier Date: Sun, 16 Oct 2022 22:35:30 +0200 Subject: [PATCH 03/15] Copy-paste the translation from configure-x.properties --- .../index_bg.properties | 31 +++++++++++++++++++ .../index_ca.properties | 4 +++ .../index_cs.properties | 25 +++++++++++++++ .../index_da.properties | 26 ++++++++++++++++ .../index_de.properties | 26 ++++++++++++++++ .../index_es.properties | 27 ++++++++++++++++ .../index_fi.properties | 24 ++++++++++++++ .../index_fr.properties | 26 ++++++++++++++++ .../index_hu.properties | 4 +++ .../index_it.properties | 27 ++++++++++++++++ .../index_ja.properties | 26 ++++++++++++++++ .../index_ko.properties | 4 +++ .../index_lv.properties | 25 +++++++++++++++ .../index_nb_NO.properties | 25 +++++++++++++++ .../index_nl.properties | 25 +++++++++++++++ .../index_pl.properties | 27 ++++++++++++++++ .../index_pt_BR.properties | 27 ++++++++++++++++ .../index_ru.properties | 25 +++++++++++++++ .../index_sk.properties | 4 +++ .../index_sr.properties | 6 ++++ .../index_sv_SE.properties | 25 +++++++++++++++ .../index_tr.properties | 26 ++++++++++++++++ .../index_uk.properties | 4 +++ .../index_zh_TW.properties | 26 ++++++++++++++++ 24 files changed, 495 insertions(+) create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_bg.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_ca.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_cs.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_da.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_de.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_es.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_fi.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_fr.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_hu.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_it.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_ja.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_ko.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_lv.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_nb_NO.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_nl.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_pl.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_pt_BR.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_ru.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_sk.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_sr.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_sv_SE.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_tr.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_uk.properties create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_zh_TW.properties diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_bg.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_bg.properties new file mode 100644 index 000000000000..bacad06f736c --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_bg.properties @@ -0,0 +1,31 @@ +# The MIT License +# +# Bulgarian translation: Copyright (c) 2015, 2016, Alexander Shopov +# +# 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. + +Description=\ + Описание +Full\ name=\ + Пълно име +# User ‘{0}’ Configuration +title=\ + Настройки за потребителя „{0}“ +Save=\ + Запазване diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_ca.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_ca.properties new file mode 100644 index 000000000000..aad7c2e559ef --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_ca.properties @@ -0,0 +1,4 @@ +# This file is under the MIT License by authors + +Description=Descripció +Full\ name=Nom diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_cs.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_cs.properties new file mode 100644 index 000000000000..541815f7d164 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_cs.properties @@ -0,0 +1,25 @@ +# The MIT License +# +# Copyright (c) 2004-2010, Sun Microsystems, 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. + +Description=Popis +Save=Uložit +Full\ name=Jméno diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_da.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_da.properties new file mode 100644 index 000000000000..aa4a8b98d500 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_da.properties @@ -0,0 +1,26 @@ +# The MIT License +# +# Copyright (c) 2004-2010, Sun Microsystems, Inc. Kohsuke Kawaguchi. Knud Poulsen. +# +# 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. + +title=Bruger ''{0}'' Konfiguration +Full\ name=Dit navn +Save=Gem +Description=Beskrivelse diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_de.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_de.properties new file mode 100644 index 000000000000..4448b8c62978 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_de.properties @@ -0,0 +1,26 @@ +# The MIT License +# +# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Simon Wiest +# +# 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. + +Full\ name=Ihr Name +Description=Beschreibung +Save=Speichern +title=Benutzer „{0}“ konfigurieren diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_es.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_es.properties new file mode 100644 index 000000000000..76ba23330c2f --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_es.properties @@ -0,0 +1,27 @@ +# The MIT License +# +# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi +# +# 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. + +title=Configuración del usuario: ''{0}'' +Full\ name=Nombre +Save=Guardar +Description=Descripción + diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_fi.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_fi.properties new file mode 100644 index 000000000000..03769c1d17c4 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_fi.properties @@ -0,0 +1,24 @@ +# The MIT License +# +# Copyright (c) 2004-2010, Sun Microsystems, 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. + +Description=Kuvaus +Save=Tallenna diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_fr.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_fr.properties new file mode 100644 index 000000000000..8ec32b9d88a6 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_fr.properties @@ -0,0 +1,26 @@ +# The MIT License +# +# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Eric Lefevre-Ardant +# +# 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. + +Full\ name=Votre nom +Description=Présentation +Save=Sauvegarder +title=Configuration de l''utilisateur ''{0}'' diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_hu.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_hu.properties new file mode 100644 index 000000000000..6e8cb34dc914 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_hu.properties @@ -0,0 +1,4 @@ +# This file is under the MIT License by authors + +Description=Leírás +Full\ name=Ön neve diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_it.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_it.properties new file mode 100644 index 000000000000..015fc76eb7c3 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_it.properties @@ -0,0 +1,27 @@ +# The MIT License +# +# Italian localization plugin for Jenkins +# Copyright © 2020 Alessandro Menti +# +# 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. + +Description=Descrizione +Full\ name=Nome completo +Save=Salva +title=Configurazione dell''utente "{0}" diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_ja.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_ja.properties new file mode 100644 index 000000000000..efcc432364b9 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_ja.properties @@ -0,0 +1,26 @@ +# The MIT License +# +# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe, id:cactusman +# +# 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. + +Full\ name=あなたの名前 +Description=説明 +Save=保存 +title=ユーザー ''{0}'' の設定 diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_ko.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_ko.properties new file mode 100644 index 000000000000..fd0ca539d7d9 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_ko.properties @@ -0,0 +1,4 @@ +# This file is under the MIT License by authors + +Description=소개 +Full\ name=이름 diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_lv.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_lv.properties new file mode 100644 index 000000000000..b16f28220290 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_lv.properties @@ -0,0 +1,25 @@ +# The MIT License +# +# Copyright (c) 2004-2010, Sun Microsystems, 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. + +Full\ name=Tavs vārds +description.title=Apraksts +Save=Saglabāt diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_nb_NO.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_nb_NO.properties new file mode 100644 index 000000000000..58a3343fb3d8 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_nb_NO.properties @@ -0,0 +1,25 @@ +# The MIT License +# +# Copyright (c) 2004-2010, Sun Microsystems, 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. + +Description=Beskrivelse +Save=Lagre +Full\ name=Ditt navn diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_nl.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_nl.properties new file mode 100644 index 000000000000..7756763a1a74 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_nl.properties @@ -0,0 +1,25 @@ +# The MIT License +# +# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, id:sorokh +# +# 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. + +Full\ name=Uw naam +Description=Omschrijving +Save=Opslaan diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_pl.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_pl.properties new file mode 100644 index 000000000000..2c63348a17e3 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_pl.properties @@ -0,0 +1,27 @@ +# The MIT License +# +# Copyright (c) 2004-2016, Sun Microsystems, Damian Szczepanik +# +# 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. + +Description=Opis +Full\ name=Twoje imię i nazwisko +# User ‘{0}’ Configuration +title=Konfiguracja użytkownika ‘{0}’ +Save=Zapisz diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_pt_BR.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_pt_BR.properties new file mode 100644 index 000000000000..c1025982d036 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_pt_BR.properties @@ -0,0 +1,27 @@ +# The MIT License +# +# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Reginaldo L. Russinholi, Cleiber Silva +# +# 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. + +Full\ name=Seu nome +Description=Descrição +Save=Salvar +# User ''{0}'' Configuration +title=Configuração do usuário ''{0}'' diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_ru.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_ru.properties new file mode 100644 index 000000000000..b05ddbbb49a8 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_ru.properties @@ -0,0 +1,25 @@ +# The MIT License +# +# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Mike Salnikov +# +# 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. + +Full\ name=Полное имя +Description=Описание +Save=Сохранить diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_sk.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_sk.properties new file mode 100644 index 000000000000..8c8f98e91b07 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_sk.properties @@ -0,0 +1,4 @@ +# This file is under the MIT License by authors + +Description=Popis +Full\ name=Meno diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_sr.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_sr.properties new file mode 100644 index 000000000000..6985fb9f994a --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_sr.properties @@ -0,0 +1,6 @@ +# This file is under the MIT License by authors + +title=Подешавања корисника ‘{0}’ +Full\ name=Име и презиме +Description=Опис +Save=Сачувај diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_sv_SE.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_sv_SE.properties new file mode 100644 index 000000000000..6e75a39365c2 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_sv_SE.properties @@ -0,0 +1,25 @@ +# The MIT License +# +# Copyright (c) 2004-2010, Sun Microsystems, 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. + +Description=Beskrivning +Save=Spara +Full\ name=Ditt namn diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_tr.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_tr.properties new file mode 100644 index 000000000000..66ce578249aa --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_tr.properties @@ -0,0 +1,26 @@ +# The MIT License +# +# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Oguz Dag +# +# 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. + +Full\ name=İsminiz +Description=Açıklama +Save=Kaydet +title=Kullanıcı ''{0}'' Konfigürasyonu diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_uk.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_uk.properties new file mode 100644 index 000000000000..3dc2751ccdeb --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_uk.properties @@ -0,0 +1,4 @@ +# This file is under the MIT License by authors + +Description=Опис +Full\ name=Ваше ім''я diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_zh_TW.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_zh_TW.properties new file mode 100644 index 000000000000..55957bf76749 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_zh_TW.properties @@ -0,0 +1,26 @@ +# The MIT License +# +# Copyright (c) 2004-2013, Sun Microsystems, Inc., Chunghwa Telecom Co., Ltd., +# and Pei-Tang Huang +# +# 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. +title=使用者 ''{0}'' 的設定 +Full\ name=全名 +Description=說明 +Save=儲存 From 40fce3acc18c6b75f775e328b9287d76248a5305 Mon Sep 17 00:00:00 2001 From: Wadeck Follonier Date: Sun, 16 Oct 2022 22:35:46 +0200 Subject: [PATCH 04/15] Experimental example --- .../userproperty/UserPreferencesProperty.java | 92 +++++++++++++ ...serPropertyCategoryExperimentalAction.java | 127 ++++++++++++++++++ .../hudson/model/Messages.properties | 2 + .../index.jelly | 74 ++++++++++ .../index.properties | 24 ++++ .../main/resources/images/symbols/flask.svg | 2 + 6 files changed, 321 insertions(+) create mode 100644 core/src/main/java/hudson/model/userproperty/UserPreferencesProperty.java create mode 100644 core/src/main/java/hudson/model/userproperty/UserPropertyCategoryExperimentalAction.java create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryExperimentalAction/index.jelly create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryExperimentalAction/index.properties create mode 100644 war/src/main/resources/images/symbols/flask.svg diff --git a/core/src/main/java/hudson/model/userproperty/UserPreferencesProperty.java b/core/src/main/java/hudson/model/userproperty/UserPreferencesProperty.java new file mode 100644 index 000000000000..cd92ba46cc86 --- /dev/null +++ b/core/src/main/java/hudson/model/userproperty/UserPreferencesProperty.java @@ -0,0 +1,92 @@ +/* + * The MIT License + * + * Copyright (c) 2022, 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.userproperty; + +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.ExtensionPoint; +import hudson.model.Messages; +import hudson.model.User; +import hudson.model.UserProperty; +import hudson.model.UserPropertyDescriptor; +import jenkins.model.Jenkins; +import org.jenkinsci.Symbol; +import org.kohsuke.stapler.export.ExportedBean; + +import java.util.Map; + +//TODO DRAFT experimental to split +/** + * Property of {@link User} responsible to store their preferences. + * + * TODO rest of the javadoc + * + * @since TODO + */ +@ExportedBean +public class UserPreferencesProperty extends UserProperty { + + private Map preferences; + + + + // descriptor must be of the UserPropertyDescriptor type + @Override + public UserPropertyDescriptor getDescriptor() { + return (UserPropertyDescriptor) Jenkins.get().getDescriptorOrDie(getClass()); + } + + public static class UserPreference implements ExtensionPoint { + public UserPreferenceKey getKey(){ + return null; + } + public UserPreferenceValue getValue(){ + return null; + } + } + + public static class UserPreferenceKey { + + } + + public static class UserPreferenceValue { + + } + +// @Extension + @Symbol("preferences") + public static class DescriptorImpl extends UserPropertyDescriptor { + + @NonNull + @Override + public String getDisplayName() { + return Messages.UserPreferencesProperty_DisplayName(); + } + + @Override + public UserProperty newInstance(User user) { + return new UserPreferencesProperty(); + } + } +} diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryExperimentalAction.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryExperimentalAction.java new file mode 100644 index 000000000000..1d443863061d --- /dev/null +++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryExperimentalAction.java @@ -0,0 +1,127 @@ +/* + * The MIT License + * + * Copyright (c) 2022, 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.userproperty; + +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.Extension; +import hudson.model.Action; +import hudson.model.Descriptor; +import hudson.model.TransientUserActionFactory; +import hudson.model.User; +import hudson.model.UserProperty; +import hudson.model.UserPropertyDescriptor; +import hudson.util.FormApply; +import jenkins.model.Jenkins; +import net.sf.json.JSONObject; +import org.jenkinsci.Symbol; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.verb.POST; + +import javax.servlet.ServletException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +//TODO DRAFT experimental to split +@Restricted(NoExternalUse.class) +public class UserPropertyCategoryExperimentalAction implements Action { + private final @NonNull User targetUser; + + public UserPropertyCategoryExperimentalAction(@NonNull User user) { + this.targetUser = user; + } + + @SuppressWarnings("unused") // Jelly use + public @NonNull User getTargetUser() { + return targetUser; + } + + @Override + public String getDisplayName() { + return Messages.UserPropertyCategoryExperimentalAction_DisplayName(); + } + + @Override + public String getIconFileName() { + return "symbol-flask"; + } + + @Override + public String getUrlName() { + return "experimental"; + } + + public @NonNull List getMyCategoryDescriptors() { + return UserProperty.allByCategoryClass(UserPropertyCategory.Experimental.class); + } + + @POST + public void doExperimentalConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException { + this.targetUser.checkPermission(Jenkins.ADMINISTER); + + JSONObject json = req.getSubmittedForm(); + + List props = new ArrayList<>(); + List myCategoryDescriptors = getMyCategoryDescriptors(); + int i = 0; + for (UserPropertyDescriptor d : myCategoryDescriptors) { + UserProperty p = this.targetUser.getProperty(d.clazz); + + JSONObject o = json.optJSONObject("userProperty" + i++); + if (o != null) { + if (p != null) { + p = p.reconfigure(req, o); + } else { + p = d.newInstance(req, o); + } + } + + if (p != null) { + props.add(p); + } + } + this.targetUser.addProperties(props); + + this.targetUser.save(); + + // we are in /user//experimental/, going to /user// + FormApply.success("..").generateResponse(req, rsp, this); + } + + /** + * Inject the outer class configuration page into the sidenav and the request routing of the user + */ + @Extension(ordinal = 100) + @Symbol("experimental") + public static class ExperimentalActionFactory extends TransientUserActionFactory { + public Collection createFor(User target) { + return Collections.singleton(new UserPropertyCategoryExperimentalAction(target)); + } + } +} diff --git a/core/src/main/resources/hudson/model/Messages.properties b/core/src/main/resources/hudson/model/Messages.properties index a14216ffe0f8..ebe24bd8172f 100644 --- a/core/src/main/resources/hudson/model/Messages.properties +++ b/core/src/main/resources/hudson/model/Messages.properties @@ -421,3 +421,5 @@ ManagementLink.Category.MISC=Other ManagementLink.Category.UNCATEGORIZED=Uncategorized FileParameterValue.IndexTitle=File Parameters + +UserPreferencesProperty.DisplayName=Preferences diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryExperimentalAction/index.jelly b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryExperimentalAction/index.jelly new file mode 100644 index 000000000000..93865e2c5461 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryExperimentalAction/index.jelly @@ -0,0 +1,74 @@ + + + + + + + + + +

+ ${%title(it.targetUser.fullName)} +

+ + + + + + + + + + + + + + + + + + + + + + + +
+ ${%warningNoItems} +
+
+
+ + + + + +
+ +
+
+
diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryExperimentalAction/index.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryExperimentalAction/index.properties new file mode 100644 index 000000000000..0d7f55d24c27 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryExperimentalAction/index.properties @@ -0,0 +1,24 @@ +# The MIT License +# +# Copyright (c) 2022, 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. + +title=Experimental flags configuration for ‘{0}’ +warningNoItems=Currently no properties with an Experimental category. diff --git a/war/src/main/resources/images/symbols/flask.svg b/war/src/main/resources/images/symbols/flask.svg new file mode 100644 index 000000000000..ccfce7974afd --- /dev/null +++ b/war/src/main/resources/images/symbols/flask.svg @@ -0,0 +1,2 @@ + +Flask \ No newline at end of file From 4284d5d4b187539ab2c22724d0bb9bd9aff07055 Mon Sep 17 00:00:00 2001 From: Tim Jacomb Date: Sat, 8 Jun 2024 22:43:16 +0100 Subject: [PATCH 05/15] Cleanup adapt to changes that have happened since this was opened --- core/src/main/java/hudson/model/User.java | 63 +-------------- .../main/java/hudson/model/UserProperty.java | 9 +-- .../hudson/model/UserPropertyDescriptor.java | 15 ++-- .../userproperty/UserPropertyCategory.java | 28 +++++-- .../UserPropertyCategoryAccountAction.java | 64 ++++----------- .../UserPropertyCategoryAction.java | 65 ++++++++++++++++ ...UserPropertyCategoryAppearanceAction.java} | 78 ++++++++----------- ...serPropertyCategoryExperimentalAction.java | 62 ++------------- ...UserPropertyCategoryPreferencesAction.java | 61 ++------------- .../UserPropertyCategorySecurityAction.java | 61 ++------------- .../UserExperimentalFlagsProperty.java | 13 +++- .../jenkins/security/ApiTokenProperty.java | 2 +- .../security/seed/UserSeedProperty.java | 2 +- .../hudson/model/User/configure.jelly | 68 ---------------- .../hudson/model/User/sidepanel.jelly | 2 - .../model/userproperty/Messages.properties | 12 ++- .../index.jelly | 6 +- .../index.properties | 2 +- .../index_bg.properties | 3 - .../index_da.properties | 1 - .../index_de.properties | 1 - .../index_es.properties | 1 - .../index_fr.properties | 1 - .../index_it.properties | 1 - .../index_ja.properties | 1 - .../index_pl.properties | 1 - .../index_pt_BR.properties | 2 - .../index_sr.properties | 1 - .../index_tr.properties | 1 - .../index_zh_TW.properties | 1 - .../index.jelly | 74 ++++++++++++++++++ .../index.properties} | 3 +- .../index.jelly | 8 +- .../index.properties | 4 +- .../index.jelly | 8 +- .../index.properties | 4 +- .../index.jelly | 8 +- .../index.properties | 4 +- .../experimentalflags/Messages.properties | 2 +- .../Messages_sv_SE.properties | 23 ------ .../config.jelly | 2 +- test/src/test/java/hudson/model/UserTest.java | 2 +- .../main/resources/images/symbols/flask.svg | 1 - 43 files changed, 282 insertions(+), 489 deletions(-) create mode 100644 core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAction.java rename core/src/main/java/hudson/model/userproperty/{UserPreferencesProperty.java => UserPropertyCategoryAppearanceAction.java} (51%) delete mode 100644 core/src/main/resources/hudson/model/User/configure.jelly create mode 100644 core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAppearanceAction/index.jelly rename core/src/main/resources/{jenkins/model/experimentalflags/Messages_fr.properties => hudson/model/userproperty/UserPropertyCategoryAppearanceAction/index.properties} (92%) delete mode 100644 core/src/main/resources/jenkins/model/experimentalflags/Messages_sv_SE.properties diff --git a/core/src/main/java/hudson/model/User.java b/core/src/main/java/hudson/model/User.java index ea4500ef4fa1..e588a79b347a 100644 --- a/core/src/main/java/hudson/model/User.java +++ b/core/src/main/java/hudson/model/User.java @@ -39,16 +39,12 @@ import hudson.XmlFile; import hudson.init.InitMilestone; import hudson.init.Initializer; -import hudson.model.Descriptor.FormException; import hudson.model.listeners.SaveableListener; -import hudson.model.userproperty.UserPreferencesProperty; import hudson.security.ACL; import hudson.security.AccessControlled; import hudson.security.SecurityRealm; import hudson.security.UserMayOrMayNotExistException2; -import hudson.util.FormApply; import hudson.util.FormValidation; -import hudson.util.HttpResponses; import hudson.util.RunList; import hudson.util.XStream2; import java.io.File; @@ -79,7 +75,6 @@ import jenkins.security.LastGrantedAuthoritiesProperty; import jenkins.security.UserDetailsCache; import jenkins.util.SystemProperties; -import net.sf.json.JSONObject; import org.jenkinsci.Symbol; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -89,7 +84,6 @@ import org.kohsuke.stapler.export.Exported; import org.kohsuke.stapler.export.ExportedBean; import org.kohsuke.stapler.interceptor.RequirePOST; -import org.kohsuke.stapler.verb.POST; import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; @@ -343,13 +337,13 @@ public synchronized void addProperty(@NonNull UserProperty p) throws IOException properties = ps; save(); } - + /** * Expand {@link #addProperty(UserProperty)} for multiple properties to be done at once. * Expected to be used by the categorized configuration pages to update part of the properties. * The properties not included in the list will be let untouched. - * It will call the {@link UserProperty#setUser(User)} method and at the end, {@link #save()} once. - * + * It will call the {@link UserProperty#setUser(User)} method and at the end, {@link #save()} once. + * * @since TODO */ public synchronized void addProperties(@NonNull List multipleProperties) throws IOException { @@ -884,57 +878,6 @@ public Api getApi() { return new Api(this); } - /** - * Accepts submission from the configuration page. - */ - @POST - public void doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, FormException { - // FIXME DRAFT system property - if (true) { - LOGGER.warning(() -> - "Attempt to use the legacy /configSubmit endpoint of user login=" + this.id + - ". The global configuration page has been deprecated in favor of categorized pages. For more details, see JENKINS-69869." - ); - throw HttpResponses.error(400, "The user global configuration page was split into categorized individual pages. See JENKINS-69869."); - } - - checkPermission(Jenkins.ADMINISTER); - - JSONObject json = req.getSubmittedForm(); - String oldFullName = this.fullName; - fullName = json.getString("fullName"); - description = json.getString("description"); - - List props = new ArrayList<>(); - int i = 0; - for (UserPropertyDescriptor d : UserProperty.all()) { - UserProperty p = getProperty(d.clazz); - - JSONObject o = json.optJSONObject("userProperty" + i++); - if (o != null) { - if (p != null) { - p = p.reconfigure(req, o); - } else { - p = d.newInstance(req, o); - } - } - - if (p != null) { - p.setUser(this); - props.add(p); - } - } - this.properties = props; - - save(); - - if (oldFullName != null && !oldFullName.equals(this.fullName)) { - UserDetailsCache.get().invalidate(oldFullName); - } - - FormApply.success(".").generateResponse(req, rsp, this); - } - /** * Deletes this user from Hudson. */ diff --git a/core/src/main/java/hudson/model/UserProperty.java b/core/src/main/java/hudson/model/UserProperty.java index 694679e12e12..6538a5fdf661 100644 --- a/core/src/main/java/hudson/model/UserProperty.java +++ b/core/src/main/java/hudson/model/UserProperty.java @@ -29,16 +29,13 @@ import hudson.ExtensionPoint; import hudson.model.Descriptor.FormException; import hudson.model.userproperty.UserPropertyCategory; +import java.util.ArrayList; +import java.util.List; import jenkins.model.Jenkins; import net.sf.json.JSONObject; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.export.ExportedBean; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - /** * Extensible property of {@link User}. * @@ -88,7 +85,7 @@ public static DescriptorExtensionList all( /** * Returns all the registered {@link UserPropertyCategory} descriptors for a given category. - * + * * @since TODO */ public static List allByCategoryClass(@NonNull Class categoryClass) { diff --git a/core/src/main/java/hudson/model/UserPropertyDescriptor.java b/core/src/main/java/hudson/model/UserPropertyDescriptor.java index 34652d2e7c34..ff3171c1fbf7 100644 --- a/core/src/main/java/hudson/model/UserPropertyDescriptor.java +++ b/core/src/main/java/hudson/model/UserPropertyDescriptor.java @@ -27,9 +27,8 @@ import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; import hudson.model.userproperty.UserPropertyCategory; -import org.jenkinsci.Symbol; - import java.util.Optional; +import org.jenkinsci.Symbol; /** * {@link Descriptor} for {@link UserProperty}. @@ -83,9 +82,9 @@ public boolean isEnabled() { /** * Define the category for this user property descriptor. - * + * * @return never null, always the same value for a given instance of {@link Descriptor}. - * + * * @since TODO */ public @NonNull UserPropertyCategory getUserPropertyCategory() { @@ -114,13 +113,13 @@ public boolean isEnabled() { } /** - * Method proposed to prevent plugins to rely on too recent core version + * Method proposed to prevent plugins to rely on too recent core version * while keeping the possibility to use the categories. - * + * * @deprecated This should only be used when the core requirement is below the version this method was added - * + * * @return String name corresponding to the symbol of {@link #getUserPropertyCategory()} - * + * * @since TODO */ @Deprecated diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategory.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategory.java index 428b640919a5..22b84ac4a30a 100644 --- a/core/src/main/java/hudson/model/userproperty/UserPropertyCategory.java +++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategory.java @@ -40,13 +40,9 @@ *

* To facilitate the separation of the user properties into multiple pages, tabs, and so on, * {@link UserProperty}s are classified into categories (such as "security", "preferences", as well - * as the catch all "unclassified".) Categories themselves are extensible — plugins may introduce + * as the catch-all "unclassified".) Categories themselves are extensible — plugins may introduce * its own category as well, although that should only happen if you are creating a big enough subsystem. * - *

- * The primary purpose of this is to enable future UIs to split the global configurations to - * smaller pieces that can be individually looked at and updated. - * * @since TODO * @see UserProperty */ @@ -149,7 +145,25 @@ public String getShortDescription() { } /** - * Security related configurations (e.g. API Token, SSH keys, ...). + * Per user feature flags (e.g. new design, ...). + */ + @Extension + @Symbol("appearance") + public static class Appearance extends UserPropertyCategory { + @Override + public String getDisplayName() { + return Messages.UserPropertyCategory_Appearance_DisplayName(); + } + + @Override + public String getShortDescription() { + return Messages.UserPropertyCategory_Appearance_ShortDescription(); + } + } + + + /** + * Security related configurations (e.g. API Token, SSH keys, ...). * With this separation, we can more easily add control on their modifications. */ @Extension @@ -183,4 +197,4 @@ public String getShortDescription() { return Messages.UserPropertyCategory_Invisible_ShortDescription(); } } -} \ No newline at end of file +} diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAccountAction.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAccountAction.java index 69acd9ec92d1..d08a9be7cf20 100644 --- a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAccountAction.java +++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAccountAction.java @@ -32,7 +32,12 @@ import hudson.model.User; import hudson.model.UserProperty; import hudson.model.UserPropertyDescriptor; -import hudson.util.FormApply; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import javax.servlet.ServletException; import jenkins.model.Jenkins; import jenkins.security.UserDetailsCache; import net.sf.json.JSONObject; @@ -43,24 +48,10 @@ import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.verb.POST; -import javax.servlet.ServletException; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - @Restricted(NoExternalUse.class) -public class UserPropertyCategoryAccountAction implements Action { - private final @NonNull User targetUser; - +public class UserPropertyCategoryAccountAction extends UserPropertyCategoryAction implements Action { public UserPropertyCategoryAccountAction(@NonNull User user) { - this.targetUser = user; - } - - @SuppressWarnings("unused") // Jelly use - public @NonNull User getTargetUser() { - return targetUser; + super(user); } @Override @@ -100,44 +91,21 @@ private static List allByTwoCategoryClasses( } @POST - public void doAccountConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException { - this.targetUser.checkPermission(Jenkins.ADMINISTER); + public void doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException { + User targetUser = this.getTargetUser(); + targetUser.checkPermission(Jenkins.ADMINISTER); JSONObject json = req.getSubmittedForm(); - String oldFullName = this.targetUser.getFullName(); - this.targetUser.setFullName(json.getString("fullName")); - this.targetUser.setDescription(json.getString("description")); - - List props = new ArrayList<>(); - List myCategoryDescriptors = getMyCategoryDescriptors(); - int i = 0; - for (UserPropertyDescriptor d : myCategoryDescriptors) { - UserProperty p = this.targetUser.getProperty(d.clazz); - - JSONObject o = json.optJSONObject("userProperty" + i++); - if (o != null) { - if (p != null) { - p = p.reconfigure(req, o); - } else { - p = d.newInstance(req, o); - } - } - - if (p != null) { - props.add(p); - } - } - this.targetUser.addProperties(props); + String oldFullName = targetUser.getFullName(); + targetUser.setFullName(json.getString("fullName")); + targetUser.setDescription(json.getString("description")); - this.targetUser.save(); + super.doConfigSubmit(req, rsp); - if (oldFullName != null && !oldFullName.equals(this.targetUser.getFullName())) { + if (!oldFullName.equals(targetUser.getFullName())) { UserDetailsCache.get().invalidate(oldFullName); } - - // we are in /user//account/, going to /user// - FormApply.success("..").generateResponse(req, rsp, this); } /** diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAction.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAction.java new file mode 100644 index 000000000000..caec7c1bdf88 --- /dev/null +++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAction.java @@ -0,0 +1,65 @@ +package hudson.model.userproperty; + +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.model.Descriptor; +import hudson.model.User; +import hudson.model.UserProperty; +import hudson.model.UserPropertyDescriptor; +import hudson.util.FormApply; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import javax.servlet.ServletException; +import jenkins.model.Jenkins; +import net.sf.json.JSONObject; +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.verb.POST; + +public abstract class UserPropertyCategoryAction { + + private final User targetUser; + + public UserPropertyCategoryAction(User targetUser) { + this.targetUser = targetUser; + } + + public @NonNull User getTargetUser() { + return targetUser; + } + + public @NonNull abstract List getMyCategoryDescriptors(); + + @POST + public void doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException { + this.targetUser.checkPermission(Jenkins.ADMINISTER); + + JSONObject json = req.getSubmittedForm(); + + List props = new ArrayList<>(); + List myCategoryDescriptors = getMyCategoryDescriptors(); + int i = 0; + for (UserPropertyDescriptor d : myCategoryDescriptors) { + UserProperty p = this.targetUser.getProperty(d.clazz); + + JSONObject o = json.optJSONObject("userProperty" + i++); + if (o != null) { + if (p != null) { + p = p.reconfigure(req, o); + } else { + p = d.newInstance(req, o); + } + } + + if (p != null) { + props.add(p); + } + } + this.targetUser.addProperties(props); + + this.targetUser.save(); + + // we are in /user///, going to /user// + FormApply.success("..").generateResponse(req, rsp, this); + } +} diff --git a/core/src/main/java/hudson/model/userproperty/UserPreferencesProperty.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAppearanceAction.java similarity index 51% rename from core/src/main/java/hudson/model/userproperty/UserPreferencesProperty.java rename to core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAppearanceAction.java index cd92ba46cc86..141dfeee7016 100644 --- a/core/src/main/java/hudson/model/userproperty/UserPreferencesProperty.java +++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAppearanceAction.java @@ -21,72 +21,56 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ - package hudson.model.userproperty; import edu.umd.cs.findbugs.annotations.NonNull; -import hudson.ExtensionPoint; -import hudson.model.Messages; +import hudson.Extension; +import hudson.model.Action; +import hudson.model.TransientUserActionFactory; import hudson.model.User; import hudson.model.UserProperty; import hudson.model.UserPropertyDescriptor; -import jenkins.model.Jenkins; +import java.util.Collection; +import java.util.Collections; +import java.util.List; import org.jenkinsci.Symbol; -import org.kohsuke.stapler.export.ExportedBean; - -import java.util.Map; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; //TODO DRAFT experimental to split -/** - * Property of {@link User} responsible to store their preferences. - * - * TODO rest of the javadoc - * - * @since TODO - */ -@ExportedBean -public class UserPreferencesProperty extends UserProperty { +@Restricted(NoExternalUse.class) +public class UserPropertyCategoryAppearanceAction extends UserPropertyCategoryAction implements Action { + public UserPropertyCategoryAppearanceAction(@NonNull User user) { + super(user); + } - private Map preferences; - - - - // descriptor must be of the UserPropertyDescriptor type @Override - public UserPropertyDescriptor getDescriptor() { - return (UserPropertyDescriptor) Jenkins.get().getDescriptorOrDie(getClass()); + public String getDisplayName() { + return Messages.UserPropertyCategoryAppearanceAction_DisplayName(); } - public static class UserPreference implements ExtensionPoint { - public UserPreferenceKey getKey(){ - return null; - } - public UserPreferenceValue getValue(){ - return null; - } + @Override + public String getIconFileName() { + return "symbol-brush-outline"; } - public static class UserPreferenceKey { - + @Override + public String getUrlName() { + return "appearance"; } - public static class UserPreferenceValue { - + public @NonNull List getMyCategoryDescriptors() { + return UserProperty.allByCategoryClass(UserPropertyCategory.Appearance.class); } -// @Extension - @Symbol("preferences") - public static class DescriptorImpl extends UserPropertyDescriptor { - - @NonNull - @Override - public String getDisplayName() { - return Messages.UserPreferencesProperty_DisplayName(); - } - - @Override - public UserProperty newInstance(User user) { - return new UserPreferencesProperty(); + /** + * Inject the outer class configuration page into the sidenav and the request routing of the user + */ + @Extension(ordinal = 350) + @Symbol("appearance") + public static class AppearanceActionFactory extends TransientUserActionFactory { + public Collection createFor(User target) { + return Collections.singleton(new UserPropertyCategoryAppearanceAction(target)); } } } diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryExperimentalAction.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryExperimentalAction.java index 1d443863061d..4b883e53264e 100644 --- a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryExperimentalAction.java +++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryExperimentalAction.java @@ -26,40 +26,21 @@ import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; import hudson.model.Action; -import hudson.model.Descriptor; import hudson.model.TransientUserActionFactory; import hudson.model.User; import hudson.model.UserProperty; import hudson.model.UserPropertyDescriptor; -import hudson.util.FormApply; -import jenkins.model.Jenkins; -import net.sf.json.JSONObject; -import org.jenkinsci.Symbol; -import org.kohsuke.accmod.Restricted; -import org.kohsuke.accmod.restrictions.NoExternalUse; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; -import org.kohsuke.stapler.verb.POST; - -import javax.servlet.ServletException; -import java.io.IOException; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import org.jenkinsci.Symbol; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; -//TODO DRAFT experimental to split @Restricted(NoExternalUse.class) -public class UserPropertyCategoryExperimentalAction implements Action { - private final @NonNull User targetUser; - +public class UserPropertyCategoryExperimentalAction extends UserPropertyCategoryAction implements Action { public UserPropertyCategoryExperimentalAction(@NonNull User user) { - this.targetUser = user; - } - - @SuppressWarnings("unused") // Jelly use - public @NonNull User getTargetUser() { - return targetUser; + super(user); } @Override @@ -81,39 +62,6 @@ public String getUrlName() { return UserProperty.allByCategoryClass(UserPropertyCategory.Experimental.class); } - @POST - public void doExperimentalConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException { - this.targetUser.checkPermission(Jenkins.ADMINISTER); - - JSONObject json = req.getSubmittedForm(); - - List props = new ArrayList<>(); - List myCategoryDescriptors = getMyCategoryDescriptors(); - int i = 0; - for (UserPropertyDescriptor d : myCategoryDescriptors) { - UserProperty p = this.targetUser.getProperty(d.clazz); - - JSONObject o = json.optJSONObject("userProperty" + i++); - if (o != null) { - if (p != null) { - p = p.reconfigure(req, o); - } else { - p = d.newInstance(req, o); - } - } - - if (p != null) { - props.add(p); - } - } - this.targetUser.addProperties(props); - - this.targetUser.save(); - - // we are in /user//experimental/, going to /user// - FormApply.success("..").generateResponse(req, rsp, this); - } - /** * Inject the outer class configuration page into the sidenav and the request routing of the user */ diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryPreferencesAction.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryPreferencesAction.java index 7061ab615e51..c956306b8c59 100644 --- a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryPreferencesAction.java +++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryPreferencesAction.java @@ -26,39 +26,21 @@ import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; import hudson.model.Action; -import hudson.model.Descriptor; import hudson.model.TransientUserActionFactory; import hudson.model.User; import hudson.model.UserProperty; import hudson.model.UserPropertyDescriptor; -import hudson.util.FormApply; -import jenkins.model.Jenkins; -import net.sf.json.JSONObject; -import org.jenkinsci.Symbol; -import org.kohsuke.accmod.Restricted; -import org.kohsuke.accmod.restrictions.NoExternalUse; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; -import org.kohsuke.stapler.verb.POST; - -import javax.servlet.ServletException; -import java.io.IOException; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import org.jenkinsci.Symbol; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; @Restricted(NoExternalUse.class) -public class UserPropertyCategoryPreferencesAction implements Action { - private final @NonNull User targetUser; - +public class UserPropertyCategoryPreferencesAction extends UserPropertyCategoryAction implements Action { public UserPropertyCategoryPreferencesAction(@NonNull User user) { - this.targetUser = user; - } - - @SuppressWarnings("unused") // Jelly use - public @NonNull User getTargetUser() { - return targetUser; + super(user); } @Override @@ -80,39 +62,6 @@ public String getUrlName() { return UserProperty.allByCategoryClass(UserPropertyCategory.Preferences.class); } - @POST - public void doPreferencesConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException { - this.targetUser.checkPermission(Jenkins.ADMINISTER); - - JSONObject json = req.getSubmittedForm(); - - List props = new ArrayList<>(); - List myCategoryDescriptors = getMyCategoryDescriptors(); - int i = 0; - for (UserPropertyDescriptor d : myCategoryDescriptors) { - UserProperty p = this.targetUser.getProperty(d.clazz); - - JSONObject o = json.optJSONObject("userProperty" + i++); - if (o != null) { - if (p != null) { - p = p.reconfigure(req, o); - } else { - p = d.newInstance(req, o); - } - } - - if (p != null) { - props.add(p); - } - } - this.targetUser.addProperties(props); - - this.targetUser.save(); - - // we are in /user//experimental/, going to /user// - FormApply.success("..").generateResponse(req, rsp, this); - } - /** * Inject the outer class configuration page into the sidenav and the request routing of the user */ diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategorySecurityAction.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategorySecurityAction.java index ed6188c61f3d..d9a3e81a0933 100644 --- a/core/src/main/java/hudson/model/userproperty/UserPropertyCategorySecurityAction.java +++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategorySecurityAction.java @@ -27,39 +27,21 @@ import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; import hudson.model.Action; -import hudson.model.Descriptor; import hudson.model.TransientUserActionFactory; import hudson.model.User; import hudson.model.UserProperty; import hudson.model.UserPropertyDescriptor; -import hudson.util.FormApply; -import jenkins.model.Jenkins; -import net.sf.json.JSONObject; -import org.jenkinsci.Symbol; -import org.kohsuke.accmod.Restricted; -import org.kohsuke.accmod.restrictions.NoExternalUse; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; -import org.kohsuke.stapler.verb.POST; - -import javax.servlet.ServletException; -import java.io.IOException; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import org.jenkinsci.Symbol; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; @Restricted(NoExternalUse.class) -public class UserPropertyCategorySecurityAction implements Action { - private final @NonNull User targetUser; - +public class UserPropertyCategorySecurityAction extends UserPropertyCategoryAction implements Action { public UserPropertyCategorySecurityAction(@NonNull User user) { - this.targetUser = user; - } - - @SuppressWarnings("unused") // Jelly use - public @NonNull User getTargetUser() { - return targetUser; + super(user); } @Override @@ -81,39 +63,6 @@ public String getUrlName() { return UserProperty.allByCategoryClass(UserPropertyCategory.Security.class); } - @POST - public void doSecurityConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException { - this.targetUser.checkPermission(Jenkins.ADMINISTER); - - JSONObject json = req.getSubmittedForm(); - - List props = new ArrayList<>(); - List myCategoryDescriptors = getMyCategoryDescriptors(); - int i = 0; - for (UserPropertyDescriptor d : myCategoryDescriptors) { - UserProperty p = this.targetUser.getProperty(d.clazz); - - JSONObject o = json.optJSONObject("userProperty" + i++); - if (o != null) { - if (p != null) { - p = p.reconfigure(req, o); - } else { - p = d.newInstance(req, o); - } - } - - if (p != null) { - props.add(p); - } - } - this.targetUser.addProperties(props); - - this.targetUser.save(); - - // we are in /user//security/, going to /user// - FormApply.success("..").generateResponse(req, rsp, this); - } - /** * Inject the outer class configuration page into the sidenav and the request routing of the user */ diff --git a/core/src/main/java/jenkins/model/experimentalflags/UserExperimentalFlagsProperty.java b/core/src/main/java/jenkins/model/experimentalflags/UserExperimentalFlagsProperty.java index 6732f2e5d696..85332d26973c 100644 --- a/core/src/main/java/jenkins/model/experimentalflags/UserExperimentalFlagsProperty.java +++ b/core/src/main/java/jenkins/model/experimentalflags/UserExperimentalFlagsProperty.java @@ -31,6 +31,7 @@ import hudson.model.User; import hudson.model.UserProperty; import hudson.model.UserPropertyDescriptor; +import hudson.model.userproperty.UserPropertyCategory; import java.util.HashMap; import java.util.Map; import net.sf.json.JSONObject; @@ -76,13 +77,19 @@ public static final class DescriptorImpl extends UserPropertyDescriptor { public UserProperty newInstance(@Nullable StaplerRequest req, @NonNull JSONObject formData) throws FormException { JSONObject flagsObj = formData.getJSONObject("flags"); Map flags = new HashMap<>(); - for (Object key : flagsObj.keySet()) { - String value = (String) flagsObj.get((String) key); + for (String key : flagsObj.keySet()) { + String value = (String) flagsObj.get(key); if (!value.isEmpty()) { - flags.put((String) key, value); + flags.put(key, value); } } return new UserExperimentalFlagsProperty(flags); } + + @NonNull + @Override + public UserPropertyCategory getUserPropertyCategory() { + return UserPropertyCategory.get(UserPropertyCategory.Experimental.class); + } } } diff --git a/core/src/main/java/jenkins/security/ApiTokenProperty.java b/core/src/main/java/jenkins/security/ApiTokenProperty.java index 9b2c6dab3237..464fdcbdf16c 100644 --- a/core/src/main/java/jenkins/security/ApiTokenProperty.java +++ b/core/src/main/java/jenkins/security/ApiTokenProperty.java @@ -32,8 +32,8 @@ import hudson.model.Descriptor.FormException; import hudson.model.User; import hudson.model.UserProperty; -import hudson.model.userproperty.UserPropertyCategory; import hudson.model.UserPropertyDescriptor; +import hudson.model.userproperty.UserPropertyCategory; import hudson.security.ACL; import hudson.util.HttpResponses; import hudson.util.Secret; diff --git a/core/src/main/java/jenkins/security/seed/UserSeedProperty.java b/core/src/main/java/jenkins/security/seed/UserSeedProperty.java index e323d87932f4..968ee9320f58 100644 --- a/core/src/main/java/jenkins/security/seed/UserSeedProperty.java +++ b/core/src/main/java/jenkins/security/seed/UserSeedProperty.java @@ -30,8 +30,8 @@ import hudson.Extension; import hudson.model.User; import hudson.model.UserProperty; -import hudson.model.userproperty.UserPropertyCategory; import hudson.model.UserPropertyDescriptor; +import hudson.model.userproperty.UserPropertyCategory; import hudson.util.HttpResponses; import java.io.IOException; import java.security.SecureRandom; diff --git a/core/src/main/resources/hudson/model/User/configure.jelly b/core/src/main/resources/hudson/model/User/configure.jelly deleted file mode 100644 index 9728cbe8e2e6..000000000000 --- a/core/src/main/resources/hudson/model/User/configure.jelly +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/core/src/main/resources/hudson/model/User/sidepanel.jelly b/core/src/main/resources/hudson/model/User/sidepanel.jelly index 33be1614125f..f8024b0c21b8 100644 --- a/core/src/main/resources/hudson/model/User/sidepanel.jelly +++ b/core/src/main/resources/hudson/model/User/sidepanel.jelly @@ -33,8 +33,6 @@ THE SOFTWARE. - - diff --git a/core/src/main/resources/hudson/model/userproperty/Messages.properties b/core/src/main/resources/hudson/model/userproperty/Messages.properties index b0d4ea87b0bc..5e52b8d2906c 100644 --- a/core/src/main/resources/hudson/model/userproperty/Messages.properties +++ b/core/src/main/resources/hudson/model/userproperty/Messages.properties @@ -23,22 +23,26 @@ UserPropertyCategory.Unclassified.DisplayName=Unclassified UserPropertyCategory.Unclassified.ShortDescription=User properties without a category yet -UserPropertyCategory.Account.DisplayName=Account settings +UserPropertyCategory.Account.DisplayName=Account UserPropertyCategory.Account.ShortDescription=User properties related to the user account configuration (e.g. timezone, email, ...) UserPropertyCategory.Preferences.DisplayName=Preferences UserPropertyCategory.Preferences.ShortDescription=User properties related to the user preferences (e.g. notification type, default view, ...) -UserPropertyCategory.Experimental.DisplayName=Experimental flags +UserPropertyCategory.Experimental.DisplayName=Experiments UserPropertyCategory.Experimental.ShortDescription=Per user flags to enable/disable experimental features (e.g. new design, ...) +UserPropertyCategory.Appearance.DisplayName=Appearance +UserPropertyCategory.Appearance.ShortDescription=User properties related to the appearance of Jenkins + UserPropertyCategory.Security.DisplayName=Security UserPropertyCategory.Security.ShortDescription=User properties related to the security of the user account (e.g. API token, SSH keys, ...) UserPropertyCategory.Invisible.DisplayName=Invisible UserPropertyCategory.Invisible.ShortDescription=User properties that do not require a configuration page -UserPropertyCategoryAccountAction.DisplayName=Account settings -UserPropertyCategoryExperimentalAction.DisplayName=Experimental flags +UserPropertyCategoryAccountAction.DisplayName=Account +UserPropertyCategoryAppearanceAction.DisplayName=Appearance +UserPropertyCategoryExperimentalAction.DisplayName=Experiments UserPropertyCategoryPreferencesAction.DisplayName=Preferences UserPropertyCategorySecurityAction.DisplayName=Security diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index.jelly b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index.jelly index 2ab9bb0158fe..8d2a8e9368e7 100644 --- a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index.jelly +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index.jelly @@ -27,12 +27,12 @@ THE SOFTWARE. --> - + - +

- ${%title(it.targetUser.fullName)} + ${%title}

diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index.properties index 7b0b3046473f..41e4d5b9689f 100644 --- a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index.properties +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index.properties @@ -20,6 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -title=Account settings for ‘{0}’ +title=Account Full\ name=Full Name Description=Description diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_bg.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_bg.properties index bacad06f736c..8654e841998b 100644 --- a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_bg.properties +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_bg.properties @@ -24,8 +24,5 @@ Description=\ Описание Full\ name=\ Пълно име -# User ‘{0}’ Configuration -title=\ - Настройки за потребителя „{0}“ Save=\ Запазване diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_da.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_da.properties index aa4a8b98d500..a5abfe2acc7a 100644 --- a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_da.properties +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_da.properties @@ -20,7 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -title=Bruger ''{0}'' Konfiguration Full\ name=Dit navn Save=Gem Description=Beskrivelse diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_de.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_de.properties index 4448b8c62978..06240b1aa6ce 100644 --- a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_de.properties +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_de.properties @@ -23,4 +23,3 @@ Full\ name=Ihr Name Description=Beschreibung Save=Speichern -title=Benutzer „{0}“ konfigurieren diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_es.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_es.properties index 76ba23330c2f..f7839a14fe3d 100644 --- a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_es.properties +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_es.properties @@ -20,7 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -title=Configuración del usuario: ''{0}'' Full\ name=Nombre Save=Guardar Description=Descripción diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_fr.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_fr.properties index 8ec32b9d88a6..3b677fa5d67b 100644 --- a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_fr.properties +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_fr.properties @@ -23,4 +23,3 @@ Full\ name=Votre nom Description=Présentation Save=Sauvegarder -title=Configuration de l''utilisateur ''{0}'' diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_it.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_it.properties index 015fc76eb7c3..d3523f2f3116 100644 --- a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_it.properties +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_it.properties @@ -24,4 +24,3 @@ Description=Descrizione Full\ name=Nome completo Save=Salva -title=Configurazione dell''utente "{0}" diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_ja.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_ja.properties index efcc432364b9..be1c04668bbf 100644 --- a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_ja.properties +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_ja.properties @@ -23,4 +23,3 @@ Full\ name=あなたの名前 Description=説明 Save=保存 -title=ユーザー ''{0}'' の設定 diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_pl.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_pl.properties index 2c63348a17e3..f90e9574abde 100644 --- a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_pl.properties +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_pl.properties @@ -23,5 +23,4 @@ Description=Opis Full\ name=Twoje imię i nazwisko # User ‘{0}’ Configuration -title=Konfiguracja użytkownika ‘{0}’ Save=Zapisz diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_pt_BR.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_pt_BR.properties index c1025982d036..c46179879578 100644 --- a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_pt_BR.properties +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_pt_BR.properties @@ -23,5 +23,3 @@ Full\ name=Seu nome Description=Descrição Save=Salvar -# User ''{0}'' Configuration -title=Configuração do usuário ''{0}'' diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_sr.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_sr.properties index 6985fb9f994a..241621057f54 100644 --- a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_sr.properties +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_sr.properties @@ -1,6 +1,5 @@ # This file is under the MIT License by authors -title=Подешавања корисника ‘{0}’ Full\ name=Име и презиме Description=Опис Save=Сачувај diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_tr.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_tr.properties index 66ce578249aa..ead6d67dee06 100644 --- a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_tr.properties +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_tr.properties @@ -23,4 +23,3 @@ Full\ name=İsminiz Description=Açıklama Save=Kaydet -title=Kullanıcı ''{0}'' Konfigürasyonu diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_zh_TW.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_zh_TW.properties index 55957bf76749..8a05a4258d59 100644 --- a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_zh_TW.properties +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAccountAction/index_zh_TW.properties @@ -20,7 +20,6 @@ # 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. -title=使用者 ''{0}'' 的設定 Full\ name=全名 Description=說明 Save=儲存 diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAppearanceAction/index.jelly b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAppearanceAction/index.jelly new file mode 100644 index 000000000000..0d90ad4b2d76 --- /dev/null +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAppearanceAction/index.jelly @@ -0,0 +1,74 @@ + + + + + + + + + +

+ ${%title} +

+ + + + + + + + + + + + + + + + + + + + + + + +
+ ${%warningNoItems} +
+
+
+ + + + + +
+ +
+
+
diff --git a/core/src/main/resources/jenkins/model/experimentalflags/Messages_fr.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAppearanceAction/index.properties similarity index 92% rename from core/src/main/resources/jenkins/model/experimentalflags/Messages_fr.properties rename to core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAppearanceAction/index.properties index 8e48740af070..f24a3f6e3851 100644 --- a/core/src/main/resources/jenkins/model/experimentalflags/Messages_fr.properties +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryAppearanceAction/index.properties @@ -20,4 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -UserExperimentalFlagsProperty.DisplayName=Expérimentations +title=Appearance +warningNoItems=No appearance items are available for configuration. diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryExperimentalAction/index.jelly b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryExperimentalAction/index.jelly index 93865e2c5461..0d90ad4b2d76 100644 --- a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryExperimentalAction/index.jelly +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryExperimentalAction/index.jelly @@ -27,12 +27,12 @@ THE SOFTWARE. --> - + - +

- ${%title(it.targetUser.fullName)} + ${%title}

@@ -57,7 +57,7 @@ THE SOFTWARE. -
+
${%warningNoItems}
diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryExperimentalAction/index.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryExperimentalAction/index.properties index 0d7f55d24c27..4e5e6b02073d 100644 --- a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryExperimentalAction/index.properties +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryExperimentalAction/index.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -title=Experimental flags configuration for ‘{0}’ -warningNoItems=Currently no properties with an Experimental category. +title=Experiments +warningNoItems=No experiments are currently available. diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryPreferencesAction/index.jelly b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryPreferencesAction/index.jelly index 44220bd14461..6971e5abf8d0 100644 --- a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryPreferencesAction/index.jelly +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryPreferencesAction/index.jelly @@ -27,12 +27,12 @@ THE SOFTWARE. --> - + - +

- ${%title(it.targetUser.fullName)} + ${%title}

@@ -57,7 +57,7 @@ THE SOFTWARE. -
+
${%warningNoItems}
diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryPreferencesAction/index.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryPreferencesAction/index.properties index 21a13047b521..89bd19371237 100644 --- a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryPreferencesAction/index.properties +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategoryPreferencesAction/index.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -title=Preferences configuration for ‘{0}’ -warningNoItems=Currently no properties with a Preference category. +title=Preferences +warningNoItems=No preferences available. diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategorySecurityAction/index.jelly b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategorySecurityAction/index.jelly index 743a73d892d5..0d90501fbbb0 100644 --- a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategorySecurityAction/index.jelly +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategorySecurityAction/index.jelly @@ -27,12 +27,12 @@ THE SOFTWARE. --> - + - +

- ${%title(it.targetUser.fullName)} + ${%title}

@@ -58,7 +58,7 @@ THE SOFTWARE. -
+
${%warningNoItems}
diff --git a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategorySecurityAction/index.properties b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategorySecurityAction/index.properties index 922c3e94ae75..be9c8e93e5f2 100644 --- a/core/src/main/resources/hudson/model/userproperty/UserPropertyCategorySecurityAction/index.properties +++ b/core/src/main/resources/hudson/model/userproperty/UserPropertyCategorySecurityAction/index.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -title=Security configuration for ‘{0}’ -warningNoItems=Currently no properties with a Security category. +title=Security +warningNoItems=No security configuration available. diff --git a/core/src/main/resources/jenkins/model/experimentalflags/Messages.properties b/core/src/main/resources/jenkins/model/experimentalflags/Messages.properties index ddf8f546e32b..13e00e615459 100644 --- a/core/src/main/resources/jenkins/model/experimentalflags/Messages.properties +++ b/core/src/main/resources/jenkins/model/experimentalflags/Messages.properties @@ -20,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -UserExperimentalFlagsProperty.DisplayName=Experiments +UserExperimentalFlagsProperty.DisplayName=Feature preview diff --git a/core/src/main/resources/jenkins/model/experimentalflags/Messages_sv_SE.properties b/core/src/main/resources/jenkins/model/experimentalflags/Messages_sv_SE.properties deleted file mode 100644 index 4f1b584608af..000000000000 --- a/core/src/main/resources/jenkins/model/experimentalflags/Messages_sv_SE.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2022, 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. - -UserExperimentalFlagsProperty.DisplayName=Experiment diff --git a/core/src/main/resources/jenkins/model/experimentalflags/UserExperimentalFlagsProperty/config.jelly b/core/src/main/resources/jenkins/model/experimentalflags/UserExperimentalFlagsProperty/config.jelly index 4fe6097089bb..a70fddf3403e 100644 --- a/core/src/main/resources/jenkins/model/experimentalflags/UserExperimentalFlagsProperty/config.jelly +++ b/core/src/main/resources/jenkins/model/experimentalflags/UserExperimentalFlagsProperty/config.jelly @@ -40,7 +40,7 @@ THE SOFTWARE. ${%FlagDisplayName} - ${%FlagDescription} + ${%FlagDescription} ${%FlagConfig} diff --git a/test/src/test/java/hudson/model/UserTest.java b/test/src/test/java/hudson/model/UserTest.java index 4f5d6e8f4365..44527148cec1 100644 --- a/test/src/test/java/hudson/model/UserTest.java +++ b/test/src/test/java/hudson/model/UserTest.java @@ -411,7 +411,7 @@ public void testDoConfigSubmit() throws Exception { j.submit(form); assertEquals("User should have full name Alice Smith.", "Alice Smith", user2.getFullName()); SecurityContextHolder.getContext().setAuthentication(user2.impersonate2()); - assertThrows("User should not have permission to configure another user.", AccessDeniedException3.class, () -> user.doConfigSubmit(null, null)); +// assertThrows("User should not have permission to configure another user.", AccessDeniedException3.class, () -> user.doConfigSubmit(null, null)); form = j.createWebClient().withBasicCredentials(user2.getId(), "password").goTo(user2.getUrl() + "/configure").getFormByName("config"); form.getInputByName("_.fullName").setValue("John"); diff --git a/war/src/main/resources/images/symbols/flask.svg b/war/src/main/resources/images/symbols/flask.svg index ccfce7974afd..9c4c478d820d 100644 --- a/war/src/main/resources/images/symbols/flask.svg +++ b/war/src/main/resources/images/symbols/flask.svg @@ -1,2 +1 @@ - Flask \ No newline at end of file From 01883b4eed74c3f5b86474a5139720f95f3e3f56 Mon Sep 17 00:00:00 2001 From: Tim Jacomb Date: Sat, 8 Jun 2024 23:00:10 +0100 Subject: [PATCH 06/15] Update TODO --- .../model/userproperty/UserPropertyCategoryAppearanceAction.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAppearanceAction.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAppearanceAction.java index 141dfeee7016..8d7243e22542 100644 --- a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAppearanceAction.java +++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAppearanceAction.java @@ -37,7 +37,6 @@ import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; -//TODO DRAFT experimental to split @Restricted(NoExternalUse.class) public class UserPropertyCategoryAppearanceAction extends UserPropertyCategoryAction implements Action { public UserPropertyCategoryAppearanceAction(@NonNull User user) { From c0934b5524e6b4945b4200830e89b85dbec59751 Mon Sep 17 00:00:00 2001 From: Tim Jacomb Date: Sat, 8 Jun 2024 23:19:23 +0100 Subject: [PATCH 07/15] Adapt tests --- test/src/test/java/hudson/model/UserTest.java | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/test/src/test/java/hudson/model/UserTest.java b/test/src/test/java/hudson/model/UserTest.java index 44527148cec1..b27adbdc15e7 100644 --- a/test/src/test/java/hudson/model/UserTest.java +++ b/test/src/test/java/hudson/model/UserTest.java @@ -64,12 +64,14 @@ import jenkins.model.IdStrategy; import jenkins.model.Jenkins; import jenkins.security.ApiTokenProperty; +import org.htmlunit.FailingHttpStatusCodeException; import org.htmlunit.WebAssert; import org.htmlunit.WebRequest; import org.htmlunit.WebResponse; import org.htmlunit.html.HtmlForm; import org.htmlunit.html.HtmlPage; import org.htmlunit.util.WebConnectionWrapper; +import org.jenkinsci.plugins.matrixauth.PermissionEntry; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -403,20 +405,23 @@ public void testDoConfigSubmit() throws Exception { User user = realm.createAccount("John Smith", "password"); User user2 = realm.createAccount("John Smith2", "password"); user2.save(); - auth.add(Jenkins.ADMINISTER, user.getId()); - auth.add(Jenkins.READ, user2.getId()); + auth.add(Jenkins.ADMINISTER, PermissionEntry.user(user.getId())); + auth.add(Jenkins.READ, PermissionEntry.user(user2.getId())); SecurityContextHolder.getContext().setAuthentication(user.impersonate2()); - HtmlForm form = j.createWebClient().withBasicCredentials(user.getId(), "password").goTo(user2.getUrl() + "/configure").getFormByName("config"); + HtmlForm form = j.createWebClient().withBasicCredentials(user.getId(), "password").goTo(user2.getUrl() + "/account/").getFormByName("config"); form.getInputByName("_.fullName").setValue("Alice Smith"); j.submit(form); assertEquals("User should have full name Alice Smith.", "Alice Smith", user2.getFullName()); SecurityContextHolder.getContext().setAuthentication(user2.impersonate2()); -// assertThrows("User should not have permission to configure another user.", AccessDeniedException3.class, () -> user.doConfigSubmit(null, null)); - form = j.createWebClient().withBasicCredentials(user2.getId(), "password").goTo(user2.getUrl() + "/configure").getFormByName("config"); + try (JenkinsRule.WebClient webClient = j.createWebClient().withBasicCredentials(user2.getId(), "password")) { + FailingHttpStatusCodeException failingHttpStatusCodeException = assertThrows("User should not have permission to configure another user.", FailingHttpStatusCodeException.class, () -> webClient.goTo(user.getUrl() + "/account/")); + assertThat(failingHttpStatusCodeException.getStatusCode(), is(403)); + form = webClient.goTo(user2.getUrl() + "/account/").getFormByName("config"); + form.getInputByName("_.fullName").setValue("John"); + j.submit(form); + } - form.getInputByName("_.fullName").setValue("John"); - j.submit(form); - assertEquals("User should be albe to configure himself.", "John", user2.getFullName()); + assertEquals("User should be able to configure himself.", "John", user2.getFullName()); } @@ -771,7 +776,7 @@ public WebResponse getResponse(WebRequest request) throws IOException { return r; } }; - wc.login("alice").goTo("me/configure"); + wc.login("alice").goTo("me/account/"); assertThat(failingResources, empty()); } From 2ca056aa7be6e790dd2913314d9aeb403aba1345 Mon Sep 17 00:00:00 2001 From: Tim Jacomb Date: Sun, 9 Jun 2024 10:41:14 +0100 Subject: [PATCH 08/15] Fix tests --- test/src/test/java/hudson/model/UserPropertyTest.java | 10 ++++++++-- .../security/HudsonPrivateSecurityRealmTest.java | 6 +++--- .../security/BasicHeaderApiTokenAuthenticatorTest.java | 4 ++-- .../security/LastGrantedAuthoritiesPropertyTest.java | 2 +- .../security/apitoken/ApiTokenStatsRestartTest.java | 8 ++++---- .../jenkins/security/apitoken/ApiTokenStatsTest.java | 6 +++--- .../jenkins/security/seed/UserSeedPropertyTest.java | 4 ++-- 7 files changed, 23 insertions(+), 17 deletions(-) diff --git a/test/src/test/java/hudson/model/UserPropertyTest.java b/test/src/test/java/hudson/model/UserPropertyTest.java index 0d2b7d5b1374..91c977d4ec28 100644 --- a/test/src/test/java/hudson/model/UserPropertyTest.java +++ b/test/src/test/java/hudson/model/UserPropertyTest.java @@ -6,6 +6,7 @@ import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; +import static org.htmlunit.html.HtmlFormUtil.submit; import static org.junit.Assert.assertNotNull; import java.io.File; @@ -35,12 +36,17 @@ public class UserPropertyTest { @Rule public JenkinsRule j = new JenkinsRule(); + public User configRoundtrip(User u) throws Exception { + submit(j.createWebClient().goTo(u.getUrl()+"/account/").getFormByName("config")); + return u; + } + @Test @Issue("JENKINS-9062") public void test() throws Exception { User u = User.get("foo"); u.addProperty(new UserProperty1()); - j.configRoundtrip(u); + configRoundtrip(u); for (UserProperty p : u.getAllProperties()) assertNotNull(p); } @@ -82,7 +88,7 @@ public void nestedUserReference() throws Exception { List fileLines = Files.readAllLines(testFile.toPath(), StandardCharsets.US_ASCII); assertThat(fileLines, hasSize(1)); - j.configRoundtrip(user); + configRoundtrip(user); user = User.get("nestedUserReference", false, Collections.emptyMap()); assertThat("nested reference should exist after user configuration change", user, nestedUserSet()); diff --git a/test/src/test/java/hudson/security/HudsonPrivateSecurityRealmTest.java b/test/src/test/java/hudson/security/HudsonPrivateSecurityRealmTest.java index d0f58f92d5ec..92745bf5f9b0 100644 --- a/test/src/test/java/hudson/security/HudsonPrivateSecurityRealmTest.java +++ b/test/src/test/java/hudson/security/HudsonPrivateSecurityRealmTest.java @@ -651,7 +651,7 @@ public void changingPassword_mustInvalidateAllSessions() throws Exception { wc_anotherTab.login(alice.getId()); assertUserConnected(wc_anotherTab, alice.getId()); - HtmlPage configurePage = wc.goTo(alice.getUrl() + "/configure"); + HtmlPage configurePage = wc.goTo(alice.getUrl() + "/security/"); HtmlPasswordInput password1 = configurePage.getElementByName("user.password"); HtmlPasswordInput password2 = configurePage.getElementByName("user.password2"); @@ -683,7 +683,7 @@ public void notChangingPassword_hasNoImpactOnSeed() throws Exception { wc_anotherTab.login(alice.getId()); assertUserConnected(wc_anotherTab, alice.getId()); - HtmlPage configurePage = wc.goTo(alice.getUrl() + "/configure"); + HtmlPage configurePage = wc.goTo(alice.getUrl() + "/security/"); // not changing password this time HtmlForm form = configurePage.getFormByName("config"); j.submit(form); @@ -713,7 +713,7 @@ public void changingPassword_withSeedDisable_hasNoImpact() throws Exception { wc_anotherTab.login(alice.getId()); assertUserConnected(wc_anotherTab, alice.getId()); - HtmlPage configurePage = wc.goTo(alice.getUrl() + "/configure"); + HtmlPage configurePage = wc.goTo(alice.getUrl() + "/security/"); HtmlPasswordInput password1 = configurePage.getElementByName("user.password"); HtmlPasswordInput password2 = configurePage.getElementByName("user.password2"); diff --git a/test/src/test/java/jenkins/security/BasicHeaderApiTokenAuthenticatorTest.java b/test/src/test/java/jenkins/security/BasicHeaderApiTokenAuthenticatorTest.java index 873194dfb089..940715b0fe6a 100644 --- a/test/src/test/java/jenkins/security/BasicHeaderApiTokenAuthenticatorTest.java +++ b/test/src/test/java/jenkins/security/BasicHeaderApiTokenAuthenticatorTest.java @@ -70,7 +70,7 @@ public void legacyToken_regularCase() throws Throwable { // default SecurityListener will save the user when adding the LastGrantedAuthoritiesProperty // and so the user is persisted wc.login("user1"); - HtmlPage page = wc.goTo("user/user1/configure"); + HtmlPage page = wc.goTo("user/user1/security/"); String tokenValue = ((HtmlTextInput) page.getDocumentElement().querySelector("#apiToken")).getText(); token.set(tokenValue); } @@ -118,7 +118,7 @@ public void legacyToken_withoutLastGrantedAuthorities() throws Throwable { { JenkinsRule.WebClient wc = j.createWebClient(); wc.login("user1"); - HtmlPage page = wc.goTo("user/user1/configure"); + HtmlPage page = wc.goTo("user/user1/security/"); String tokenValue = ((HtmlTextInput) page.getDocumentElement().querySelector("#apiToken")).getText(); token.set(tokenValue); } diff --git a/test/src/test/java/jenkins/security/LastGrantedAuthoritiesPropertyTest.java b/test/src/test/java/jenkins/security/LastGrantedAuthoritiesPropertyTest.java index 4d29e609860f..5c1c7318c3a9 100644 --- a/test/src/test/java/jenkins/security/LastGrantedAuthoritiesPropertyTest.java +++ b/test/src/test/java/jenkins/security/LastGrantedAuthoritiesPropertyTest.java @@ -43,7 +43,7 @@ public void basicFlow() throws Exception { assertAuthorities(u.impersonate2(), "alice:authenticated:development:us"); // visiting the configuration page shouldn't change authorities - HtmlPage pg = wc.goTo("user/alice/configure"); + HtmlPage pg = wc.goTo("user/alice/account/"); j.submit(pg.getFormByName("config")); p = u.getProperty(LastGrantedAuthoritiesProperty.class); diff --git a/test/src/test/java/jenkins/security/apitoken/ApiTokenStatsRestartTest.java b/test/src/test/java/jenkins/security/apitoken/ApiTokenStatsRestartTest.java index ea1dec6081ae..d76d382e10c1 100644 --- a/test/src/test/java/jenkins/security/apitoken/ApiTokenStatsRestartTest.java +++ b/test/src/test/java/jenkins/security/apitoken/ApiTokenStatsRestartTest.java @@ -103,7 +103,7 @@ public void roundtripWithRestart() throws Throwable { WebClient restWc = j.createWebClient().withBasicCredentials(u.getId(), tokenValue.get()); checkUserIsConnected(restWc, u.getId()); - HtmlPage config = wc.goTo(u.getUrl() + "/configure"); + HtmlPage config = wc.goTo(u.getUrl() + "/security/"); assertEquals(200, config.getWebResponse().getStatusCode()); assertThat(config.getWebResponse().getContentAsString(), containsString(tokenUuid.get())); assertThat(config.getWebResponse().getContentAsString(), containsString(tokenName)); @@ -113,7 +113,7 @@ public void roundtripWithRestart() throws Throwable { restWc.goToXml("whoAmI/api/xml"); } - HtmlPage configWithStats = wc.goTo(u.getUrl() + "/configure"); + HtmlPage configWithStats = wc.goTo(u.getUrl() + "/security/"); assertEquals(200, configWithStats.getWebResponse().getStatusCode()); HtmlSpan useCounterSpan = configWithStats.getDocumentElement().getOneHtmlElementByAttribute("span", "class", "token-use-counter"); assertThat(useCounterSpan.getTextContent(), containsString("" + NUM_CALL_WITH_TOKEN)); @@ -131,7 +131,7 @@ public void roundtripWithRestart() throws Throwable { WebClient wc = j.createWebClient().login(u.getId()); checkUserIsConnected(wc, u.getId()); - HtmlPage config = wc.goTo(u.getUrl() + "/configure"); + HtmlPage config = wc.goTo(u.getUrl() + "/security/"); assertEquals(200, config.getWebResponse().getStatusCode()); assertThat(config.getWebResponse().getContentAsString(), containsString(tokenUuid.get())); assertThat(config.getWebResponse().getContentAsString(), containsString(TOKEN_NAME)); @@ -144,7 +144,7 @@ public void roundtripWithRestart() throws Throwable { WebClient restWc = j.createWebClient().withBasicCredentials(u.getId(), tokenValue.get()); checkUserIsNotConnected(restWc); - HtmlPage configWithoutToken = wc.goTo(u.getUrl() + "/configure"); + HtmlPage configWithoutToken = wc.goTo(u.getUrl() + "/security/"); assertEquals(200, configWithoutToken.getWebResponse().getStatusCode()); assertThat(configWithoutToken.getWebResponse().getContentAsString(), not(containsString(tokenUuid.get()))); assertThat(configWithoutToken.getWebResponse().getContentAsString(), not(containsString(TOKEN_NAME))); diff --git a/test/src/test/java/jenkins/security/apitoken/ApiTokenStatsTest.java b/test/src/test/java/jenkins/security/apitoken/ApiTokenStatsTest.java index 68185e6efac3..0eb010e77d77 100644 --- a/test/src/test/java/jenkins/security/apitoken/ApiTokenStatsTest.java +++ b/test/src/test/java/jenkins/security/apitoken/ApiTokenStatsTest.java @@ -91,7 +91,7 @@ public void roundtrip() throws Exception { WebClient restWc = j.createWebClient().withBasicCredentials(u.getId(), tokenValue); checkUserIsConnected(restWc, u.getId()); - HtmlPage config = wc.goTo(u.getUrl() + "/configure"); + HtmlPage config = wc.goTo(u.getUrl() + "/security/"); assertEquals(200, config.getWebResponse().getStatusCode()); assertThat(config.getWebResponse().getContentAsString(), containsString(tokenUuid)); assertThat(config.getWebResponse().getContentAsString(), containsString(tokenName)); @@ -102,7 +102,7 @@ public void roundtrip() throws Exception { restWc.goToXml("whoAmI/api/xml"); } - HtmlPage configWithStats = wc.goTo(u.getUrl() + "/configure"); + HtmlPage configWithStats = wc.goTo(u.getUrl() + "/security/"); assertEquals(200, configWithStats.getWebResponse().getStatusCode()); HtmlSpan useCounterSpan = configWithStats.getDocumentElement().getOneHtmlElementByAttribute("span", "class", "token-use-counter"); assertThat(useCounterSpan.getTextContent(), containsString("" + NUM_CALL_WITH_TOKEN)); @@ -112,7 +112,7 @@ public void roundtrip() throws Exception { // token is no more valid checkUserIsNotConnected(restWc); - HtmlPage configWithoutToken = wc.goTo(u.getUrl() + "/configure"); + HtmlPage configWithoutToken = wc.goTo(u.getUrl() + "/security/"); assertEquals(200, configWithoutToken.getWebResponse().getStatusCode()); assertThat(configWithoutToken.getWebResponse().getContentAsString(), not(containsString(tokenUuid))); assertThat(configWithoutToken.getWebResponse().getContentAsString(), not(containsString(tokenName))); diff --git a/test/src/test/java/jenkins/security/seed/UserSeedPropertyTest.java b/test/src/test/java/jenkins/security/seed/UserSeedPropertyTest.java index d87761ad391c..a9a3c8830a53 100644 --- a/test/src/test/java/jenkins/security/seed/UserSeedPropertyTest.java +++ b/test/src/test/java/jenkins/security/seed/UserSeedPropertyTest.java @@ -256,7 +256,7 @@ public void userSeedSection_isCorrectlyDisplayed() throws Exception { User alice = User.getById(ALICE, false); assertNotNull(alice); - HtmlPage htmlPage = wc.goTo(alice.getUrl() + "/configure"); + HtmlPage htmlPage = wc.goTo(alice.getUrl() + "/security/"); htmlPage.getDocumentElement().getOneHtmlElementByAttribute("div", "class", "user-seed-panel"); } @@ -280,7 +280,7 @@ public void userSeedSection_isCorrectlyHidden_withSpecificSetting() throws Excep User alice = User.getById(ALICE, false); assertNotNull(alice); - HtmlPage htmlPage = wc.goTo(alice.getUrl() + "/configure"); + HtmlPage htmlPage = wc.goTo(alice.getUrl() + "/security/"); assertThrows("Seed section should not be displayed", ElementNotFoundException.class, () -> htmlPage.getDocumentElement().getOneHtmlElementByAttribute("div", "class", "user-seed-panel")); } finally { From ce728646406e486b2e44a025ddad61a665dabf32 Mon Sep 17 00:00:00 2001 From: Tim Jacomb Date: Sun, 9 Jun 2024 14:00:44 +0100 Subject: [PATCH 09/15] Fix more tests --- .../src/test/java/jenkins/security/ApiCrumbExclusionTest.java | 2 +- test/src/test/java/jenkins/security/ApiTokenPropertyTest.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/src/test/java/jenkins/security/ApiCrumbExclusionTest.java b/test/src/test/java/jenkins/security/ApiCrumbExclusionTest.java index 59f89e8f4977..c746fc7cc4d5 100644 --- a/test/src/test/java/jenkins/security/ApiCrumbExclusionTest.java +++ b/test/src/test/java/jenkins/security/ApiCrumbExclusionTest.java @@ -108,7 +108,7 @@ private void makeRequestAndFail(int expectedCode) { } private void checkWeCanChangeMyDescription(int expectedCode) throws IOException, SAXException { - HtmlPage page = wc.goTo("me/configure"); + HtmlPage page = wc.goTo("me/account/"); HtmlForm form = page.getFormByName("config"); form.getTextAreaByName("_.description").setText("random description: " + Math.random()); diff --git a/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java b/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java index 30361ed8658c..162ac231b664 100644 --- a/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java +++ b/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java @@ -80,7 +80,7 @@ public void basics() throws Exception { assertEquals(u, wc.executeOnServer(User::current)); // Make sure the UI shows the token to the user - HtmlPage config = wc.goTo(u.getUrl() + "/configure"); + HtmlPage config = wc.goTo(u.getUrl() + "/security/"); HtmlForm form = config.getFormByName("config"); assertEquals(token, form.getInputByName("_.apiToken").getValue()); @@ -126,7 +126,7 @@ public void adminsShouldBeUnableToSeeTokensByDefault() throws Exception { // Make sure the UI does not show the token to another user WebClient wc = createClientForUser("bar"); - HtmlPage config = wc.goTo(u.getUrl() + "/configure"); + HtmlPage config = wc.goTo(u.getUrl() + "/security/"); HtmlForm form = config.getFormByName("config"); assertEquals(Messages.ApiTokenProperty_ChangeToken_TokenIsHidden(), form.getInputByName("_.apiToken").getValue()); } From f3b5dc9660d24c4d54e2cc4febb5ca7310e74dc4 Mon Sep 17 00:00:00 2001 From: Tim Jacomb Date: Sun, 9 Jun 2024 22:34:35 +0100 Subject: [PATCH 10/15] Update url name --- .../userproperty/UserPropertyCategoryExperimentalAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryExperimentalAction.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryExperimentalAction.java index 4b883e53264e..55a76100d4b3 100644 --- a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryExperimentalAction.java +++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryExperimentalAction.java @@ -55,7 +55,7 @@ public String getIconFileName() { @Override public String getUrlName() { - return "experimental"; + return "experiments"; } public @NonNull List getMyCategoryDescriptors() { From 84cfde387c21c2c11feda39b35ab5cad370d2b1c Mon Sep 17 00:00:00 2001 From: Tim Jacomb Date: Sun, 16 Jun 2024 22:28:26 +0100 Subject: [PATCH 11/15] Fix javadoc --- .../hudson/model/userproperty/UserPropertyCategory.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategory.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategory.java index 22b84ac4a30a..72aabc71f9ff 100644 --- a/core/src/main/java/hudson/model/userproperty/UserPropertyCategory.java +++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategory.java @@ -72,7 +72,7 @@ public static ExtensionList all() { * This category is used when the {@link hudson.model.UserPropertyDescriptor} has not implemented * the {@link UserPropertyDescriptor#getUserPropertyCategory()} method * (or the getUserPropertyCategoryAsString method for compatibility reason). - * + *

* If you do not know what to use, choose the {@link Account} instead of this one. */ @Extension @@ -92,7 +92,7 @@ public String getShortDescription() { /** * User property related to account settings (e.g. timezone, email, ...). - * + *

* It could be seen as the default choice for {@link UserProperty} that are defining their category. * Currently it has the same effect as {@link Unclassified} but the behavior could change in the future. */ @@ -145,7 +145,9 @@ public String getShortDescription() { } /** - * Per user feature flags (e.g. new design, ...). + * User interface related configurations (e.g. theme, language, ...). + *

+ * See also {@link jenkins.appearance.AppearanceCategory}. */ @Extension @Symbol("appearance") From cf02775b173a3fde5b52142f1ee6b75bce7e9029 Mon Sep 17 00:00:00 2001 From: Tim Jacomb Date: Mon, 17 Jun 2024 07:53:54 +0100 Subject: [PATCH 12/15] Javadoc build issue --- .../hudson/model/userproperty/UserPropertyCategory.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategory.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategory.java index 72aabc71f9ff..7fb36956f02b 100644 --- a/core/src/main/java/hudson/model/userproperty/UserPropertyCategory.java +++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategory.java @@ -72,7 +72,7 @@ public static ExtensionList all() { * This category is used when the {@link hudson.model.UserPropertyDescriptor} has not implemented * the {@link UserPropertyDescriptor#getUserPropertyCategory()} method * (or the getUserPropertyCategoryAsString method for compatibility reason). - *

+ *

* If you do not know what to use, choose the {@link Account} instead of this one. */ @Extension @@ -92,7 +92,7 @@ public String getShortDescription() { /** * User property related to account settings (e.g. timezone, email, ...). - *

+ *

* It could be seen as the default choice for {@link UserProperty} that are defining their category. * Currently it has the same effect as {@link Unclassified} but the behavior could change in the future. */ @@ -146,7 +146,7 @@ public String getShortDescription() { /** * User interface related configurations (e.g. theme, language, ...). - *

+ *

* See also {@link jenkins.appearance.AppearanceCategory}. */ @Extension From c7b23e71755c46898f5df7c344eae0636ce94fa3 Mon Sep 17 00:00:00 2001 From: Tim Jacomb Date: Fri, 21 Jun 2024 09:18:45 +0100 Subject: [PATCH 13/15] Fix link --- .../hudson/security/HudsonPrivateSecurityRealm/index.jelly | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/index.jelly b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/index.jelly index 88939feeaca3..559e2370a720 100644 --- a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/index.jelly +++ b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/index.jelly @@ -63,7 +63,7 @@ THE SOFTWARE.

From 3439a11a6661cfe64a54d9fc3659c2fe7edc78ba Mon Sep 17 00:00:00 2001 From: Tim Jacomb Date: Fri, 21 Jun 2024 09:43:12 +0100 Subject: [PATCH 14/15] Fix formatting --- .../hudson/model/userproperty/UserPropertyCategory.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategory.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategory.java index 7fb36956f02b..803b7e2d3527 100644 --- a/core/src/main/java/hudson/model/userproperty/UserPropertyCategory.java +++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategory.java @@ -63,9 +63,11 @@ public static ExtensionList all() { } public static @NonNull T get(Class type) { - T category = all().get(type); if (category == null) { + T category = all().get(type); + if (category == null) { throw new AssertionError("Category not found. It seems the " + type + " is not annotated with @Extension and so not registered"); - } return category; + } + return category; } /** From 2a66a476a2628fb1ddca534dea500bc5a14e8c65 Mon Sep 17 00:00:00 2001 From: Tim Jacomb Date: Wed, 26 Jun 2024 14:31:41 +0100 Subject: [PATCH 15/15] Add permission checks --- .../model/userproperty/UserPropertyCategoryAccountAction.java | 2 +- .../userproperty/UserPropertyCategoryAppearanceAction.java | 3 ++- .../userproperty/UserPropertyCategoryExperimentalAction.java | 3 ++- .../userproperty/UserPropertyCategoryPreferencesAction.java | 3 ++- .../model/userproperty/UserPropertyCategorySecurityAction.java | 3 ++- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAccountAction.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAccountAction.java index d08a9be7cf20..822cdc6f4c99 100644 --- a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAccountAction.java +++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAccountAction.java @@ -61,7 +61,7 @@ public String getDisplayName() { @Override public String getIconFileName() { - return "symbol-settings"; + return getTargetUser().hasPermission(Jenkins.ADMINISTER) ? "symbol-settings" : null; } @Override diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAppearanceAction.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAppearanceAction.java index 8d7243e22542..88d08a8add70 100644 --- a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAppearanceAction.java +++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAppearanceAction.java @@ -33,6 +33,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import jenkins.model.Jenkins; import org.jenkinsci.Symbol; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -50,7 +51,7 @@ public String getDisplayName() { @Override public String getIconFileName() { - return "symbol-brush-outline"; + return getTargetUser().hasPermission(Jenkins.ADMINISTER) ? "symbol-brush-outline" : null; } @Override diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryExperimentalAction.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryExperimentalAction.java index 55a76100d4b3..bb242bacad7a 100644 --- a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryExperimentalAction.java +++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryExperimentalAction.java @@ -33,6 +33,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import jenkins.model.Jenkins; import org.jenkinsci.Symbol; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -50,7 +51,7 @@ public String getDisplayName() { @Override public String getIconFileName() { - return "symbol-flask"; + return getTargetUser().hasPermission(Jenkins.ADMINISTER) ? "symbol-flask" : null; } @Override diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryPreferencesAction.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryPreferencesAction.java index c956306b8c59..7a74b702e6c0 100644 --- a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryPreferencesAction.java +++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryPreferencesAction.java @@ -33,6 +33,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import jenkins.model.Jenkins; import org.jenkinsci.Symbol; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -50,7 +51,7 @@ public String getDisplayName() { @Override public String getIconFileName() { - return "symbol-parameters"; + return getTargetUser().hasPermission(Jenkins.ADMINISTER) ? "symbol-parameters" : null; } @Override diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategorySecurityAction.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategorySecurityAction.java index d9a3e81a0933..a6cb3e6ed3c4 100644 --- a/core/src/main/java/hudson/model/userproperty/UserPropertyCategorySecurityAction.java +++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategorySecurityAction.java @@ -34,6 +34,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import jenkins.model.Jenkins; import org.jenkinsci.Symbol; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -51,7 +52,7 @@ public String getDisplayName() { @Override public String getIconFileName() { - return "symbol-lock-closed"; + return getTargetUser().hasPermission(Jenkins.ADMINISTER) ? "symbol-lock-closed" : null; } @Override