From 13417cf9c6eec555b51da49742e47939d2f5715b Mon Sep 17 00:00:00 2001 From: James Moger <james.moger@gitblit.com> Date: Fri, 19 Oct 2012 22:47:33 -0400 Subject: [PATCH] Exclude submodules from zip downloads (issue 151) --- src/com/gitblit/wicket/pages/EditRepositoryPage.java | 272 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 247 insertions(+), 25 deletions(-) diff --git a/src/com/gitblit/wicket/pages/EditRepositoryPage.java b/src/com/gitblit/wicket/pages/EditRepositoryPage.java index be88bd5..a2dad10 100644 --- a/src/com/gitblit/wicket/pages/EditRepositoryPage.java +++ b/src/com/gitblit/wicket/pages/EditRepositoryPage.java @@ -19,33 +19,49 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.wicket.PageParameters; +import org.apache.wicket.behavior.SimpleAttributeModifier; import org.apache.wicket.extensions.markup.html.form.palette.Palette; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.Button; import org.apache.wicket.markup.html.form.CheckBox; -import org.apache.wicket.markup.html.form.ChoiceRenderer; import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.IChoiceRenderer; +import org.apache.wicket.markup.html.form.Radio; +import org.apache.wicket.markup.html.form.RadioGroup; import org.apache.wicket.markup.html.form.TextField; +import org.apache.wicket.markup.html.list.ListItem; +import org.apache.wicket.markup.html.list.ListView; import org.apache.wicket.model.CompoundPropertyModel; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; import org.apache.wicket.model.util.CollectionModel; import org.apache.wicket.model.util.ListModel; +import com.gitblit.Constants; import com.gitblit.Constants.AccessRestrictionType; +import com.gitblit.Constants.AuthorizationControl; import com.gitblit.Constants.FederationStrategy; import com.gitblit.GitBlit; import com.gitblit.GitBlitException; import com.gitblit.Keys; import com.gitblit.models.RepositoryModel; import com.gitblit.models.UserModel; +import com.gitblit.utils.ArrayUtils; import com.gitblit.utils.StringUtils; import com.gitblit.wicket.GitBlitWebSession; +import com.gitblit.wicket.StringChoiceRenderer; import com.gitblit.wicket.WicketUtils; +import com.gitblit.wicket.panels.BulletListPanel; public class EditRepositoryPage extends RootSubPage { @@ -53,11 +69,31 @@ private boolean isAdmin; + private IModel<String> mailingLists; + public EditRepositoryPage() { // create constructor super(); isCreate = true; - setupPage(new RepositoryModel()); + RepositoryModel model = new RepositoryModel(); + String restriction = GitBlit.getString(Keys.git.defaultAccessRestriction, null); + model.accessRestriction = AccessRestrictionType.fromName(restriction); + String authorization = GitBlit.getString(Keys.git.defaultAuthorizationControl, null); + model.authorizationControl = AuthorizationControl.fromName(authorization); + + GitBlitWebSession session = GitBlitWebSession.get(); + UserModel user = session.getUser(); + if (user != null && user.canCreate() && !user.canAdmin()) { + // personal create permissions, inject personal repository path + model.name = user.getPersonalPath() + "/"; + model.projectPath = user.getPersonalPath(); + model.owner = user.username; + // personal repositories are private by default + model.accessRestriction = AccessRestrictionType.VIEW; + model.authorizationControl = AuthorizationControl.NAMED; + } + + setupPage(model); } public EditRepositoryPage(PageParameters params) { @@ -73,31 +109,101 @@ // ensure this user can create or edit this repository checkPermissions(repositoryModel); + List<String> indexedBranches = new ArrayList<String>(); List<String> federationSets = new ArrayList<String>(); List<String> repositoryUsers = new ArrayList<String>(); + List<String> repositoryTeams = new ArrayList<String>(); + List<String> preReceiveScripts = new ArrayList<String>(); + List<String> postReceiveScripts = new ArrayList<String>(); + + GitBlitWebSession session = GitBlitWebSession.get(); + final UserModel user = session.getUser() == null ? UserModel.ANONYMOUS : session.getUser(); + if (isCreate) { - super.setupPage(getString("gb.newRepository"), ""); + if (user.canAdmin()) { + super.setupPage(getString("gb.newRepository"), ""); + } else { + super.setupPage(getString("gb.newRepository"), user.getDisplayName()); + } } else { super.setupPage(getString("gb.edit"), repositoryModel.name); if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE)) { repositoryUsers.addAll(GitBlit.self().getRepositoryUsers(repositoryModel)); + repositoryTeams.addAll(GitBlit.self().getRepositoryTeams(repositoryModel)); Collections.sort(repositoryUsers); } federationSets.addAll(repositoryModel.federationSets); - } - + if (!ArrayUtils.isEmpty(repositoryModel.indexedBranches)) { + indexedBranches.addAll(repositoryModel.indexedBranches); + } + } final String oldName = repositoryModel.name; // users palette final Palette<String> usersPalette = new Palette<String>("users", new ListModel<String>( repositoryUsers), new CollectionModel<String>(GitBlit.self().getAllUsernames()), - new ChoiceRenderer<String>("", ""), 10, false); + new StringChoiceRenderer(), 10, false); + // teams palette + final Palette<String> teamsPalette = new Palette<String>("teams", new ListModel<String>( + repositoryTeams), new CollectionModel<String>(GitBlit.self().getAllTeamnames()), + new StringChoiceRenderer(), 8, false); + + // indexed local branches palette + List<String> allLocalBranches = new ArrayList<String>(); + allLocalBranches.add(Constants.DEFAULT_BRANCH); + allLocalBranches.addAll(repositoryModel.getLocalBranches()); + boolean luceneEnabled = GitBlit.getBoolean(Keys.web.allowLuceneIndexing, true); + final Palette<String> indexedBranchesPalette = new Palette<String>("indexedBranches", new ListModel<String>( + indexedBranches), new CollectionModel<String>(allLocalBranches), + new StringChoiceRenderer(), 8, false); + indexedBranchesPalette.setEnabled(luceneEnabled); + // federation sets palette List<String> sets = GitBlit.getStrings(Keys.federation.sets); final Palette<String> federationSetsPalette = new Palette<String>("federationSets", new ListModel<String>(federationSets), new CollectionModel<String>(sets), - new ChoiceRenderer<String>("", ""), 10, false); + new StringChoiceRenderer(), 8, false); + + // pre-receive palette + if (!ArrayUtils.isEmpty(repositoryModel.preReceiveScripts)) { + preReceiveScripts.addAll(repositoryModel.preReceiveScripts); + } + final Palette<String> preReceivePalette = new Palette<String>("preReceiveScripts", + new ListModel<String>(preReceiveScripts), new CollectionModel<String>(GitBlit + .self().getPreReceiveScriptsUnused(repositoryModel)), + new StringChoiceRenderer(), 12, true); + + // post-receive palette + if (!ArrayUtils.isEmpty(repositoryModel.postReceiveScripts)) { + postReceiveScripts.addAll(repositoryModel.postReceiveScripts); + } + final Palette<String> postReceivePalette = new Palette<String>("postReceiveScripts", + new ListModel<String>(postReceiveScripts), new CollectionModel<String>(GitBlit + .self().getPostReceiveScriptsUnused(repositoryModel)), + new StringChoiceRenderer(), 12, true); + + // custom fields + final Map<String, String> customFieldsMap = GitBlit.getMap(Keys.groovy.customFields); + List<String> customKeys = new ArrayList<String>(customFieldsMap.keySet()); + final ListView<String> customFieldsListView = new ListView<String>("customFieldsListView", customKeys) { + + private static final long serialVersionUID = 1L; + + @Override + protected void populateItem(ListItem<String> item) { + String key = item.getModelObject(); + item.add(new Label("customFieldLabel", customFieldsMap.get(key))); + + String value = ""; + if (repositoryModel.customFields != null && repositoryModel.customFields.containsKey(key)) { + value = repositoryModel.customFields.get(key); + } + TextField<String> field = new TextField<String>("customFieldValue", new Model<String>(value)); + item.add(field); + } + }; + customFieldsListView.setReuseItems(true); CompoundPropertyModel<RepositoryModel> model = new CompoundPropertyModel<RepositoryModel>( repositoryModel); @@ -109,11 +215,14 @@ protected void onSubmit() { try { // confirm a repository name was entered - if (StringUtils.isEmpty(repositoryModel.name)) { - error("Please set repository name!"); + if (repositoryModel.name == null && StringUtils.isEmpty(repositoryModel.name)) { + error(getString("gb.pleaseSetRepositoryName")); return; } - + + // ensure name is trimmed + repositoryModel.name = repositoryModel.name.trim(); + // automatically convert backslashes to forward slashes repositoryModel.name = repositoryModel.name.replace('\\', '/'); // Automatically replace // with / @@ -121,35 +230,54 @@ // prohibit folder paths if (repositoryModel.name.startsWith("/")) { - error("Leading root folder references (/) are prohibited."); + error(getString("gb.illegalLeadingSlash")); return; } if (repositoryModel.name.startsWith("../")) { - error("Relative folder references (../) are prohibited."); + error(getString("gb.illegalRelativeSlash")); return; } if (repositoryModel.name.contains("/../")) { - error("Relative folder references (../) are prohibited."); + error(getString("gb.illegalRelativeSlash")); return; + } + if (repositoryModel.name.endsWith("/")) { + repositoryModel.name = repositoryModel.name.substring(0, repositoryModel.name.length() - 1); } // confirm valid characters in repository name Character c = StringUtils.findInvalidCharacter(repositoryModel.name); if (c != null) { - error(MessageFormat.format("Illegal character ''{0}'' in repository name!", + error(MessageFormat.format(getString("gb.illegalCharacterRepositoryName"), c)); return; + } + + if (user.canCreate() && !user.canAdmin()) { + // ensure repository name begins with the user's path + if (!repositoryModel.name.startsWith(user.getPersonalPath())) { + error(MessageFormat.format(getString("gb.illegalPersonalRepositoryLocation"), + user.getPersonalPath())); + return; + } + + if (repositoryModel.name.equals(user.getPersonalPath())) { + // reset path prefix and show error + repositoryModel.name = user.getPersonalPath() + "/"; + error(getString("gb.pleaseSetRepositoryName")); + return; + } } // confirm access restriction selection if (repositoryModel.accessRestriction == null) { - error("Please select access restriction!"); + error(getString("gb.selectAccessRestriction")); return; } // confirm federation strategy selection if (repositoryModel.federationStrategy == null) { - error("Please select federation strategy!"); + error(getString("gb.selectFederationStrategy")); return; } @@ -162,11 +290,61 @@ } } + // set mailing lists + String ml = mailingLists.getObject(); + if (!StringUtils.isEmpty(ml)) { + Set<String> list = new HashSet<String>(); + for (String address : ml.split("(,|\\s)")) { + if (StringUtils.isEmpty(address)) { + continue; + } + list.add(address.toLowerCase()); + } + repositoryModel.mailingLists = new ArrayList<String>(list); + } + + // indexed branches + List<String> indexedBranches = new ArrayList<String>(); + Iterator<String> branches = indexedBranchesPalette.getSelectedChoices(); + while (branches.hasNext()) { + indexedBranches.add(branches.next()); + } + repositoryModel.indexedBranches = indexedBranches; + + // pre-receive scripts + List<String> preReceiveScripts = new ArrayList<String>(); + Iterator<String> pres = preReceivePalette.getSelectedChoices(); + while (pres.hasNext()) { + preReceiveScripts.add(pres.next()); + } + repositoryModel.preReceiveScripts = preReceiveScripts; + + // post-receive scripts + List<String> postReceiveScripts = new ArrayList<String>(); + Iterator<String> post = postReceivePalette.getSelectedChoices(); + while (post.hasNext()) { + postReceiveScripts.add(post.next()); + } + repositoryModel.postReceiveScripts = postReceiveScripts; + + // custom fields + repositoryModel.customFields = new LinkedHashMap<String, String>(); + for (int i = 0; i < customFieldsListView.size(); i++) { + ListItem<String> child = (ListItem<String>) customFieldsListView.get(i); + String key = child.getModelObject(); + + TextField<String> field = (TextField<String>) child.get("customFieldValue"); + String value = field.getValue(); + + repositoryModel.customFields.put(key, value); + } + // save the repository GitBlit.self().updateRepositoryModel(oldName, repositoryModel, isCreate); - // save the repository access list + // repository access if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE)) { + // save the user access list Iterator<String> users = usersPalette.getSelectedChoices(); List<String> repositoryUsers = new ArrayList<String>(); while (users.hasNext()) { @@ -178,6 +356,14 @@ repositoryUsers.add(repositoryModel.owner); } GitBlit.self().setRepositoryUsers(repositoryModel, repositoryUsers); + + // save the team access list + Iterator<String> teams = teamsPalette.getSelectedChoices(); + List<String> repositoryTeams = new ArrayList<String>(); + while (teams.hasNext()) { + repositoryTeams.add(teams.next()); + } + GitBlit.self().setRepositoryTeams(repositoryModel, repositoryTeams); } } catch (GitBlitException e) { error(e.getMessage()); @@ -188,16 +374,27 @@ } }; + // do not let the browser pre-populate these fields + form.add(new SimpleAttributeModifier("autocomplete", "off")); + // field names reflective match RepositoryModel fields - form.add(new TextField<String>("name").setEnabled(isCreate || isAdmin)); + form.add(new TextField<String>("name").setEnabled(isCreate || isAdmin || repositoryModel.isUsersPersonalRepository(user.username))); form.add(new TextField<String>("description")); form.add(new DropDownChoice<String>("owner", GitBlit.self().getAllUsernames()) .setEnabled(GitBlitWebSession.get().canAdmin())); + form.add(new CheckBox("allowForks")); form.add(new DropDownChoice<AccessRestrictionType>("accessRestriction", Arrays .asList(AccessRestrictionType.values()), new AccessRestrictionRenderer())); form.add(new CheckBox("isFrozen")); // TODO enable origin definition form.add(new TextField<String>("origin").setEnabled(false/* isCreate */)); + + // allow relinking HEAD to a branch or tag other than master on edit repository + List<String> availableRefs = new ArrayList<String>(); + if (!ArrayUtils.isEmpty(repositoryModel.availableRefs)) { + availableRefs.addAll(repositoryModel.availableRefs); + } + form.add(new DropDownChoice<String>("HEAD", availableRefs).setEnabled(availableRefs.size() > 0)); // federation strategies - remove ORIGIN choice if this repository has // no origin. @@ -214,8 +411,33 @@ form.add(new CheckBox("showReadme")); form.add(new CheckBox("skipSizeCalculation")); form.add(new CheckBox("skipSummaryMetrics")); + mailingLists = new Model<String>(ArrayUtils.isEmpty(repositoryModel.mailingLists) ? "" + : StringUtils.flattenStrings(repositoryModel.mailingLists, " ")); + form.add(new TextField<String>("mailingLists", mailingLists)); + form.add(indexedBranchesPalette); + + RadioGroup<AuthorizationControl> group = new RadioGroup<AuthorizationControl>("authorizationControl"); + Radio<AuthorizationControl> allowAuthenticated = new Radio<AuthorizationControl>("allowAuthenticated", new Model<AuthorizationControl>(AuthorizationControl.AUTHENTICATED)); + Radio<AuthorizationControl> allowNamed = new Radio<AuthorizationControl>("allowNamed", new Model<AuthorizationControl>(AuthorizationControl.NAMED)); + group.add(allowAuthenticated); + group.add(allowNamed); + form.add(group); + + form.add(new CheckBox("verifyCommitter")); + form.add(usersPalette); + form.add(teamsPalette); form.add(federationSetsPalette); + form.add(preReceivePalette); + form.add(new BulletListPanel("inheritedPreReceive", getString("gb.inherited"), GitBlit.self() + .getPreReceiveScriptsInherited(repositoryModel))); + form.add(postReceivePalette); + form.add(new BulletListPanel("inheritedPostReceive", getString("gb.inherited"), GitBlit.self() + .getPostReceiveScriptsInherited(repositoryModel))); + + WebMarkupContainer customFieldsSection = new WebMarkupContainer("customFieldsSection"); + customFieldsSection.add(customFieldsListView); + form.add(customFieldsSection.setVisible(!GitBlit.getString(Keys.groovy.customFields, "").isEmpty())); form.add(new Button("save")); Button cancel = new Button("cancel") { @@ -250,31 +472,31 @@ if (authenticateAdmin) { if (user == null) { // No Login Available - error("Administration requires a login", true); + error(getString("gb.errorAdminLoginRequired"), true); } if (isCreate) { // Create Repository - if (!user.canAdmin) { - // Only Administrators May Create - error("Only an administrator may create a repository", true); + if (!user.canCreate() && !user.canAdmin()) { + // Only administrators or permitted users may create + error(getString("gb.errorOnlyAdminMayCreateRepository"), true); } } else { // Edit Repository - if (user.canAdmin) { + if (user.canAdmin()) { // Admins can edit everything isAdmin = true; return; } else { if (!model.owner.equalsIgnoreCase(user.username)) { // User is not an Admin nor Owner - error("Only an administrator or the owner may edit a repository", true); + error(getString("gb.errorOnlyAdminOrOwnerMayEditRepository"), true); } } } } } else { // No Administration Permitted - error("Administration is disabled", true); + error(getString("gb.errorAdministrationDisabled"), true); } } -- Gitblit v1.9.1