James Moger
2014-03-27 8ec06317276abd624630c37675d8d563a1fcb754
src/main/java/com/gitblit/transport/ssh/gitblit/UsersDispatcher.java
@@ -22,11 +22,13 @@
import org.kohsuke.args4j.Option;
import com.gitblit.Constants.AccessPermission;
import com.gitblit.GitBlitException;
import com.gitblit.Keys;
import com.gitblit.manager.IGitblit;
import com.gitblit.models.RegistrantAccessPermission;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.TeamModel;
import com.gitblit.models.UserModel;
import com.gitblit.transport.ssh.SshKey;
import com.gitblit.transport.ssh.commands.CommandMetaData;
import com.gitblit.transport.ssh.commands.DispatchCommand;
import com.gitblit.transport.ssh.commands.ListFilterCommand;
@@ -46,12 +48,13 @@
   protected void setup(UserModel user) {
      // primary user commands
      register(user, NewUser.class);
      register(user, RenameUser.class);
      register(user, RemoveUser.class);
      register(user, ShowUser.class);
      register(user, ListUsers.class);
      // user-specific commands
      register(user, SetName.class);
      register(user, SetField.class);
      register(user, Permissions.class);
      register(user, DisableUser.class);
      register(user, EnableUser.class);
@@ -113,32 +116,175 @@
         user.disabled = disabled;
         IGitblit gitblit = getContext().getGitblit();
         if (gitblit.updateUserModel(username, user)) {
         try {
            gitblit.addUser(user);
            stdout.println(String.format("%s created.", username));
         } else {
            throw new UnloggedFailure(1, String.format("Failed to create %s!", username));
         } catch (GitBlitException e) {
            log.error("Failed to add " + username, e);
            throw new UnloggedFailure(1, e.getMessage());
         }
      }
   }
   @CommandMetaData(name = "set-name", description = "Set the display name of an account")
   @UsageExample(syntax = "${cmd} john John Smith", description = "The display name to \"John Smith\" for john's account")
   public static class SetName extends UserCommand {
   @CommandMetaData(name = "rename", aliases = { "mv" }, description = "Rename an account")
   @UsageExample(syntax = "${cmd} john frank", description = "Rename the account from john to frank")
   public static class RenameUser extends UserCommand {
      @Argument(index = 1, required = true, metaVar = "NEWNAME", usage = "the new account name")
      protected String newUserName;
      @Argument(index = 1, multiValued = true, required = true, metaVar = "NAME", usage = "display name")
      protected List<String> displayName = new ArrayList<String>();
            @Override
      public void run() throws UnloggedFailure {
         UserModel user = getUser(true);
         IGitblit gitblit = getContext().getGitblit();
         if (null != gitblit.getTeamModel(newUserName)) {
            throw new UnloggedFailure(1, String.format("Team %s already exists!", newUserName));
         }
         // set the new name
         user.username = newUserName;
         try {
            gitblit.reviseUser(username, user);
            stdout.println(String.format("Renamed user %s to %s.", username, newUserName));
         } catch (GitBlitException e) {
            String msg = String.format("Failed to rename user from %s to %s", username, newUserName);
            log.error(msg, e);
            throw new UnloggedFailure(1, msg);
         }
      }
   }
   @CommandMetaData(name = "set", description = "Set the specified field of an account")
   @UsageExample(syntax = "${cmd} john name John Smith", description = "Set the display name to \"John Smith\" for john's account")
   public static class SetField extends UserCommand {
      @Argument(index = 1, required = true, metaVar = "FIELD", usage = "the field to update")
      protected String fieldName;
      @Argument(index = 2, required = true, metaVar = "VALUE", usage = "the new value")
      protected List<String> fieldValues = new ArrayList<String>();
      protected enum Field {
         name, displayName, email, password, canAdmin, canFork, canCreate;
         static Field fromString(String name) {
            for (Field field : values()) {
               if (field.name().equalsIgnoreCase(name)) {
                  return field;
               }
            }
            return null;
         }
      }
      @Override
      protected String getUsageText() {
         String fields = Joiner.on(", ").join(Field.values());
         StringBuilder sb = new StringBuilder();
         sb.append("Valid fields are:\n   ").append(fields);
         return sb.toString();
      }
      @Override
      public void run() throws UnloggedFailure {
         UserModel user = getUser(true);
         IGitblit gitblit = getContext().getGitblit();
         user.displayName = Joiner.on(" ").join(displayName);
         if (gitblit.updateUserModel(username, user)) {
            stdout.println(String.format("Set the display name of %s to \"%s\".", username, user.displayName));
         } else {
            throw new UnloggedFailure(1, String.format("Failed to set the display name of %s!", username));
         Field field = Field.fromString(fieldName);
         if (field == null) {
            throw new UnloggedFailure(1, String.format("Unknown field %s", fieldName));
         }
         String value = Joiner.on(" ").join(fieldValues).trim();
         IGitblit gitblit = getContext().getGitblit();
         boolean editCredentials = gitblit.supportsCredentialChanges(user);
         boolean editDisplayName = gitblit.supportsDisplayNameChanges(user);
         boolean editEmailAddress = gitblit.supportsEmailAddressChanges(user);
         String m = String.format("Can not edit %s for %s (%s)", field, user.username, user.accountType);
         switch(field) {
         case name:
         case displayName:
            if (!editDisplayName) {
               throw new UnloggedFailure(1, m);
            }
            user.displayName = value;
            break;
         case email:
            if (!editEmailAddress) {
               throw new UnloggedFailure(1, m);
            }
            user.emailAddress = value;
            break;
         case password:
            if (!editCredentials) {
               throw new UnloggedFailure(1, m);
            }
            int minLength = gitblit.getSettings().getInteger(Keys.realm.minPasswordLength, 5);
            if (minLength < 4) {
               minLength = 4;
            }
            if (value.trim().length() < minLength) {
               throw new UnloggedFailure(1,  "Password is too short.");
            }
            // Optionally store the password MD5 digest.
            String type = gitblit.getSettings().getString(Keys.realm.passwordStorage, "md5");
            if (type.equalsIgnoreCase("md5")) {
               // store MD5 digest of password
               user.password = StringUtils.MD5_TYPE + StringUtils.getMD5(value);
            } else if (type.equalsIgnoreCase("combined-md5")) {
               // store MD5 digest of username+password
               user.password = StringUtils.COMBINED_MD5_TYPE + StringUtils.getMD5(username + value);
            } else {
               user.password = value;
            }
            // reset the cookie
            user.cookie = StringUtils.getSHA1(user.username + value);
            break;
         case canAdmin:
            user.canAdmin = toBool(value);
            break;
         case canFork:
            user.canFork = toBool(value);
            break;
         case canCreate:
            user.canCreate = toBool(value);
            break;
         default:
            throw new UnloggedFailure(1,  String.format("Field %s was not properly handled by the set command.", fieldName));
         }
         try {
            gitblit.reviseUser(username, user);
            stdout.println(String.format("Set %s.%s = %s", username, fieldName, value));
         } catch (GitBlitException e) {
            String msg = String.format("Failed to set %s.%s = %s", username, fieldName, value);
            log.error(msg, e);
            throw new UnloggedFailure(1, msg);
         }
      }
      protected boolean toBool(String value) throws UnloggedFailure {
         String v = value.toLowerCase();
         if (v.equals("t")
               || v.equals("true")
               || v.equals("yes")
               || v.equals("on")
               || v.equals("y")
               || v.equals("1")) {
            return true;
         } else if (v.equals("f")
               || v.equals("false")
               || v.equals("no")
               || v.equals("off")
               || v.equals("n")
               || v.equals("0")) {
            return false;
         }
         throw new UnloggedFailure(1,  String.format("Invalid boolean value %s", value));
      }
   }
@@ -272,28 +418,41 @@
         UserModel u = getUser(true);
         // fields
         String [] fheaders = new String [] { "Field", "Value" };
         Object [][] fdata = new Object[5][];
         fdata[0] = new Object [] { "Email", u.emailAddress };
         fdata[1] = new Object [] { "Type", u.accountType };
         fdata[2] = new Object [] { "Can Admin", u.canAdmin() ? "Y":"" };
         fdata[3] = new Object [] { "Can Fork", u.canFork() ? "Y":"" };
         fdata[4] = new Object [] { "Can Create", u.canCreate() ? "Y":"" };
         String fields = FlipTable.of(fheaders, fdata, Borders.COLS);
         StringBuilder fb = new StringBuilder();
         fb.append("Email      : ").append(u.emailAddress == null ? "": u.emailAddress).append('\n');
         fb.append("Type       : ").append(u.accountType).append('\n');
         fb.append("Can Admin  : ").append(u.canAdmin() ? "Y":"").append('\n');
         fb.append("Can Fork   : ").append(u.canFork() ? "Y":"").append('\n');
         fb.append("Can Create : ").append(u.canCreate() ? "Y":"").append('\n');
         String fields = fb.toString();
         // teams
         String teams;
         if (u.teams.size() == 0) {
            teams = FlipTable.EMPTY;
         } else {
            String [] theaders = new String [] { "Team", "Type" };
            Object [][] tdata = new Object[u.teams.size()][];
            teams = Joiner.on(", ").join(u.teams);
         }
         // owned repositories
         String ownedTable;
         List<RepositoryModel> owned = new ArrayList<RepositoryModel>();
         for (RepositoryModel repository : getContext().getGitblit().getRepositoryModels(u)) {
            if (repository.isOwner(u.username)) {
               owned.add(repository);
            }
         }
         if (owned.isEmpty()) {
            ownedTable = FlipTable.EMPTY;
         } else {
            String [] theaders = new String [] { "Repository", "Description" };
            Object [][] tdata = new Object[owned.size()][];
            int i = 0;
            for (TeamModel t : u.teams) {
               tdata[i] = new Object [] { t.name, t.accountType };
            for (RepositoryModel r : owned) {
               tdata[i] = new Object [] { r.name, r.description };
               i++;
            }
            teams = FlipTable.of(theaders, tdata, Borders.COLS);
            ownedTable = FlipTable.of(theaders, tdata, Borders.COLS);
         }
         // permissions
@@ -311,25 +470,47 @@
            permissions = FlipTable.of(pheaders, pdata, Borders.COLS);
         }
         // keys
         String keyTable;
         List<SshKey> keys = getContext().getGitblit().getPublicKeyManager().getKeys(u.username);
         if (ArrayUtils.isEmpty(keys)) {
            keyTable = FlipTable.EMPTY;
         } else {
            String[] headers = { "#", "Fingerprint", "Comment", "Type" };
            int len = keys == null ? 0 : keys.size();
            Object[][] data = new Object[len][];
            for (int i = 0; i < len; i++) {
               // show 1-based index numbers with the fingerprint
               // this is useful for comparing with "ssh-add -l"
               SshKey k = keys.get(i);
               data[i] = new Object[] { (i + 1), k.getFingerprint(), k.getComment(), k.getAlgorithm() };
            }
            keyTable = FlipTable.of(headers, data, Borders.COLS);
         }
         // assemble user table
         String userTitle = u.getDisplayName() + (u.username.equals(u.getDisplayName()) ? "" : (" (" + u.username + ")"));
         if (u.disabled) {
            userTitle += "  [DISABLED]";
         }
         String [] headers = new String[] { userTitle };
         String[][] data = new String[6][];
         String[][] data = new String[8][];
         data[0] = new String [] { "FIELDS" };
         data[1] = new String [] { fields };
         data[2] = new String [] { "TEAMS" };
         data[3] = new String [] { teams };
         data[4] = new String [] { "OWNED REPOSITORIES" };
         data[5] = new String [] { ownedTable };
         data[4] = new String [] { "PERMISSIONS" };
         data[5] = new String [] { permissions };
         data[6] = new String [] { "SSH PUBLIC KEYS" };
         data[7] = new String [] { keyTable };
         stdout.println(FlipTable.of(headers, data));
      }
   }
   @CommandMetaData(name = "list", aliases= { "ls" }, description = "List accounts")
   @UsageExamples( examples = {
   @UsageExamples(examples = {
      @UsageExample(syntax = "${cmd}", description = "List accounts as a table"),
      @UsageExample(syntax = "${cmd} j.*", description = "List all accounts that start with 'j'"),
   })
@@ -351,10 +532,10 @@
      protected void asTable(List<UserModel> list) {
         String[] headers;
         if (verbose) {
            String[] h = { "Name", "Display name", "Type", "Email", "Create?", "Fork?"};
            String[] h = { "Name", "Display name", "Email", "Type", "Teams", "Create?", "Fork?"};
            headers = h;
         } else {
            String[] h = { "Name", "Display name", "Type", "Email"};
            String[] h = { "Name", "Display name", "Email", "Type"};
            headers = h;
         }
@@ -364,13 +545,20 @@
            String name = (u.disabled ? "-" : ((u.canAdmin() ? "*" : " "))) + u.username;
            if (verbose) {
               data[i] = new Object[] { name, u.displayName, u.accountType,
               data[i] = new Object[] {
                     name,
                     u.displayName,
                     u.emailAddress,
                     u.accountType + (u.canAdmin() ? ",admin":""),
                     u.teams.isEmpty() ? "" : u.teams.size(),
                     (u.canAdmin() || u.canCreate()) ? "Y":"",
                     (u.canAdmin() || u.canFork()) ? "Y" : ""};
            } else {
               data[i] = new Object[] { name, u.displayName, u.accountType,
                     u.emailAddress };
               data[i] = new Object[] {
                     name,
                     u.displayName,
                     u.emailAddress,
                     u.accountType + (u.canAdmin() ? ",admin":"")};
            }
         }
         stdout.print(FlipTable.of(headers, data, Borders.BODY_HCOLS));
@@ -382,10 +570,12 @@
      protected void asTabbed(List<UserModel> users) {
         if (verbose) {
            for (UserModel u : users) {
               outTabbed(u.disabled ? "-" : ((u.canAdmin() ? "*" : " ")) + u.username,
               outTabbed(
                     u.disabled ? "-" : ((u.canAdmin() ? "*" : " ")) + u.username,
                     u.getDisplayName(),
                     u.accountType,
                     u.emailAddress == null ? "" : u.emailAddress,
                     u.accountType + (u.canAdmin() ? ",admin":""),
                     u.teams.isEmpty() ? "" : u.teams.size(),
                     (u.canAdmin() || u.canCreate()) ? "Y":"",
                     (u.canAdmin() || u.canFork()) ? "Y" : "");
            }