View Javadoc
1   package org.itracker.web.servlets;
2   
3   import com.sun.syndication.feed.module.DCModuleImpl;
4   import com.sun.syndication.feed.module.SyModuleImpl;
5   import com.sun.syndication.feed.rss.*;
6   import org.apache.commons.lang.StringUtils;
7   import org.apache.struts.config.ForwardConfig;
8   import org.apache.struts.config.ModuleConfig;
9   import org.apache.struts.taglib.TagUtils;
10  import org.apache.struts.util.ModuleUtils;
11  import org.itracker.core.resources.ITrackerResources;
12  import org.itracker.model.Issue;
13  import org.itracker.model.IssueHistory;
14  import org.itracker.model.PermissionType;
15  import org.itracker.model.Project;
16  import org.itracker.model.util.IssueUtilities;
17  import org.itracker.services.ConfigurationService;
18  import org.itracker.services.IssueService;
19  import org.itracker.services.ProjectService;
20  import org.itracker.web.util.Constants;
21  import org.itracker.web.util.HTMLUtilities;
22  import org.itracker.web.util.LoginUtilities;
23  import org.itracker.web.util.ServletContextUtils;
24  import org.springframework.http.HttpStatus;
25  import org.springframework.http.converter.feed.RssChannelHttpMessageConverter;
26  import org.springframework.http.server.ServletServerHttpResponse;
27  
28  import javax.mail.internet.InternetAddress;
29  import javax.servlet.ServletConfig;
30  import javax.servlet.ServletContext;
31  import javax.servlet.ServletException;
32  import javax.servlet.http.HttpServletRequest;
33  import javax.servlet.http.HttpServletResponse;
34  import java.io.IOException;
35  import java.net.MalformedURLException;
36  import java.util.*;
37  import java.util.regex.Matcher;
38  import java.util.regex.Pattern;
39  
40  
41  public class RssFeedController extends GenericController {
42  
43      final private static Pattern URL_PATTERN = Pattern.compile("(?i).*/issues/p?([0-9]*)/?i?([0-9]*)");
44      @Override
45      public void init(ServletConfig config) throws ServletException {
46          super.init(config);
47  
48      }
49  
50      @Override
51      protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
52  
53  
54          RssChannelHttpMessageConverter conv = new RssChannelHttpMessageConverter();
55          try (ServletServerHttpResponse sr = new ServletServerHttpResponse(resp)) {
56              Matcher uriMatcher = URL_PATTERN.matcher(req.getRequestURI());
57  
58              Integer projectId = null;
59              Integer issueId = null;
60              try {
61                  if (uriMatcher.matches()) {
62                      projectId = uriMatcher.group(1).equals("") ? null : Integer.valueOf(uriMatcher.group(1));
63                      issueId = uriMatcher.group(2).equals("") ? null : Integer.valueOf(uriMatcher.group(2));
64  
65                  }
66  
67              } catch (RuntimeException e) {
68                  deny(sr);
69                  return;
70              }
71  
72              final IssueService is = ServletContextUtils.getItrackerServices().getIssueService();
73              final ProjectService ps = ServletContextUtils.getItrackerServices().getProjectService();
74              final ConfigurationService cs = ServletContextUtils.getItrackerServices().getConfigurationService();
75  
76              final String baseURL = cs.getSystemBaseURL();
77              final String generator = cs.getProperty("notification_from_text",
78                      "iTracker "
79                              + cs.getProperty(Constants.VERSION_KEY, "3"));
80  
81  
82              Channel c = new Channel(conv.getSupportedMediaTypes().get(0).getType());
83  
84  
85              c.setGenerator(generator);
86  
87  
88              c.setModules(Arrays.asList(
89                      new DCModuleImpl(),
90                      new SyModuleImpl()
91              ));
92  
93  
94              c.setFeedType("rss_2.0");
95              c.setLink(cs.getSystemBaseURL() + req.getServletPath());
96  
97              if (null != issueId) {
98                  Issue i = is.getIssue(issueId);
99                  if (!LoginUtilities.canViewIssue(i)) {
100                     deny(sr);
101                     return;
102                 }
103 
104                 toChannel(c, i, baseURL);
105             } else if (null != projectId) {
106                 Project p = ps.getProject(projectId);
107                 if (null == p) {
108                     deny(sr);
109                     return;
110                 }
111                 if (!LoginUtilities.hasPermission(p, PermissionType.ISSUE_VIEW_USERS)) {
112                     deny(sr);
113                     return;
114                 }
115 
116                 toChannel(c, p, is, req, baseURL);
117 
118             } else {
119 
120                 toChannel(c, ps, req, baseURL);
121             }
122 
123             conv.write(c, conv.getSupportedMediaTypes().get(0), sr);
124         }
125 
126 
127 
128     }
129 
130     private void toChannel(Channel c, ProjectService ps, HttpServletRequest req, String baseURL) {
131         List<Project> projects = ps.getAllAvailableProjects();
132         c.setTitle(ITrackerResources.getString("itracker.feed.projects.title"));
133         c.setDescription(ITrackerResources.getString("itracker.feed.projects.description", baseURL));
134         c.setLink(baseURL);
135         c.setUri(baseURL);
136         for (Project p : projects) {
137             if (LoginUtilities.hasAnyPermission(p, null)) {
138                 Item pi = new Item();
139                 pi.setLink(getProjectURL(p, req, getServletContext(), baseURL));
140 
141                 pi.setTitle(p.getName());
142                 Guid guid = new Guid();
143                 guid.setValue(pi.getLink());
144                 guid.setPermaLink(true);
145 
146                 pi.setGuid(guid);
147 
148                 Description desc = new Description();
149                 desc.setType(Content.TEXT);
150                 desc.setValue(p.getDescription());
151                 pi.setDescription(desc);
152 
153                 Content content = new Content();
154                 content.setType(Content.HTML);
155 
156                 content.setValue(
157                         p.getDescription()
158                 );
159                 pi.setPubDate(ps.getLatestIssueUpdatedDateByProjectId(p.getId()));
160 
161                 c.getItems().add(pi);
162             }
163         }
164     }
165 
166     private void toChannel(Channel channel, Project project, IssueService is, HttpServletRequest req, String baseURL) throws MalformedURLException {
167         List<Issue> listIssues;
168         if (!LoginUtilities.hasPermission(project, PermissionType.ISSUE_VIEW_ALL)) {
169             listIssues = new ArrayList<>();
170             for (Issue issue : is.getIssuesByProjectId(project.getId())) {
171                 if (LoginUtilities.canViewIssue(issue)) {
172                     listIssues.add(issue);
173                 }
174             }
175         } else {
176             listIssues = is.getIssuesByProjectId(project.getId());
177         }
178 
179         channel.setDescription(ITrackerResources.getString("itracker.feed.project.description", project.getName()));
180         channel.setTitle(ITrackerResources.getString("itracker.feed.project.title ", project.getName(), project.getDescription()));
181         channel.setLink(getProjectURL(project, req, getServletContext(), baseURL));
182 
183         is.getIssuesByProjectId(project.getId());
184         List<Item> sItems = projectIssueItems(req, baseURL, listIssues);
185 
186         channel.setItems(sItems);
187     }
188 
189     private void toChannel(Channel channel, Issue issue, String baseURL) throws MalformedURLException {
190         channel.setDescription( ITrackerResources.getString("itracker.feed.issue.description.description", String.valueOf(issue.getId())));
191         channel.setTitle(ITrackerResources.getString("itracker.feed.issue.title",
192                 String.valueOf(issue.getId()), issue.getDescription()));
193         channel.setLink(getIssueURL(issue, baseURL));
194 
195         channel.setTitle(issue.getId() + " - " + issue.getDescription());
196         List<Item> sItems = issueHistoryItems(baseURL, issue);
197 
198         channel.setItems(sItems);
199     }
200 
201 
202     private void deny(ServletServerHttpResponse sr) {
203         sr.getHeaders().clear();
204         sr.setStatusCode(HttpStatus.FORBIDDEN);
205     }
206 
207     private List<Item> projectIssueItems(HttpServletRequest req, String baseURL, List<Issue> listIssues) throws MalformedURLException {
208 
209         List<Item> sItems = new ArrayList<>(listIssues.size());
210 
211         final Iterator<Issue> issuesIt = listIssues.iterator();
212 // start copying from Models to PTOs
213         Issue issue;
214         Item current;
215 
216         while (issuesIt.hasNext()) {
217 
218             issue = issuesIt.next();
219             current = new Item();
220             current.setUri(baseURL + req.getServletPath());
221             current.setLink(getIssueURL(issue, baseURL));
222 
223             Guid guid = new Guid();
224             guid.setValue(current.getLink());
225             guid.setPermaLink(true);
226 
227             current.setGuid(guid);
228 
229             Description desc = new Description();
230             desc.setType(Content.TEXT);
231             desc.setValue("Issue " + issue.getId());
232             current.setDescription(desc);
233 
234             current.setTitle(issue.getDescription());
235             current.setPubDate(issue.getLastModifiedDate());
236             Content c = new Content();
237             c.setType(Content.HTML);
238 
239             c.setValue(
240                     issue.getHistory().get(issue.getHistory().size() - 1).getDescription()
241             );
242             current.setContent(c);
243 
244             sItems.add(current);
245         }
246         return sItems;
247     }
248 
249     private List<Item> issueHistoryItems(String baseURL, Issue i) throws MalformedURLException {
250         List<Item> sItems = new ArrayList<>(i.getHistory().size());
251         Item current;
252 
253         StringBuilder author = new StringBuilder();
254         List<IssueHistory> history = new LinkedList<>(i.getHistory());
255         Collections.reverse(history);
256         for (IssueHistory ih : history) {
257             int index = ( history.indexOf(ih)+1 );
258             if (index > 10) {
259                 // limited to newest 10 issues
260                 break;
261             }
262 
263             current = new Item();
264             Content content = new Content();
265 
266             current.setLink(getIssueURL(i, baseURL));
267 
268             Guid guid = new Guid();
269             guid.setValue(current.getLink() + "#h" + index);
270             guid.setPermaLink(true);
271             current.setGuid(guid);
272 
273             current.setTitle(ITrackerResources.getString("itracker.feed.history.title",
274                     String.valueOf(history.size() + 1 - index)));
275 
276             Description desc = new Description();
277             desc.setType(Content.TEXT);
278             desc.setValue(HTMLUtilities.removeMarkup( ih.getDescription() ));
279             current.setDescription(desc);
280 
281             content.setType(Content.HTML);
282 
283             content.setValue(
284                     "<p>" + HTMLUtilities.removeMarkup( ih.getDescription() ) + "</p>"
285             );
286             current.setContent(content);
287             current.setPubDate(ih.getCreateDate());
288 
289             author.setLength(0);
290             InternetAddress authorAddress = ih.getUser().getEmailAddress();
291             if (StringUtils.isNotBlank(authorAddress.getAddress())) {
292                 author.append(authorAddress.getAddress());
293                 if (StringUtils.isNotBlank(authorAddress.getPersonal())) {
294                     author.append(' ')
295                             .append('(')
296                             .append(authorAddress.getPersonal())
297                             .append(')');
298                 }
299                 current.setAuthor(String.valueOf(author));
300             }
301 
302 
303             sItems.add(current);
304         }
305         return sItems;
306     }
307 
308 
309     private String getIssueURL(Issue i, String baseUrl) throws MalformedURLException {
310         return String.valueOf(IssueUtilities.getIssueURL(i, baseUrl));
311 
312     }
313 
314     private String getProjectURL(Project p, HttpServletRequest req, ServletContext context, String baseUrl) {
315         ModuleConfig conf = ModuleUtils.getInstance().getModuleConfig(
316                 "/module-projects",
317                 req,
318                 context);
319 
320         ForwardConfig forwardConfig = conf.findForwardConfig("listissues");
321         return baseUrl + TagUtils.getInstance().pageURL(req, forwardConfig.getPath(), conf) + "?projectId=" + p.getId();
322     }
323 }