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