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