@@ -99,8 +99,7 @@ public class RpcServlet extends JsonServlet { | |||
} else if (RpcRequest.EDIT_REPOSITORY.equals(reqType)) { | |||
// edit repository | |||
RepositoryModel model = deserialize(request, response, RepositoryModel.class); | |||
// name parameter specifies original repository name in event of | |||
// rename | |||
// name specifies original repository name in event of rename | |||
String repoName = objectName; | |||
if (repoName == null) { | |||
repoName = model.name; |
@@ -24,8 +24,14 @@ import java.awt.GridLayout; | |||
import java.awt.Insets; | |||
import java.awt.event.ActionEvent; | |||
import java.awt.event.ActionListener; | |||
import java.text.MessageFormat; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.HashSet; | |||
import java.util.List; | |||
import java.util.Set; | |||
import javax.swing.DefaultComboBoxModel; | |||
import javax.swing.ImageIcon; | |||
import javax.swing.JButton; | |||
import javax.swing.JCheckBox; | |||
@@ -42,7 +48,6 @@ import javax.swing.ListCellRenderer; | |||
import com.gitblit.Constants.AccessRestrictionType; | |||
import com.gitblit.Constants.FederationStrategy; | |||
import com.gitblit.models.RepositoryModel; | |||
import com.gitblit.models.UserModel; | |||
import com.gitblit.utils.StringUtils; | |||
/** | |||
@@ -56,6 +61,8 @@ public class EditRepositoryDialog extends JDialog { | |||
private final RepositoryModel repository; | |||
private boolean isCreate; | |||
private boolean canceled = true; | |||
private JTextField nameField; | |||
@@ -76,42 +83,37 @@ public class EditRepositoryDialog extends JDialog { | |||
private JComboBox federationStrategy; | |||
private JComboBox owner; | |||
private JComboBox ownerField; | |||
private JPalette<String> usersPalette; | |||
private JPalette<String> setsPalette; | |||
public EditRepositoryDialog(List<UserModel> allusers) { | |||
this(new RepositoryModel(), allusers); | |||
private Set<String> repositoryNames; | |||
public EditRepositoryDialog() { | |||
this(new RepositoryModel()); | |||
this.isCreate = true; | |||
setTitle(Translation.get("gb.newRepository")); | |||
} | |||
public EditRepositoryDialog(RepositoryModel aRepository, List<UserModel> allUsers) { | |||
public EditRepositoryDialog(RepositoryModel aRepository) { | |||
super(); | |||
this.repository = new RepositoryModel(); | |||
initialize(aRepository, allUsers); | |||
this.repositoryNames = new HashSet<String>(); | |||
this.isCreate = false; | |||
initialize(aRepository); | |||
setModal(true); | |||
setTitle(Translation.get("gb.edit") + ": " + aRepository.name); | |||
setIconImage(new ImageIcon(getClass().getResource("/gitblt-favicon.png")).getImage()); | |||
} | |||
private void initialize(RepositoryModel anRepository, List<UserModel> allUsers) { | |||
private void initialize(RepositoryModel anRepository) { | |||
nameField = new JTextField(anRepository.name == null ? "" : anRepository.name, 35); | |||
descriptionField = new JTextField(anRepository.description == null ? "" | |||
: anRepository.description, 35); | |||
owner = new JComboBox(allUsers.toArray()); | |||
if (!StringUtils.isEmpty(anRepository.owner)) { | |||
UserModel currentOwner = null; | |||
for (UserModel user : allUsers) { | |||
if (user.username.equalsIgnoreCase(anRepository.owner)) { | |||
currentOwner = user; | |||
break; | |||
} | |||
} | |||
owner.setSelectedItem(currentOwner); | |||
} | |||
ownerField = new JComboBox(); | |||
useTickets = new JCheckBox(Translation.get("gb.useTicketsDescription"), | |||
anRepository.useTickets); | |||
@@ -126,14 +128,21 @@ public class EditRepositoryDialog extends JDialog { | |||
accessRestriction.setRenderer(new AccessRestrictionRenderer()); | |||
accessRestriction.setSelectedItem(anRepository.accessRestriction); | |||
federationStrategy = new JComboBox(FederationStrategy.values()); | |||
// federation strategies - remove ORIGIN choice if this repository has | |||
// no origin. | |||
List<FederationStrategy> federationStrategies = new ArrayList<FederationStrategy>( | |||
Arrays.asList(FederationStrategy.values())); | |||
if (StringUtils.isEmpty(anRepository.origin)) { | |||
federationStrategies.remove(FederationStrategy.FEDERATE_ORIGIN); | |||
} | |||
federationStrategy = new JComboBox(federationStrategies.toArray()); | |||
federationStrategy.setRenderer(new FederationStrategyRenderer()); | |||
federationStrategy.setSelectedItem(anRepository.federationStrategy); | |||
JPanel fieldsPanel = new JPanel(new GridLayout(0, 1)); | |||
fieldsPanel.add(newFieldPanel(Translation.get("gb.name"), nameField)); | |||
fieldsPanel.add(newFieldPanel(Translation.get("gb.description"), descriptionField)); | |||
fieldsPanel.add(newFieldPanel(Translation.get("gb.owner"), owner)); | |||
fieldsPanel.add(newFieldPanel(Translation.get("gb.owner"), ownerField)); | |||
fieldsPanel.add(newFieldPanel(Translation.get("gb.enableTickets"), useTickets)); | |||
fieldsPanel.add(newFieldPanel(Translation.get("gb.enableDocs"), useDocs)); | |||
@@ -214,19 +223,104 @@ public class EditRepositoryDialog extends JDialog { | |||
} | |||
private boolean validateFields() { | |||
// TODO validate input and populate model | |||
String rname = nameField.getText(); | |||
if (StringUtils.isEmpty(rname)) { | |||
error("Please enter a repository name!"); | |||
return false; | |||
} | |||
// automatically convert backslashes to forward slashes | |||
rname = rname.replace('\\', '/'); | |||
// Automatically replace // with / | |||
rname = rname.replace("//", "/"); | |||
// prohibit folder paths | |||
if (rname.startsWith("/")) { | |||
error("Leading root folder references (/) are prohibited."); | |||
return false; | |||
} | |||
if (rname.startsWith("../")) { | |||
error("Relative folder references (../) are prohibited."); | |||
return false; | |||
} | |||
if (rname.contains("/../")) { | |||
error("Relative folder references (../) are prohibited."); | |||
return false; | |||
} | |||
// confirm valid characters in repository name | |||
Character c = StringUtils.findInvalidCharacter(rname); | |||
if (c != null) { | |||
error(MessageFormat.format("Illegal character ''{0}'' in repository name!", c)); | |||
return false; | |||
} | |||
// verify repository name uniqueness on create | |||
if (isCreate) { | |||
// force repo names to lowercase | |||
// this means that repository name checking for rpc creation | |||
// is case-insensitive, regardless of the Gitblit server's | |||
// filesystem | |||
if (repositoryNames.contains(rname.toLowerCase())) { | |||
error(MessageFormat.format( | |||
"Can not create repository ''{0}'' because it already exists.", rname)); | |||
return false; | |||
} | |||
} | |||
if (accessRestriction.getSelectedItem() == null) { | |||
error("Please select access restriction!"); | |||
return false; | |||
} | |||
if (federationStrategy.getSelectedItem() == null) { | |||
error("Please select federation strategy!"); | |||
return false; | |||
} | |||
repository.name = rname; | |||
repository.description = descriptionField.getText(); | |||
repository.owner = ownerField.getSelectedItem() == null ? null : ownerField | |||
.getSelectedItem().toString(); | |||
repository.useTickets = useTickets.isSelected(); | |||
repository.useDocs = useDocs.isSelected(); | |||
repository.showRemoteBranches = showRemoteBranches.isSelected(); | |||
repository.showReadme = showReadme.isSelected(); | |||
repository.isFrozen = isFrozen.isSelected(); | |||
repository.accessRestriction = (AccessRestrictionType) accessRestriction.getSelectedItem(); | |||
repository.federationStrategy = (FederationStrategy) federationStrategy.getSelectedItem(); | |||
if (repository.federationStrategy.exceeds(FederationStrategy.EXCLUDE)) { | |||
repository.federationSets = setsPalette.getSelections(); | |||
} | |||
return true; | |||
} | |||
private void showValidationError(String message) { | |||
private void error(String message) { | |||
JOptionPane.showMessageDialog(EditRepositoryDialog.this, message, | |||
Translation.get("gb.error"), JOptionPane.ERROR_MESSAGE); | |||
} | |||
public void setUsers(List<String> all, List<String> selected) { | |||
public void setUsers(String owner, List<String> all, List<String> selected) { | |||
ownerField.setModel(new DefaultComboBoxModel(all.toArray())); | |||
if (!StringUtils.isEmpty(owner)) { | |||
ownerField.setSelectedItem(owner); | |||
} | |||
usersPalette.setObjects(all, selected); | |||
} | |||
public void setRepositories(List<RepositoryModel> repositories) { | |||
repositoryNames.clear(); | |||
for (RepositoryModel repository : repositories) { | |||
// force repo names to lowercase | |||
// this means that repository name checking for rpc creation | |||
// is case-insensitive, regardless of the Gitblit server's | |||
// filesystem | |||
repositoryNames.add(repository.name.toLowerCase()); | |||
} | |||
} | |||
public void setFederationSets(List<String> all, List<String> selected) { | |||
setsPalette.setObjects(all, selected); | |||
} | |||
@@ -238,6 +332,10 @@ public class EditRepositoryDialog extends JDialog { | |||
return repository; | |||
} | |||
public List<String> getPermittedUsers() { | |||
return usersPalette.getSelections(); | |||
} | |||
/** | |||
* ListCellRenderer to display descriptive text about the access | |||
* restriction. |
@@ -26,7 +26,9 @@ import java.awt.event.ActionListener; | |||
import java.text.MessageFormat; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.HashSet; | |||
import java.util.List; | |||
import java.util.Set; | |||
import javax.swing.ImageIcon; | |||
import javax.swing.JButton; | |||
@@ -54,6 +56,8 @@ public class EditUserDialog extends JDialog { | |||
private final IStoredSettings settings; | |||
private boolean isCreate; | |||
private boolean canceled = true; | |||
private JTextField usernameField; | |||
@@ -68,15 +72,20 @@ public class EditUserDialog extends JDialog { | |||
private JPalette<String> repositoryPalette; | |||
private Set<String> usernames; | |||
public EditUserDialog(IStoredSettings settings) { | |||
this(new UserModel(""), settings); | |||
setTitle(Translation.get("gb.newUser")); | |||
this.isCreate = true; | |||
setTitle(Translation.get("gb.newUser")); | |||
} | |||
public EditUserDialog(UserModel anUser, IStoredSettings settings) { | |||
super(); | |||
this.user = new UserModel(""); | |||
this.settings = settings; | |||
this.usernames = new HashSet<String>(); | |||
this.isCreate = false; | |||
initialize(anUser); | |||
setModal(true); | |||
setTitle(Translation.get("gb.edit") + ": " + anUser.username); | |||
@@ -161,20 +170,17 @@ public class EditUserDialog extends JDialog { | |||
private boolean validateFields() { | |||
String uname = usernameField.getText(); | |||
if (StringUtils.isEmpty(uname)) { | |||
showValidationError("Please enter a username!"); | |||
error("Please enter a username!"); | |||
return false; | |||
} | |||
// TODO verify username uniqueness on create | |||
// if (isCreate) { | |||
// UserModel model = GitBlit.self().getUserModel(username); | |||
// if (model != null) { | |||
// error(MessageFormat.format("Username ''{0}'' is unavailable.", | |||
// username)); | |||
// return; | |||
// } | |||
// } | |||
// verify username uniqueness on create | |||
if (isCreate) { | |||
if (usernames.contains(uname.toLowerCase())) { | |||
error(MessageFormat.format("Username ''{0}'' is unavailable.", uname)); | |||
return false; | |||
} | |||
} | |||
int minLength = settings.getInteger(Keys.realm.minPasswordLength, 5); | |||
if (minLength < 4) { | |||
@@ -182,17 +188,17 @@ public class EditUserDialog extends JDialog { | |||
} | |||
char[] pw = passwordField.getPassword(); | |||
if (pw == null || pw.length < minLength) { | |||
showValidationError(MessageFormat.format( | |||
error(MessageFormat.format( | |||
"Password is too short. Minimum length is {0} characters.", minLength)); | |||
return false; | |||
} | |||
char[] cpw = confirmPasswordField.getPassword(); | |||
if (cpw == null || cpw.length != pw.length) { | |||
showValidationError("Please confirm the password!"); | |||
error("Please confirm the password!"); | |||
return false; | |||
} | |||
if (!Arrays.equals(pw, cpw)) { | |||
showValidationError("Passwords do not match!"); | |||
error("Passwords do not match!"); | |||
return false; | |||
} | |||
user.username = uname; | |||
@@ -211,11 +217,18 @@ public class EditUserDialog extends JDialog { | |||
return true; | |||
} | |||
private void showValidationError(String message) { | |||
private void error(String message) { | |||
JOptionPane.showMessageDialog(EditUserDialog.this, message, Translation.get("gb.error"), | |||
JOptionPane.ERROR_MESSAGE); | |||
} | |||
public void setUsers(List<UserModel> users) { | |||
usernames.clear(); | |||
for (UserModel user : users) { | |||
usernames.add(user.username.toLowerCase()); | |||
} | |||
} | |||
public void setRepositories(List<RepositoryModel> repositories, List<String> selected) { | |||
List<String> restricted = new ArrayList<String>(); | |||
for (RepositoryModel repo : repositories) { |
@@ -517,9 +517,17 @@ public class GitblitPanel extends JPanel implements CloseTabListener { | |||
* | |||
*/ | |||
protected void createRepository() { | |||
EditRepositoryDialog dialog = new EditRepositoryDialog(allUsers); | |||
List<String> usernames = new ArrayList<String>(); | |||
for (UserModel user : this.allUsers) { | |||
usernames.add(user.username); | |||
} | |||
Collections.sort(usernames); | |||
EditRepositoryDialog dialog = new EditRepositoryDialog(); | |||
dialog.setUsers(null, usernames, null); | |||
dialog.setRepositories(allRepositories); | |||
dialog.setVisible(true); | |||
final RepositoryModel newRepository = dialog.getRepository(); | |||
final List<String> permittedUsers = dialog.getPermittedUsers(); | |||
if (newRepository == null) { | |||
return; | |||
} | |||
@@ -529,7 +537,14 @@ public class GitblitPanel extends JPanel implements CloseTabListener { | |||
@Override | |||
protected Boolean doInBackground() throws IOException { | |||
return RpcUtils.createRepository(newRepository, url, account, password); | |||
boolean success = true; | |||
success &= RpcUtils.createRepository(newRepository, url, account, password); | |||
if (permittedUsers.size() > 0) { | |||
// if new repository has named members, set them | |||
success &= RpcUtils.setRepositoryMembers(newRepository, permittedUsers, url, | |||
account, password); | |||
} | |||
return success; | |||
} | |||
@Override | |||
@@ -538,6 +553,9 @@ public class GitblitPanel extends JPanel implements CloseTabListener { | |||
boolean success = get(); | |||
if (success) { | |||
refreshRepositoriesTable(); | |||
if (permittedUsers.size() > 0) { | |||
refreshUsersTable(); | |||
} | |||
} else { | |||
String msg = MessageFormat.format( | |||
"Failed to execute request \"{0}\" for repository \"{1}\".", | |||
@@ -564,17 +582,22 @@ public class GitblitPanel extends JPanel implements CloseTabListener { | |||
* @param repository | |||
*/ | |||
protected void editRepository(final RepositoryModel repository) { | |||
EditRepositoryDialog dialog = new EditRepositoryDialog(repository, allUsers); | |||
EditRepositoryDialog dialog = new EditRepositoryDialog(repository); | |||
List<String> members = new ArrayList<String>(); | |||
List<String> usernames = new ArrayList<String>(); | |||
for (UserModel user : this.allUsers) { | |||
usernames.add(user.username); | |||
if (user.repositories.contains(repository.name)) { | |||
members.add(user.username); | |||
} | |||
} | |||
Collections.sort(usernames); | |||
dialog.setUsers(usernames, null); | |||
dialog.setUsers(repository.owner, usernames, members); | |||
dialog.setFederationSets(settings.getStrings(Keys.federation.sets), | |||
repository.federationSets); | |||
dialog.setVisible(true); | |||
final RepositoryModel revisedRepository = dialog.getRepository(); | |||
final List<String> permittedUsers = dialog.getPermittedUsers(); | |||
if (revisedRepository == null) { | |||
return; | |||
} | |||
@@ -584,8 +607,13 @@ public class GitblitPanel extends JPanel implements CloseTabListener { | |||
@Override | |||
protected Boolean doInBackground() throws IOException { | |||
return RpcUtils.updateRepository(repository.name, revisedRepository, url, account, | |||
boolean success = true; | |||
success &= RpcUtils.updateRepository(repository.name, revisedRepository, url, | |||
account, password); | |||
// always set the repository members | |||
success &= RpcUtils.setRepositoryMembers(repository, permittedUsers, url, account, | |||
password); | |||
return success; | |||
} | |||
@Override | |||
@@ -594,6 +622,7 @@ public class GitblitPanel extends JPanel implements CloseTabListener { | |||
boolean success = get(); | |||
if (success) { | |||
refreshRepositoriesTable(); | |||
refreshUsersTable(); | |||
} else { | |||
String msg = MessageFormat.format( | |||
"Failed to execute request \"{0}\" for repository \"{1}\".", | |||
@@ -666,6 +695,7 @@ public class GitblitPanel extends JPanel implements CloseTabListener { | |||
*/ | |||
protected void createUser() { | |||
EditUserDialog dialog = new EditUserDialog(settings); | |||
dialog.setUsers(allUsers); | |||
dialog.setRepositories(allRepositories, null); | |||
dialog.setVisible(true); | |||
final UserModel newUser = dialog.getUser(); |
@@ -147,6 +147,12 @@ public class EditRepositoryPage extends RootSubPage { | |||
return; | |||
} | |||
// confirm federation strategy selection | |||
if (repositoryModel.federationStrategy == null) { | |||
error("Please select federation strategy!"); | |||
return; | |||
} | |||
// save federation set preferences | |||
if (repositoryModel.federationStrategy.exceeds(FederationStrategy.EXCLUDE)) { | |||
repositoryModel.federationSets.clear(); |