]> source.dussan.org Git - gitblit.git/commitdiff
Support pagination in RSS feeds. Standardize pg as page parameter.
authorJames Moger <james.moger@gitblit.com>
Sat, 5 Nov 2011 02:28:32 +0000 (22:28 -0400)
committerJames Moger <james.moger@gitblit.com>
Sat, 5 Nov 2011 02:28:32 +0000 (22:28 -0400)
docs/02_rpc.mkd
src/com/gitblit/SyndicationServlet.java
src/com/gitblit/client/FeedsPanel.java
src/com/gitblit/client/GitblitClient.java
src/com/gitblit/client/SearchDialog.java
src/com/gitblit/utils/SyndicationUtils.java
src/com/gitblit/wicket/WicketUtils.java
tests/com/gitblit/tests/SyndicationUtilsTest.java

index bb58d68f82d5833f52bee02b80cc60465a0f6c9d..d1bb1f33b210e38133cf4945ab2730dc315afc82 100644 (file)
@@ -42,6 +42,7 @@ The Gitblit API includes methods for retrieving and interpreting RSS feeds.  The
 <tr><td><em>repository</em></td><td><em>required</em></td><td>repository name is part of the url (see examples below)</td></tr>\r
 <tr><td>h=</td><td><em>optional</em><br/>default: HEAD</td><td>starting branch, ref, or commit id</td></tr>\r
 <tr><td>l=</td><td><em>optional</em><br/>default: web.syndicationEntries</td><td>maximum return count</td></tr>\r
+<tr><td>pg=</td><td><em>optional</em><br/>default: 0</td><td>page number for paging<br/>(offset into history = pagenumber*maximum return count)</td></tr>\r
 <tr><td colspan='3'><b>search query</b></td></tr>\r
 <tr><td>s=</td><td><em>required</em></td><td>search string</td></tr>\r
 <tr><td>st=</td><td><em>optional</em><br/>default: COMMIT</td><td>search type</td></tr>\r
@@ -51,7 +52,7 @@ The Gitblit API includes methods for retrieving and interpreting RSS feeds.  The
 \r
     https://localhost:8443/feed/gitblit.git?l=50&h=refs/heads/master\r
     https://localhost:8443/feed/gitblit.git?l=50&h=refs/heads/master&s=documentation\r
-    https://localhost:8443/feed/gitblit.git?l=50&h=refs/heads/master&s=james&st=author\r
+    https://localhost:8443/feed/gitblit.git?l=50&h=refs/heads/master&s=james&st=author&pg=2\r
 \r
 ## JSON Remote Procedure Call (RPC) Interface\r
 \r
index 128df43f7f727c58bd54ecef7c46946e4dafb51b..39e37ca952172d48306f591346beef4ff1e10e80 100644 (file)
@@ -129,6 +129,7 @@ public class SyndicationServlet extends HttpServlet {
                String repositoryName = url;\r
                String objectId = request.getParameter("h");\r
                String l = request.getParameter("l");\r
+               String page = request.getParameter("pg");\r
                String searchString = request.getParameter("s");\r
                Constants.SearchType searchType = Constants.SearchType.COMMIT;\r
                if (!StringUtils.isEmpty(request.getParameter("st"))) {\r
@@ -147,6 +148,13 @@ public class SyndicationServlet extends HttpServlet {
                        } catch (NumberFormatException x) {\r
                        }\r
                }\r
+               int offset = 0;\r
+               if (!StringUtils.isEmpty(page)) {\r
+                       try {\r
+                               offset = length * Integer.parseInt(page);\r
+                       } catch (NumberFormatException x) {\r
+                       }\r
+               }\r
 \r
                response.setContentType("application/rss+xml; charset=UTF-8");\r
                Repository repository = GitBlit.self().getRepository(repositoryName);\r
@@ -154,11 +162,11 @@ public class SyndicationServlet extends HttpServlet {
                List<RevCommit> commits;\r
                if (StringUtils.isEmpty(searchString)) {\r
                        // standard log/history lookup\r
-                       commits = JGitUtils.getRevLog(repository, objectId, 0, length);\r
+                       commits = JGitUtils.getRevLog(repository, objectId, offset, length);\r
                } else {\r
                        // repository search\r
-                       commits = JGitUtils.searchRevlogs(repository, objectId, searchString, searchType, 0,\r
-                                       length);\r
+                       commits = JGitUtils.searchRevlogs(repository, objectId, searchString, searchType,\r
+                                       offset, length);\r
                }\r
                Map<ObjectId, List<RefModel>> allRefs = JGitUtils.getAllRefs(repository);\r
                List<SyndicatedEntryModel> entries = new ArrayList<SyndicatedEntryModel>();\r
index a8094f80dc4838759241af1859d372a1b2b2d90a..97764db7a328dffbadb247fa3ed7247ae94e6d49 100644 (file)
@@ -18,6 +18,7 @@ package com.gitblit.client;
 import java.awt.BorderLayout;\r
 import java.awt.FlowLayout;\r
 import java.awt.Insets;\r
+import java.awt.Rectangle;\r
 import java.awt.event.ActionEvent;\r
 import java.awt.event.ActionListener;\r
 import java.awt.event.MouseAdapter;\r
@@ -76,6 +77,12 @@ public abstract class FeedsPanel extends JPanel {
 \r
        private JComboBox authorSelector;\r
 \r
+       private int page;\r
+\r
+       private JButton prev;\r
+\r
+       private JButton next;\r
+\r
        public FeedsPanel(GitblitClient gitblit) {\r
                super();\r
                this.gitblit = gitblit;\r
@@ -83,10 +90,29 @@ public abstract class FeedsPanel extends JPanel {
        }\r
 \r
        private void initialize() {\r
+\r
+               prev = new JButton("<");\r
+               prev.setToolTipText(Translation.get("gb.pagePrevious"));\r
+               prev.setEnabled(false);\r
+               prev.addActionListener(new ActionListener() {\r
+                       public void actionPerformed(ActionEvent e) {\r
+                               refreshFeeds(--page);\r
+                       }\r
+               });\r
+\r
+               next = new JButton(">");\r
+               next.setToolTipText(Translation.get("gb.pageNext"));\r
+               next.setEnabled(false);\r
+               next.addActionListener(new ActionListener() {\r
+                       public void actionPerformed(ActionEvent e) {\r
+                               refreshFeeds(++page);\r
+                       }\r
+               });\r
+\r
                JButton refreshFeeds = new JButton(Translation.get("gb.refresh"));\r
                refreshFeeds.addActionListener(new ActionListener() {\r
                        public void actionPerformed(ActionEvent e) {\r
-                               refreshFeeds();\r
+                               refreshFeeds(0);\r
                        }\r
                });\r
 \r
@@ -205,6 +231,8 @@ public abstract class FeedsPanel extends JPanel {
                northControls.add(repositorySelector);\r
                northControls.add(new JLabel(Translation.get("gb.author")));\r
                northControls.add(authorSelector);\r
+//             northControls.add(prev);\r
+//             northControls.add(next);\r
 \r
                JPanel northPanel = new JPanel(new BorderLayout(0, Utils.MARGIN));\r
                northPanel.add(header, BorderLayout.NORTH);\r
@@ -221,11 +249,12 @@ public abstract class FeedsPanel extends JPanel {
                return Utils.INSETS;\r
        }\r
 \r
-       protected void refreshFeeds() {\r
+       protected void refreshFeeds(final int page) {\r
+               this.page = page;\r
                GitblitWorker worker = new GitblitWorker(FeedsPanel.this, null) {\r
                        @Override\r
                        protected Boolean doRequest() throws IOException {\r
-                               gitblit.refreshSubscribedFeeds();\r
+                               gitblit.refreshSubscribedFeeds(page);\r
                                return true;\r
                        }\r
 \r
@@ -244,24 +273,33 @@ public abstract class FeedsPanel extends JPanel {
                tableModel.entries.addAll(gitblit.getSyndicatedEntries());\r
                tableModel.fireTableDataChanged();\r
                header.setText(Translation.get("gb.activity") + " ("\r
-                               + gitblit.getSyndicatedEntries().size() + ")");\r
+                               + gitblit.getSyndicatedEntries().size() + (page > 0 ? (", pg " + (page + 1)) : "")\r
+                               + ")");\r
                if (pack) {\r
                        Utils.packColumns(table, Utils.MARGIN);\r
                }\r
-               // determine unique repositories\r
-               Set<String> uniqueRepositories = new HashSet<String>();\r
-               for (SyndicatedEntryModel entry : tableModel.entries) {\r
-                       uniqueRepositories.add(entry.repository);\r
-               }\r
+               table.scrollRectToVisible(new Rectangle(table.getCellRect(0, 0, true)));\r
 \r
-               // repositories\r
-               List<String> sortedRespositories = new ArrayList<String>(uniqueRepositories);\r
-               StringUtils.sortRepositorynames(sortedRespositories);\r
-               repositoryChoices.removeAllElements();\r
-               repositoryChoices.addElement(ALL);\r
-               for (String repo : sortedRespositories) {\r
-                       repositoryChoices.addElement(repo);\r
+               if (page == 0) {\r
+                       // determine unique repositories\r
+                       Set<String> uniqueRepositories = new HashSet<String>();\r
+                       for (SyndicatedEntryModel entry : tableModel.entries) {\r
+                               uniqueRepositories.add(entry.repository);\r
+                       }\r
+\r
+                       // repositories\r
+                       List<String> sortedRespositories = new ArrayList<String>(uniqueRepositories);\r
+                       StringUtils.sortRepositorynames(sortedRespositories);\r
+                       repositoryChoices.removeAllElements();\r
+                       repositoryChoices.addElement(ALL);\r
+                       for (String repo : sortedRespositories) {\r
+                               repositoryChoices.addElement(repo);\r
+                       }\r
                }\r
+\r
+               // update pagination buttons\r
+               next.setEnabled(tableModel.entries.size() > 0);\r
+               prev.setEnabled(page > 0);\r
        }\r
 \r
        private void updateAuthors() {\r
index e8460f5fb0ce1b94f4c6abc2d5208c78e9c191f6..588b6d805cd4bc0d766c3fd20f9051ad63dc1948 100644 (file)
@@ -101,13 +101,7 @@ public class GitblitClient implements Serializable {
                refreshSettings();\r
                refreshAvailableFeeds();\r
                refreshRepositories();\r
-\r
-               try {\r
-                       // RSS feeds may be disabled by server\r
-                       refreshSubscribedFeeds();\r
-               } catch (IOException e) {\r
-                       e.printStackTrace();\r
-               }\r
+               refreshSubscribedFeeds(0);\r
 \r
                try {\r
                        // credentials may not have administrator access\r
@@ -253,14 +247,14 @@ public class GitblitClient implements Serializable {
                return availableFeeds;\r
        }\r
 \r
-       public List<SyndicatedEntryModel> refreshSubscribedFeeds() throws IOException {\r
+       public List<SyndicatedEntryModel> refreshSubscribedFeeds(int page) throws IOException {\r
                Set<SyndicatedEntryModel> allEntries = new HashSet<SyndicatedEntryModel>();\r
                if (reg.feeds.size() > 0) {\r
                        for (FeedModel feed : reg.feeds) {\r
                                feed.lastRefreshDate = feed.currentRefreshDate;\r
                                feed.currentRefreshDate = new Date();\r
                                List<SyndicatedEntryModel> entries = SyndicationUtils.readFeed(url,\r
-                                               feed.repository, feed.branch, -1, account, password);\r
+                                               feed.repository, feed.branch, -1, page, account, password);\r
                                allEntries.addAll(entries);\r
                        }\r
                }\r
@@ -308,9 +302,9 @@ public class GitblitClient implements Serializable {
        }\r
 \r
        public List<SyndicatedEntryModel> search(String repository, String branch, String fragment,\r
-                       Constants.SearchType type, int numberOfEntries) throws IOException {\r
+                       Constants.SearchType type, int numberOfEntries, int page) throws IOException {\r
                return SyndicationUtils.readSearchFeed(url, repository, branch, fragment, type,\r
-                               numberOfEntries, account, password);\r
+                               numberOfEntries, page, account, password);\r
        }\r
 \r
        public List<FederationModel> refreshFederationRegistrations() throws IOException {\r
index 2f45611ebd42e92892f799959371c69081792784..5dbea7892fa9ea17151e01b564118d53eacf7cf1 100644 (file)
@@ -18,6 +18,7 @@ package com.gitblit.client;
 import java.awt.BorderLayout;\r
 import java.awt.FlowLayout;\r
 import java.awt.Insets;\r
+import java.awt.Rectangle;\r
 import java.awt.event.ActionEvent;\r
 import java.awt.event.ActionListener;\r
 import java.awt.event.MouseAdapter;\r
@@ -77,6 +78,12 @@ public class SearchDialog extends JFrame {
 \r
        private JComboBox maxHitsSelector;\r
 \r
+       private int page;\r
+\r
+       private JButton prev;\r
+\r
+       private JButton next;\r
+\r
        public SearchDialog(GitblitClient gitblit) {\r
                super();\r
                this.gitblit = gitblit;\r
@@ -88,10 +95,28 @@ public class SearchDialog extends JFrame {
 \r
        private void initialize() {\r
 \r
+               prev = new JButton("<");\r
+               prev.setToolTipText(Translation.get("gb.pagePrevious"));\r
+               prev.setEnabled(false);\r
+               prev.addActionListener(new ActionListener() {\r
+                       public void actionPerformed(ActionEvent e) {\r
+                               search(--page);\r
+                       }\r
+               });\r
+\r
+               next = new JButton(">");\r
+               next.setToolTipText(Translation.get("gb.pageNext"));\r
+               next.setEnabled(false);\r
+               next.addActionListener(new ActionListener() {\r
+                       public void actionPerformed(ActionEvent e) {\r
+                               search(++page);\r
+                       }\r
+               });\r
+\r
                final JButton search = new JButton(Translation.get("gb.search"));\r
                search.addActionListener(new ActionListener() {\r
                        public void actionPerformed(ActionEvent e) {\r
-                               search();\r
+                               search(0);\r
                        }\r
                });\r
 \r
@@ -194,12 +219,12 @@ public class SearchDialog extends JFrame {
                searchTypeSelector.setSelectedItem(Constants.SearchType.COMMIT);\r
 \r
                maxHitsSelector = new JComboBox(new Integer[] { 25, 50, 75, 100 });\r
-               maxHitsSelector.setSelectedIndex(-1);\r
+               maxHitsSelector.setSelectedIndex(0);\r
 \r
                searchFragment = new JTextField(25);\r
                searchFragment.addActionListener(new ActionListener() {\r
                        public void actionPerformed(ActionEvent event) {\r
-                               search();\r
+                               search(0);\r
                        }\r
                });\r
 \r
@@ -214,6 +239,8 @@ public class SearchDialog extends JFrame {
                northControls.add(maxHitsSelector);\r
                northControls.add(searchFragment);\r
                northControls.add(search);\r
+               northControls.add(prev);\r
+               northControls.add(next);\r
 \r
                JPanel northPanel = new JPanel(new BorderLayout(0, Utils.MARGIN));\r
                northPanel.add(header, BorderLayout.NORTH);\r
@@ -263,7 +290,8 @@ public class SearchDialog extends JFrame {
                }\r
        }\r
 \r
-       protected void search() {\r
+       protected void search(final int page) {\r
+               this.page = page;\r
                final String repository = repositorySelector.getSelectedItem().toString();\r
                final String branch = branchSelector.getSelectedIndex() > -1 ? branchSelector\r
                                .getSelectedItem().toString() : null;\r
@@ -272,13 +300,15 @@ public class SearchDialog extends JFrame {
                final String fragment = searchFragment.getText();\r
                final int maxEntryCount = maxHitsSelector.getSelectedIndex() > -1 ? ((Integer) maxHitsSelector\r
                                .getSelectedItem()) : -1;\r
+\r
                if (StringUtils.isEmpty(fragment)) {\r
                        return;\r
                }\r
                SwingWorker<List<SyndicatedEntryModel>, Void> worker = new SwingWorker<List<SyndicatedEntryModel>, Void>() {\r
                        @Override\r
                        protected List<SyndicatedEntryModel> doInBackground() throws IOException {\r
-                               return gitblit.search(repository, branch, fragment, searchType, maxEntryCount);\r
+                               return gitblit\r
+                                               .search(repository, branch, fragment, searchType, maxEntryCount, page);\r
                        }\r
 \r
                        @Override\r
@@ -298,11 +328,18 @@ public class SearchDialog extends JFrame {
                tableModel.entries.clear();\r
                tableModel.entries.addAll(entries);\r
                tableModel.fireTableDataChanged();\r
-               setTitle(Translation.get("gb.search") + ": " + fragment + " (" + entries.size() + ")");\r
+               setTitle(Translation.get("gb.search") + ": " + fragment + " (" + entries.size()\r
+                               + (page > 0 ? (", pg " + (page + 1)) : "") + ")");\r
                header.setText(getTitle());\r
                if (pack) {\r
                        Utils.packColumns(table, Utils.MARGIN);\r
                }\r
+               table.scrollRectToVisible(new Rectangle(table.getCellRect(0, 0, true)));\r
+\r
+               // update pagination buttons\r
+               int maxHits = (Integer) maxHitsSelector.getSelectedItem();\r
+               next.setEnabled(entries.size() == maxHits);\r
+               prev.setEnabled(page > 0);\r
        }\r
 \r
        protected SyndicatedEntryModel getSelectedSyndicatedEntry() {\r
index 4ba56223bdcec7949b5bba88ad171d5b8ffdc463..6919cd2480c39e2a7b06934621039d1276023370 100644 (file)
@@ -100,7 +100,7 @@ public class SyndicationUtils {
                        content.setType(entryModel.contentType);\r
                        content.setValue(entryModel.content);\r
                        entry.setDescription(content);\r
-                       \r
+\r
                        entries.add(entry);\r
                }\r
                feed.setEntries(entries);\r
@@ -123,18 +123,23 @@ public class SyndicationUtils {
         * @param numberOfEntries\r
         *            the number of entries to retrieve. if <= 0 the server default\r
         *            is used.\r
+        * @param page\r
+        *            0-indexed. used to paginate the results.\r
         * @param username\r
         * @param password\r
         * @return a list of SyndicationModel entries\r
         * @throws {@link IOException}\r
         */\r
        public static List<SyndicatedEntryModel> readFeed(String url, String repository, String branch,\r
-                       int numberOfEntries, String username, char[] password) throws IOException {\r
+                       int numberOfEntries, int page, String username, char[] password) throws IOException {\r
                // build feed url\r
                List<String> parameters = new ArrayList<String>();\r
                if (numberOfEntries > 0) {\r
                        parameters.add("l=" + numberOfEntries);\r
                }\r
+               if (page > 0) {\r
+                       parameters.add("pg=" + page);\r
+               }\r
                if (!StringUtils.isEmpty(branch)) {\r
                        parameters.add("h=" + branch);\r
                }\r
@@ -155,6 +160,8 @@ public class SyndicationUtils {
         * @param numberOfEntries\r
         *            the number of entries to retrieve. if <= 0 the server default\r
         *            is used.\r
+        * @param page\r
+        *            0-indexed. used to paginate the results.\r
         * @param username\r
         * @param password\r
         * @return a list of SyndicationModel entries\r
@@ -162,13 +169,16 @@ public class SyndicationUtils {
         */\r
        public static List<SyndicatedEntryModel> readSearchFeed(String url, String repository,\r
                        String branch, String fragment, Constants.SearchType searchType, int numberOfEntries,\r
-                       String username, char[] password) throws IOException {\r
+                       int page, String username, char[] password) throws IOException {\r
                // determine parameters\r
                List<String> parameters = new ArrayList<String>();\r
                parameters.add("s=" + StringUtils.encodeURL(fragment));\r
                if (numberOfEntries > 0) {\r
                        parameters.add("l=" + numberOfEntries);\r
                }\r
+               if (page > 0) {\r
+                       parameters.add("pg=" + page);\r
+               }\r
                if (!StringUtils.isEmpty(branch)) {\r
                        parameters.add("h=" + branch);\r
                }\r
index f47663cae1ea69fa4fb20678cfb7c267dfb5606e..37b44472fbd798df1e703f6d69240484944f148c 100644 (file)
@@ -284,9 +284,9 @@ public class WicketUtils {
                        return newObjectParameter(repositoryName, objectId);\r
                }\r
                if (StringUtils.isEmpty(objectId)) {\r
-                       return new PageParameters("r=" + repositoryName + ",page=" + pageNumber);\r
+                       return new PageParameters("r=" + repositoryName + ",pg=" + pageNumber);\r
                }\r
-               return new PageParameters("r=" + repositoryName + ",h=" + objectId + ",page=" + pageNumber);\r
+               return new PageParameters("r=" + repositoryName + ",h=" + objectId + ",pg=" + pageNumber);\r
        }\r
 \r
        public static PageParameters newHistoryPageParameter(String repositoryName, String objectId,\r
@@ -295,10 +295,10 @@ public class WicketUtils {
                        return newObjectParameter(repositoryName, objectId);\r
                }\r
                if (StringUtils.isEmpty(objectId)) {\r
-                       return new PageParameters("r=" + repositoryName + ",f=" + path + ",page=" + pageNumber);\r
+                       return new PageParameters("r=" + repositoryName + ",f=" + path + ",pg=" + pageNumber);\r
                }\r
                return new PageParameters("r=" + repositoryName + ",h=" + objectId + ",f=" + path\r
-                               + ",page=" + pageNumber);\r
+                               + ",pg=" + pageNumber);\r
        }\r
 \r
        public static PageParameters newBlobDiffParameter(String repositoryName, String baseCommitId,\r
@@ -323,10 +323,10 @@ public class WicketUtils {
                        String search, Constants.SearchType type, int pageNumber) {\r
                if (StringUtils.isEmpty(commitId)) {\r
                        return new PageParameters("r=" + repositoryName + ",s=" + search + ",st=" + type.name()\r
-                                       + ",page=" + pageNumber);\r
+                                       + ",pg=" + pageNumber);\r
                }\r
                return new PageParameters("r=" + repositoryName + ",h=" + commitId + ",s=" + search\r
-                               + ",st=" + type.name() + ",page=" + pageNumber);\r
+                               + ",st=" + type.name() + ",pg=" + pageNumber);\r
        }\r
 \r
        public static String getRepositoryName(PageParameters params) {\r
@@ -355,7 +355,7 @@ public class WicketUtils {
 \r
        public static int getPage(PageParameters params) {\r
                // index from 1\r
-               return params.getInt("page", 1);\r
+               return params.getInt("pg", 1);\r
        }\r
 \r
        public static String getUsername(PageParameters params) {\r
index 98bdd4bff0b74f2d3a15b783e4a343a44dcdfbcb..e0a32bf3c34f8e1ce49ec1bddf2f6434f913d1cf 100644 (file)
@@ -18,7 +18,9 @@ package com.gitblit.tests;
 import java.io.ByteArrayOutputStream;\r
 import java.util.ArrayList;\r
 import java.util.Date;\r
+import java.util.HashSet;\r
 import java.util.List;\r
+import java.util.Set;\r
 \r
 import junit.framework.TestCase;\r
 \r
@@ -51,16 +53,24 @@ public class SyndicationUtilsTest extends TestCase {
        }\r
 \r
        public void testFeedRead() throws Exception {\r
-               List<SyndicatedEntryModel> feed = SyndicationUtils.readFeed("https://localhost:8443",\r
-                               "ticgit.git", "master", 5, "admin", "admin".toCharArray());\r
-               assertTrue(feed != null);\r
-               assertTrue(feed.size() > 0);\r
-               assertEquals(5, feed.size());\r
+               Set<String> links = new HashSet<String>();\r
+               for (int i = 0; i < 2; i++) {\r
+                       List<SyndicatedEntryModel> feed = SyndicationUtils.readFeed("https://localhost:8443",\r
+                                       "ticgit.git", "master", 5, i, "admin", "admin".toCharArray());\r
+                       assertTrue(feed != null);\r
+                       assertTrue(feed.size() > 0);\r
+                       assertEquals(5, feed.size());\r
+                       for (SyndicatedEntryModel entry : feed) {\r
+                               links.add(entry.link);\r
+                       }\r
+               }\r
+               // confirm we have 10 unique commits\r
+               assertEquals("Feed pagination failed", 10, links.size());\r
        }\r
 \r
        public void testSearchFeedRead() throws Exception {\r
                List<SyndicatedEntryModel> feed = SyndicationUtils.readSearchFeed("https://localhost:8443",\r
-                               "ticgit.git", null, "documentation", null, 5, "admin", "admin".toCharArray());\r
+                               "ticgit.git", null, "documentation", null, 5, 0, "admin", "admin".toCharArray());\r
                assertTrue(feed != null);\r
                assertTrue(feed.size() > 0);\r
                assertEquals(2, feed.size());\r