James Moger
2013-05-30 79d3240ea489067f3eb1af5e535b3687c507a249
Added simple star/unstar function
2 files added
8 files modified
252 ■■■■■ changed files
releases.moxie 1 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/ConfigUserService.java 19 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/GitBlit.java 24 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/IStoredSettings.java 2 ●●● patch | view | raw | blame | history
src/main/java/com/gitblit/models/UserModel.java 8 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/models/UserPreferences.java 91 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/models/UserRepositoryPreferences.java 40 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/wicket/GitBlitWebApp.properties 2 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/wicket/pages/RepositoryPage.html 9 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/wicket/pages/RepositoryPage.java 56 ●●●●● patch | view | raw | blame | history
releases.moxie
@@ -39,6 +39,7 @@
     - Updated Japanese translation
     
    additions: 
     - Added simple star/unstar function to flag or bookmark interesting repositories
     - Added a ui for the push log introduced in 1.2.1 (issue-177)
     - Added client application menus for Git, SourceTree, Tower, GitHub for Windows, GitHub for Mac, and SparkleShare
     - Added GO http/https connector thread pool size setting
src/main/java/com/gitblit/ConfigUserService.java
@@ -37,6 +37,7 @@
import com.gitblit.Constants.AccessPermission;
import com.gitblit.models.TeamModel;
import com.gitblit.models.UserModel;
import com.gitblit.models.UserRepositoryPreferences;
import com.gitblit.utils.ArrayUtils;
import com.gitblit.utils.DeepCopier;
import com.gitblit.utils.StringUtils;
@@ -88,6 +89,8 @@
    private static final String PRERECEIVE = "preReceiveScript";
    private static final String POSTRECEIVE = "postReceiveScript";
    private static final String STARRED = "starred";
    private final File realmFile;
@@ -879,6 +882,14 @@
                }
                config.setStringList(USER, model.username, REPOSITORY, permissions);
            }
            // user preferences
            if (model.getPreferences() != null) {
                List<String> starred =  model.getPreferences().getStarredRepositories();
                if (starred.size() > 0) {
                    config.setStringList(USER, model.username, STARRED, starred);
                }
            }
        }
        // write teams
@@ -1021,6 +1032,14 @@
                        }
                    }
                    // starred repositories
                    Set<String> starred = new HashSet<String>(Arrays.asList(config
                            .getStringList(USER, username, STARRED)));
                    for (String repository : starred) {
                        UserRepositoryPreferences prefs = user.getPreferences().getRepositoryPreferences(repository);
                        prefs.starred = true;
                    }
                    // update cache
                    users.put(user.username, user);
                    if (!StringUtils.isEmpty(user.cookie)) {
src/main/java/com/gitblit/GitBlit.java
@@ -353,7 +353,7 @@
     * Returns a list of space-separated strings from the specified key.
     * 
     * @see IStoredSettings.getStrings(String key)
     * @param name
     * @param n
     * @return list of strings
     */
    public static List<String> getStrings(String key) {
@@ -364,7 +364,7 @@
     * Returns a map of space-separated key-value pairs from the specified key.
     * 
     * @see IStoredSettings.getStrings(String key)
     * @param name
     * @param n
     * @return map of string, string
     */
    public static Map<String, String> getMap(String key) {
@@ -1571,6 +1571,22 @@
        return DeepCopier.copy(model);
    }
    
    /**
     * Returns the star count of the repository.
     *
     * @param repository
     * @return the star count
     */
    public long getStarCount(RepositoryModel repository) {
        long count = 0;
        for (UserModel user : getAllUsers()) {
            if (user.getPreferences().isStarredRepository(repository.name)) {
                count++;
            }
        }
        return count;
    }
    
    /**
     * Returns the map of project config.  This map is cached and reloaded if
@@ -1924,7 +1940,7 @@
    /**
     * Determines if this server has the requested repository.
     * 
     * @param name
     * @param n
     * @return true if the repository exists
     */
    public boolean hasRepository(String repositoryName) {
@@ -1934,7 +1950,7 @@
    /**
     * Determines if this server has the requested repository.
     * 
     * @param name
     * @param n
     * @param caseInsensitive
     * @return true if the repository exists
     */
src/main/java/com/gitblit/IStoredSettings.java
@@ -161,7 +161,7 @@
    
    /**
     * Returns an long filesize from a string value such as 50m or 50mb
     * @param name
     * @param n
     * @param defaultValue
     * @return a long filesize or defaultValue if the key does not exist or can
     *         not be parsed
src/main/java/com/gitblit/models/UserModel.java
@@ -76,16 +76,20 @@
    public boolean isAuthenticated;
    public AccountType accountType;
    
    public UserPreferences userPreferences;
    public UserModel(String username) {
        this.username = username;
        this.isAuthenticated = true;
        this.accountType = AccountType.LOCAL;
        this.userPreferences = new UserPreferences(this.username);
    }
    private UserModel() {
        this.username = "$anonymous";
        this.isAuthenticated = false;
        this.accountType = AccountType.LOCAL;
        this.userPreferences = new UserPreferences(this.username);
    }
    
    public boolean isLocalAccount() {
@@ -602,6 +606,10 @@
        return "~" + username;
    }
    
    public UserPreferences getPreferences() {
        return userPreferences;
    }
    @Override
    public int hashCode() {
        return username.hashCode();
src/main/java/com/gitblit/models/UserPreferences.java
New file
@@ -0,0 +1,91 @@
/*
 * Copyright 2013 gitblit.com.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gitblit.models;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import com.gitblit.utils.StringUtils;
/**
 * User preferences.
 *
 * @author James Moger
 *
 */
public class UserPreferences implements Serializable {
    private static final long serialVersionUID = 1L;
    public final String username;
    private final Map<String, UserRepositoryPreferences> repositoryPreferences = new TreeMap<String, UserRepositoryPreferences>();
    public UserPreferences(String username) {
        this.username = username;
    }
    public Locale getLocale() {
        if (StringUtils.isEmpty(locale)) {
            return null;
        }
        return new Locale(locale);
    }
    public UserRepositoryPreferences getRepositoryPreferences(String repositoryName) {
        String key = repositoryName.toLowerCase();
        if (!repositoryPreferences.containsKey(key)) {
            // default preferences
            UserRepositoryPreferences prefs = new UserRepositoryPreferences();
            prefs.username = username;
            prefs.repositoryName = repositoryName;
            repositoryPreferences.put(key, prefs);
        }
        return repositoryPreferences.get(key);
    }
    public void setRepositoryPreferences(UserRepositoryPreferences pref) {
        repositoryPreferences.put(pref.repositoryName.toLowerCase(), pref);
    }
    public boolean isStarredRepository(String repository) {
        if (repositoryPreferences == null) {
            return false;
        }
        String key = repository.toLowerCase();
        if (repositoryPreferences.containsKey(key)) {
            UserRepositoryPreferences pref = repositoryPreferences.get(key);
            return pref.starred;
        }
        return false;
    }
    public List<String> getStarredRepositories() {
        List<String> list = new ArrayList<String>();
        for (UserRepositoryPreferences prefs : repositoryPreferences.values()) {
            if (prefs.starred) {
                list.add(prefs.repositoryName);
            }
        }
        Collections.sort(list);
        return list;
    }
}
src/main/java/com/gitblit/models/UserRepositoryPreferences.java
New file
@@ -0,0 +1,40 @@
/*
 * Copyright 2013 gitblit.com.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gitblit.models;
import java.io.Serializable;
/**
 * User repository preferences.
 *
 * @author James Moger
 *
 */
public class UserRepositoryPreferences implements Serializable {
    private static final long serialVersionUID = 1L;
    public String username;
    public String repositoryName;
    public boolean starred;
    @Override
    public String toString() {
        return username + ":" + repositoryName;
    }
}
src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
@@ -472,3 +472,5 @@
gb.pushedNewBranch = pushed new branch
gb.deletedBranch = deleted branch
gb.rewind = REWIND
gb.star = star
gb.unstar = unstar
src/main/java/com/gitblit/wicket/pages/RepositoryPage.html
@@ -38,8 +38,9 @@
                    <div>
                        <div class="hidden-phone btn-group pull-right" style="margin-top:5px;">
                            <!-- future spot for other repo buttons -->
<!--                             <a class="btn"><i class="icon-star-empty" style="padding-right:3px;"></i>star</a> -->
<!--                             <a class="btn"><i class="icon-envelope" style="padding-right:3px;"></i>subscribe</a> -->
                            <a class="btn" wicket:id="starLink"></a>
                            <a class="btn" wicket:id="unstarLink"></a>
                            <a class="btn" wicket:id="myForkLink"><img style="border:0px;vertical-align:middle;" src="fork-black_16x16.png"></img> <wicket:message key="gb.myFork"></wicket:message></a>
                            <a class="btn" wicket:id="forkLink"><img style="border:0px;vertical-align:middle;" src="fork-black_16x16.png"></img> <wicket:message key="gb.fork"></wicket:message></a>
                        </div>
@@ -54,6 +55,10 @@
            <wicket:child />
        </div>
        
        <wicket:fragment wicket:id="toolbarLinkFragment">
            <i wicket:id="icon" style="padding-right:3px;"></i><span wicket:id="label"></span>
        </wicket:fragment>
        <wicket:fragment wicket:id="originFragment">
            <p class="originRepository"><wicket:message key="gb.forkedFrom">[forked from]</wicket:message> <span wicket:id="originRepository">[origin repository]</span></p>
        </wicket:fragment>
src/main/java/com/gitblit/wicket/pages/RepositoryPage.java
@@ -28,6 +28,7 @@
import org.apache.wicket.Component;
import org.apache.wicket.PageParameters;
import org.apache.wicket.behavior.SimpleAttributeModifier;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.TextField;
@@ -41,9 +42,12 @@
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gitblit.Constants;
import com.gitblit.GitBlit;
import com.gitblit.GitBlitException;
import com.gitblit.Keys;
import com.gitblit.PagesServlet;
import com.gitblit.SyndicationServlet;
@@ -52,7 +56,9 @@
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.SubmoduleModel;
import com.gitblit.models.UserModel;
import com.gitblit.models.UserRepositoryPreferences;
import com.gitblit.utils.ArrayUtils;
import com.gitblit.utils.DeepCopier;
import com.gitblit.utils.JGitUtils;
import com.gitblit.utils.PushLogUtils;
import com.gitblit.utils.StringUtils;
@@ -67,6 +73,10 @@
import com.gitblit.wicket.panels.RefsPanel;
public abstract class RepositoryPage extends RootPage {
    private final Logger logger = LoggerFactory.getLogger(getClass());
    private final String PARAM_STAR = "star";
    protected final String projectName;
    protected final String repositoryName;
@@ -117,6 +127,22 @@
                                branch.reference.getName());
                if (!canAccess) {
                    error(getString("gb.accessDenied"), true);
                }
            }
        }
        if (params.containsKey(PARAM_STAR)) {
            // set starred state
            boolean star = params.getBoolean(PARAM_STAR);
            UserModel user = GitBlitWebSession.get().getUser();
            if (user != null && user.isAuthenticated) {
                UserRepositoryPreferences prefs = user.getPreferences().getRepositoryPreferences(getRepositoryModel().name);
                prefs.starred = star;
                try {
                    GitBlit.self().updateUserModel(user.username, user, false);
                } catch (GitBlitException e) {
                    logger.error("Failed to update user " + user.username, e);
                    error(getString("gb.failedToUpdateUser"), false);
                }
            }
        }
@@ -260,6 +286,26 @@
            }
        }
        
        // (un)star link allows a user to star someone else's repository
        if (user.isAuthenticated && !model.isOwner(user.username) && !model.isUsersPersonalRepository(user.username)) {
            PageParameters starParams = DeepCopier.copy(getPageParameters());
            starParams.put(PARAM_STAR, !user.getPreferences().isStarredRepository(model.name));
            String toggleStarUrl = getRequestCycle().urlFor(getClass(), starParams).toString();
            if (user.getPreferences().isStarredRepository(model.name)) {
                // show unstar button
                add(new Label("starLink").setVisible(false));
                addToolbarButton("unstarLink", "icon-star-empty", getString("gb.unstar"), toggleStarUrl);
            } else {
                // show star button
                addToolbarButton("starLink", "icon-star", getString("gb.star"), toggleStarUrl);
                add(new Label("unstarLink").setVisible(false));
            }
        } else {
            // anonymous user or the repository owner is browsing the repository
            add(new Label("starLink").setVisible(false));
            add(new Label("unstarLink").setVisible(false));
        }
        // fork controls
        if (!allowForkControls() || user == null || !user.isAuthenticated) {
            // must be logged-in to fork, hide all fork controls
@@ -293,6 +339,16 @@
        super.setupPage(repositoryName, pageName);
    }
    protected void addToolbarButton(String wicketId, String iconClass, String label, String url) {
        Fragment button = new Fragment(wicketId, "toolbarLinkFragment", this);
        Label icon = new Label("icon");
        WicketUtils.setCssClass(icon, iconClass);
        button.add(icon);
        button.add(new Label("label", label));
        button.add(new SimpleAttributeModifier("href", url));
        add(button);
    }
    protected void addSyndicationDiscoveryLink() {
        add(WicketUtils.syndicationDiscoveryLink(SyndicationServlet.getTitle(repositoryName,
                objectId), SyndicationServlet.asLink(getRequest()