James Moger
2014-05-30 5779988cf3a1d737322b2b6a1d568da8713509e7
Use RepositoryNamePanel in EditRepositoryPage, rename AccessPolicyPanel
2 files renamed
7 files modified
276 ■■■■ changed files
src/main/java/com/gitblit/wicket/GitBlitWebApp.properties 22 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html 4 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java 63 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html 5 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java 9 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html 7 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java 70 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html 7 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java 89 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
@@ -686,16 +686,18 @@
gb.plugins = plugins
gb.extensions = extensions
gb.pleaseSelectProject = Please select the project!
gb.anonymousPush = Anonymous Pushes
gb.anonymousPushDescription = Anyone can see, clone, and push to this repository.
gb.pushRestrictedAuthenticated = Restrict Pushes (Authenticated)
gb.pushRestrictedAuthenticatedDescription = Anyone can see and clone this repository. All authenticated users can push.
gb.pushRestrictedNamed = Restrict Pushes (Named)
gb.pushRestrictedNamedDescription = Anyone can see and clone this repository. You choose who can push.
gb.cloneRestricted = Restrict Clones & Pushes
gb.cloneRestrictedDescription = Anyone can see this repository. You choose who can clone and push.
gb.private = Private
gb.privateRepoDescription = You choose who can see, clone, and push to this repository.
gb.accessPolicy = Access Policy
gb.accessPolicyDescription = Choose an access policy to control visibility, cloning, and pushing to this repository.
gb.anonymousPolicy = Anonymous View, Clone, & Push
gb.anonymousPolicyDescription = Anyone can see, clone, and push to this repository.
gb.authenticatedPushPolicy = Restrict Push (Authenticated)
gb.authenticatedPushPolicyDescription = Anyone can see and clone this repository. All authenticated users have RW+ push permission.
gb.namedPushPolicy = Restrict Push (Named)
gb.namedPushPolicyDescription = Anyone can see and clone this repository. You choose who can push.
gb.clonePolicy = Restrict Clone & Push
gb.clonePolicyDescription = Anyone can see this repository. You choose who can clone and push.
gb.viewPolicy  = Restrict View, Clone, & Push
gb.viewPolicyDescription = You choose who can see, clone, and push to this repository.
gb.initialCommit = Initial Commit
gb.initialCommitDescription = This will allow you to <code>git clone</code> this repository immediately. Skip this step if you have already run <code>git init</code> locally.
gb.initWithReadme = Include a README
src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html
@@ -24,10 +24,10 @@
        <!-- general tab -->
        <div class="tab-pane active" id="general">
        <div wicket:id="namePanel"></div>
        <table class="plain">
            <tbody class="settings">
                <tr><th><wicket:message key="gb.name"></wicket:message></th><td class="edit"><input class="span4" type="text" wicket:id="name" id="name" size="40" tabindex="1" /> &nbsp;<span class="help-inline"><wicket:message key="gb.nameDescription"></wicket:message></span></td></tr>
                <tr><th><wicket:message key="gb.description"></wicket:message></th><td class="edit"><input class="span4" type="text" wicket:id="description" size="40" tabindex="2" /></td></tr>
                <tr><th colspan="2"><hr/></th></tr>
                <tr><th><wicket:message key="gb.origin"></wicket:message></th><td class="edit"><input class="span5" type="text" wicket:id="origin" size="80" tabindex="3" /></td></tr>
                <tr><th><wicket:message key="gb.headRef"></wicket:message></th><td class="edit"><select class="span3" wicket:id="HEAD" tabindex="4" /> &nbsp;<span class="help-inline"><wicket:message key="gb.headRefDescription"></wicket:message></span></td></tr>
src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java
@@ -72,10 +72,13 @@
import com.gitblit.wicket.panels.BasePanel.JavascriptEventConfirmation;
import com.gitblit.wicket.panels.BulletListPanel;
import com.gitblit.wicket.panels.RegistrantPermissionsPanel;
import com.gitblit.wicket.panels.RepositoryNamePanel;
public class EditRepositoryPage extends RootSubPage {
    private final boolean isCreate;
    RepositoryNamePanel namePanel;
    private boolean isAdmin;
@@ -263,59 +266,8 @@
            @Override
            protected void onSubmit() {
                try {
                    // confirm a repository name was entered
                    if (repositoryModel.name == null && StringUtils.isEmpty(repositoryModel.name)) {
                        error(getString("gb.pleaseSetRepositoryName"));
                    if (!namePanel.updateModel(repositoryModel)) {
                        return;
                    }
                    // ensure name is trimmed
                    repositoryModel.name = repositoryModel.name.trim();
                    // automatically convert backslashes to forward slashes
                    repositoryModel.name = repositoryModel.name.replace('\\', '/');
                    // Automatically replace // with /
                    repositoryModel.name = repositoryModel.name.replace("//", "/");
                    // prohibit folder paths
                    if (repositoryModel.name.startsWith("/")) {
                        error(getString("gb.illegalLeadingSlash"));
                        return;
                    }
                    if (repositoryModel.name.startsWith("../")) {
                        error(getString("gb.illegalRelativeSlash"));
                        return;
                    }
                    if (repositoryModel.name.contains("/../")) {
                        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(getString("gb.illegalCharacterRepositoryName"),
                                c));
                        return;
                    }
                    if (user.canCreate() && !user.canAdmin() && allowEditName) {
                        // 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
@@ -426,6 +378,7 @@
                    }
                } catch (GitBlitException e) {
                    error(e.getMessage());
                    namePanel.resetModel(repositoryModel);
                    return;
                }
                setRedirect(false);
@@ -437,8 +390,10 @@
        form.add(new SimpleAttributeModifier("autocomplete", "off"));
        // field names reflective match RepositoryModel fields
        form.add(new TextField<String>("name").setEnabled(allowEditName));
        form.add(new TextField<String>("description"));
        namePanel = new RepositoryNamePanel("namePanel", repositoryModel);
        namePanel.setEditable(allowEditName);
        form.add(namePanel);
        form.add(ownersPalette);
        form.add(new CheckBox("allowForks").setEnabled(app().settings().getBoolean(Keys.web.allowForking, true)));
        DropDownChoice<AccessRestrictionType> accessRestriction = new DropDownChoice<AccessRestrictionType>("accessRestriction",
src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html
@@ -12,11 +12,6 @@
        <div wicket:id="namePanel"></div>
        
        <div>
            <b><wicket:message key="gb.description"></wicket:message></b><br/>
            <input class="span6" type="text" wicket:id="description" />
        </div>
        <hr/>
        
        <div wicket:id="permissionPanel"></div>
src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java
@@ -29,7 +29,6 @@
import org.apache.wicket.markup.html.form.CheckBox;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
@@ -61,7 +60,7 @@
import com.gitblit.wicket.GitBlitWebSession;
import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.panels.RepositoryNamePanel;
import com.gitblit.wicket.panels.RepositoryPermissionPanel;
import com.gitblit.wicket.panels.AccessPolicyPanel;
public class NewRepositoryPage extends RootSubPage {
@@ -70,7 +69,7 @@
    private Model<String> gitignoreModel;
    private IModel<Boolean> addGitflowModel;
    private IModel<Boolean> addGitignoreModel;
    private RepositoryPermissionPanel permissionPanel;
    private AccessPolicyPanel permissionPanel;
    private RepositoryNamePanel namePanel;
    public NewRepositoryPage() {
@@ -159,8 +158,6 @@
        namePanel = new RepositoryNamePanel("namePanel", repositoryModel);
        form.add(namePanel);
        form.add(new TextField<String>("description"));
        // prepare the default access controls
        AccessRestrictionType defaultRestriction = AccessRestrictionType.fromName(
                app().settings().getString(Keys.git.defaultAccessRestriction, AccessRestrictionType.PUSH.name()));
@@ -177,7 +174,7 @@
        repositoryModel.authorizationControl = defaultControl;
        repositoryModel.accessRestriction = defaultRestriction;
        permissionPanel = new RepositoryPermissionPanel("permissionPanel", repositoryModel);
        permissionPanel = new AccessPolicyPanel("permissionPanel", repositoryModel);
        form.add(permissionPanel);
        //
src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html
File was renamed from src/main/java/com/gitblit/wicket/panels/RepositoryPermissionPanel.html
@@ -7,8 +7,11 @@
<body>
<wicket:panel>
    <span wicket:id="permissionsGroup">
            <div wicket:id="permissions">
    <h4><wicket:message key="gb.accessPolicy"></wicket:message></h4>
    <p><wicket:message key="gb.accessPolicyDescription"></wicket:message></p>
    <span wicket:id="policiesGroup">
            <div wicket:id="policies">
                <div style="display: inline-block;vertical-align: top;">
                    <input type="radio" wicket:id="radio" />
                    <img wicket:id="image"></img> 
src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java
File was renamed from src/main/java/com/gitblit/wicket/panels/RepositoryPermissionPanel.java
@@ -38,15 +38,15 @@
 * @author James Moger
 *
 */
public class RepositoryPermissionPanel extends BasePanel {
public class AccessPolicyPanel extends BasePanel {
    private static final long serialVersionUID = 1L;
    private final RepositoryModel repository;
    private RadioGroup<Permission> permissionGroup;
    private RadioGroup<AccessPolicy> policiesGroup;
    public RepositoryPermissionPanel(String wicketId, RepositoryModel repository) {
    public AccessPolicyPanel(String wicketId, RepositoryModel repository) {
        super(wicketId);
        this.repository = repository;
    }
@@ -55,44 +55,44 @@
    protected void onInitialize() {
        super.onInitialize();
        Permission anonymousPermission = new Permission(getString("gb.anonymousPush"),
                getString("gb.anonymousPushDescription"),
        AccessPolicy anonymousPolicy = new AccessPolicy(getString("gb.anonymousPolicy"),
                getString("gb.anonymousPolicyDescription"),
                "blank.png",
                AuthorizationControl.AUTHENTICATED,
                AccessRestrictionType.NONE);
        Permission authenticatedPermission = new Permission(getString("gb.pushRestrictedAuthenticated"),
                getString("gb.pushRestrictedAuthenticatedDescription"),
        AccessPolicy authenticatedPushPolicy = new AccessPolicy(getString("gb.authenticatedPushPolicy"),
                getString("gb.authenticatedPushPolicyDescription"),
                "lock_go_16x16.png",
                AuthorizationControl.AUTHENTICATED,
                AccessRestrictionType.PUSH);
        Permission publicPermission = new Permission(getString("gb.pushRestrictedNamed"),
                getString("gb.pushRestrictedNamedDescription"),
        AccessPolicy namedPushPolicy = new AccessPolicy(getString("gb.namedPushPolicy"),
                getString("gb.namedPushPolicyDescription"),
                "lock_go_16x16.png",
                AuthorizationControl.NAMED,
                AccessRestrictionType.PUSH);
        Permission protectedPermission = new Permission(getString("gb.cloneRestricted"),
                getString("gb.cloneRestrictedDescription"),
        AccessPolicy clonePolicy = new AccessPolicy(getString("gb.clonePolicy"),
                getString("gb.clonePolicyDescription"),
                "lock_pull_16x16.png",
                AuthorizationControl.NAMED,
                AccessRestrictionType.CLONE);
        Permission privatePermission = new Permission(getString("gb.private"),
                getString("gb.privateRepoDescription"),
        AccessPolicy viewPolicy = new AccessPolicy(getString("gb.viewPolicy"),
                getString("gb.viewPolicyDescription"),
                "shield_16x16.png",
                AuthorizationControl.NAMED,
                AccessRestrictionType.VIEW);
        List<Permission> permissions = new ArrayList<Permission>();
        List<AccessPolicy> policies = new ArrayList<AccessPolicy>();
        if (app().settings().getBoolean(Keys.git.allowAnonymousPushes, false)) {
            permissions.add(anonymousPermission);
            policies.add(anonymousPolicy);
        }
        permissions.add(authenticatedPermission);
        permissions.add(publicPermission);
        permissions.add(protectedPermission);
        permissions.add(privatePermission);
        policies.add(authenticatedPushPolicy);
        policies.add(namedPushPolicy);
        policies.add(clonePolicy);
        policies.add(viewPolicy);
        AccessRestrictionType defaultRestriction = repository.accessRestriction;
        if (defaultRestriction == null) {
@@ -106,38 +106,38 @@
                    AuthorizationControl.NAMED.name()));
        }
        Permission defaultPermission = publicPermission;
        for (Permission permission : permissions) {
            if (permission.type == defaultRestriction && permission.control == defaultControl) {
                defaultPermission = permission;
        AccessPolicy defaultPolicy = namedPushPolicy;
        for (AccessPolicy policy : policies) {
            if (policy.type == defaultRestriction && policy.control == defaultControl) {
                defaultPolicy = policy;
            }
        }
        permissionGroup = new RadioGroup<>("permissionsGroup", new Model<Permission>(defaultPermission));
        ListView<Permission> permissionsList = new ListView<Permission>("permissions", permissions) {
        policiesGroup = new RadioGroup<>("policiesGroup", new Model<AccessPolicy>(defaultPolicy));
        ListView<AccessPolicy> policiesList = new ListView<AccessPolicy>("policies", policies) {
            private static final long serialVersionUID = 1L;
            @Override
            protected void populateItem(ListItem<Permission> item) {
                Permission p = item.getModelObject();
                item.add(new Radio<Permission>("radio", item.getModel()));
            protected void populateItem(ListItem<AccessPolicy> item) {
                AccessPolicy p = item.getModelObject();
                item.add(new Radio<AccessPolicy>("radio", item.getModel()));
                item.add(WicketUtils.newImage("image",  p.image));
                item.add(new Label("name", p.name));
                item.add(new Label("description", p.description));
            }
        };
        permissionGroup.add(permissionsList);
        policiesGroup.add(policiesList);
        setOutputMarkupId(true);
        add(permissionGroup);
        add(policiesGroup);
    }
    public void updateModel(RepositoryModel repository) {
        Permission permission = permissionGroup.getModelObject();
        repository.authorizationControl = permission.control;
        repository.accessRestriction = permission.type;
        AccessPolicy policy = policiesGroup.getModelObject();
        repository.authorizationControl = policy.control;
        repository.accessRestriction = policy.type;
    }
    @Override
@@ -145,7 +145,7 @@
        return false;
    }
    private static class Permission implements Serializable {
    private static class AccessPolicy implements Serializable {
        private static final long serialVersionUID = 1L;
@@ -155,7 +155,7 @@
        final AuthorizationControl control;
        final AccessRestrictionType type;
        Permission(String name, String description, String img, AuthorizationControl control, AccessRestrictionType type) {
        AccessPolicy(String name, String description, String img, AuthorizationControl control, AccessRestrictionType type) {
            this.name = name;
            this.description = description;
            this.image = img;
src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html
@@ -11,16 +11,19 @@
        <tbody class="settings">
            <tr>
                <th><wicket:message key="gb.project"></wicket:message></th>
                <td></td>
                <th><wicket:message key="gb.name"></wicket:message></th>
            </tr>
            <tr>
                <td><select class="span2" wicket:id="projectPath" /></td>
                <td style="font-size:24px;color:#ccc;">/</td>
                <td class="edit"><input class="span3" type="text" wicket:id="name" id="name" /> &nbsp;<span class="help-inline"><wicket:message key="gb.nameDescription"></wicket:message></span></td>
            </tr>
        </tbody>
    </table>
    <div>
        <b><wicket:message key="gb.description"></wicket:message></b><br/>
        <input class="span5" type="text" wicket:id="description" />
    </div>
            
</wicket:panel>
</body>
src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java
@@ -17,18 +17,20 @@
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.TextField;
import com.gitblit.models.ProjectModel;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.UserModel;
import com.gitblit.utils.StringUtils;
import com.gitblit.wicket.GitBlitWebSession;
/**
 * A radio group panel of the 5 available authorization/access restriction combinations.
 * A panel for naming a repository, specifying it's project, and entering a description.
 *
 * @author James Moger
 *
@@ -37,44 +39,79 @@
    private static final long serialVersionUID = 1L;
    private final RepositoryModel repository;
    private String fullName;
    private DropDownChoice<String> projectChoice;
    private TextField<String> nameField;
    public RepositoryNamePanel(String wicketId, RepositoryModel repository) {
        super(wicketId);
        this.repository = repository;
    }
    @Override
    protected void onInitialize() {
        super.onInitialize();
        GitBlitWebSession session = GitBlitWebSession.get();
        UserModel user = session.getUser();
        // build project list for repository destination
        // build project set for repository destination
        String defaultProject = null;
        List<String> projects = new ArrayList<String>();
        Set<String> projectNames = new TreeSet<String>();
        if (user.canAdmin()) {
            projects.add("/");
            defaultProject = "/";
        }
        if (user.canCreate()) {
            String p =  user.getPersonalPath() + "/";
            projects.add(p);
            if (defaultProject == null) {
                // only prefer personal namespace if default is not already set
                defaultProject = p;
        // add the registered/known projects
        for (ProjectModel project : app().projects().getProjectModels(user, false)) {
            // TODO issue-351: user.canAdmin(project)
            if (user.canAdmin()) {
                if (project.isRoot) {
                    projectNames.add("/");
                } else {
                    projectNames.add(project.name + "/");
                }
            }
        }
        repository.projectPath = defaultProject;
        // add the user's personal project namespace
        if (user.canAdmin() || user.canCreate()) {
            projectNames.add(user.getPersonalPath() + "/");
        }
        add(new DropDownChoice<String>("projectPath", projects));
        add(new TextField<String>("name"));
        if (!StringUtils.isEmpty(repository.name)) {
            // editing a repository name
            // set the defaultProject to the current repository project
            defaultProject = repository.projectPath;
            if (StringUtils.isEmpty(defaultProject)) {
                defaultProject = "/";
            } else {
                defaultProject += "/";
            }
            projectNames.add(defaultProject);
        }
        // if default project is not already set, set preference based on the user permissions
        if (defaultProject == null) {
            if (user.canAdmin()) {
                defaultProject = "/";
            } else if (user.canCreate()) {
                defaultProject = user.getPersonalPath() + "/";
            }
        }
        // update the model which is reflectively mapped to the Wicket fields by name
        repository.projectPath = defaultProject;
        if (repository.projectPath.length() > 1 && !StringUtils.isEmpty(repository.name)) {
            repository.name = repository.name.substring(repository.projectPath.length());
        }
        projectChoice = new DropDownChoice<String>("projectPath", new ArrayList<String>(projectNames));
        nameField = new TextField<String>("name");
        // only enable project selection if we actually have multiple choices
        add(projectChoice.setEnabled(projectNames.size() > 1));
        add(nameField);
        add(new TextField<String>("description"));
    }
    public void setEditable(boolean editable) {
        // only enable project selection if we actually have multiple choices
        projectChoice.setEnabled(projectChoice.getChoices().size() > 1 && editable);
        nameField.setEnabled(editable);
    }
    public boolean updateModel(RepositoryModel repositoryModel) {