diff options
Diffstat (limited to 'sonar-server/src')
34 files changed, 545 insertions, 222 deletions
diff --git a/sonar-server/src/dev/web.xml b/sonar-server/src/dev/web.xml index fbf1d357710..d1b0b8a7b18 100644 --- a/sonar-server/src/dev/web.xml +++ b/sonar-server/src/dev/web.xml @@ -40,7 +40,11 @@ <filter-name>DatabaseSessionFilter</filter-name> <filter-class>org.sonar.server.ui.DatabaseSessionFilter</filter-class> </filter> - <filter> + <filter> + <filter-name>UserSessionFilter</filter-name> + <filter-class>org.sonar.server.platform.UserSessionFilter</filter-class> + </filter> + <filter> <filter-name>RackFilter</filter-name> <filter-class>org.jruby.rack.RackFilter</filter-class> </filter> @@ -49,6 +53,10 @@ <filter-name>DatabaseSessionFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> + <filter-mapping> + <filter-name>UserSessionFilter</filter-name> + <url-pattern>/*</url-pattern> + </filter-mapping> <filter-mapping> <filter-name>ServletFilters</filter-name> <url-pattern>/*</url-pattern> diff --git a/sonar-server/src/main/java/org/sonar/server/issue/DefaultJRubyIssues.java b/sonar-server/src/main/java/org/sonar/server/issue/JRubyApiIssues.java index 4c72fe8385d..513820ea099 100644 --- a/sonar-server/src/main/java/org/sonar/server/issue/DefaultJRubyIssues.java +++ b/sonar-server/src/main/java/org/sonar/server/issue/JRubyApiIssues.java @@ -30,7 +30,7 @@ import org.sonar.api.issue.JRubyIssues; import org.sonar.api.rule.RuleKey; import org.sonar.api.utils.DateUtils; import org.sonar.api.web.UserRole; -import org.sonar.server.ui.JRubyFacades; +import org.sonar.server.platform.UserSession; import javax.annotation.Nullable; import java.util.Collection; @@ -43,24 +43,21 @@ import java.util.Map; * * @since 3.6 */ -public class DefaultJRubyIssues implements JRubyIssues { +public class JRubyApiIssues implements JRubyIssues { private final IssueFinder finder; - private final ServerIssueActions changes; - public DefaultJRubyIssues(IssueFinder f, ServerIssueActions changes) { + public JRubyApiIssues(IssueFinder f) { this.finder = f; - this.changes = changes; - JRubyFacades.setIssues(this); } /** * Requires the role {@link org.sonar.api.web.UserRole#CODEVIEWER} */ @Override - public IssueFinder.Results find(Map<String, Object> params, @Nullable Integer currentUserId) { + public IssueFinder.Results find(Map<String, Object> params) { // TODO move the role to IssueFinder - return finder.find(toQuery(params), currentUserId, UserRole.CODEVIEWER); + return finder.find(toQuery(params), UserSession.get().userId(), UserRole.CODEVIEWER); } IssueQuery toQuery(Map<String, Object> props) { diff --git a/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacades.java b/sonar-server/src/main/java/org/sonar/server/issue/JRubyInternalIssues.java index 0cd75620df2..aa4c4b63cea 100644 --- a/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacades.java +++ b/sonar-server/src/main/java/org/sonar/server/issue/JRubyInternalIssues.java @@ -17,36 +17,27 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.sonar.server.ui; +package org.sonar.server.issue; import org.sonar.api.ServerComponent; -import org.sonar.api.issue.JRubyIssues; -import org.sonar.api.rule.JRubyRules; +import org.sonar.core.issue.workflow.Transition; +import org.sonar.server.platform.UserSession; + +import java.util.List; /** - * All the facades to Java components - * - * @since 3.6 + * All the issue features that are not published to public API */ -public class JRubyFacades implements ServerComponent { - - private static JRubyIssues issues = null; - private static JRubyRules rules = null; +public class JRubyInternalIssues implements ServerComponent { - public static void setIssues(JRubyIssues i) { - JRubyFacades.issues = i; - } - - public static JRubyIssues issues() { - return issues; - } + private final ServerIssueActions actions; - public static void setRules(JRubyRules rules) { - JRubyFacades.rules = rules; + public JRubyInternalIssues(ServerIssueActions actions) { + this.actions = actions; } - public static JRubyRules rules() { - return rules; + public List<Transition> listTransitions(String issueKey) { + return actions.listTransitions(issueKey, UserSession.get().userId()); } } diff --git a/sonar-server/src/main/java/org/sonar/server/issue/ServerIssueActions.java b/sonar-server/src/main/java/org/sonar/server/issue/ServerIssueActions.java index 7e6db78a103..969e04e17f1 100644 --- a/sonar-server/src/main/java/org/sonar/server/issue/ServerIssueActions.java +++ b/sonar-server/src/main/java/org/sonar/server/issue/ServerIssueActions.java @@ -21,14 +21,18 @@ package org.sonar.server.issue; import org.sonar.api.ServerComponent; import org.sonar.api.issue.Issue; +import org.sonar.api.issue.IssueFinder; import org.sonar.api.web.UserRole; import org.sonar.core.issue.DefaultIssue; import org.sonar.core.issue.db.IssueDao; import org.sonar.core.issue.db.IssueDto; import org.sonar.core.issue.workflow.IssueWorkflow; +import org.sonar.core.issue.workflow.Transition; import org.sonar.core.user.AuthorizationDao; import javax.annotation.Nullable; +import java.util.Collections; +import java.util.List; /** * @since 3.6 @@ -36,15 +40,26 @@ import javax.annotation.Nullable; public class ServerIssueActions implements ServerComponent { private final IssueWorkflow workflow; + private final IssueFinder finder; private final IssueDao issueDao; private final AuthorizationDao authorizationDao; - public ServerIssueActions(IssueWorkflow workflow, IssueDao issueDao, AuthorizationDao authorizationDao) { + public ServerIssueActions(IssueWorkflow workflow, IssueFinder finder, IssueDao issueDao, AuthorizationDao authorizationDao) { this.workflow = workflow; + this.finder = finder; this.issueDao = issueDao; this.authorizationDao = authorizationDao; } + public List<Transition> listTransitions(String issueKey, @Nullable Integer userId) { + Issue issue = finder.findByKey(issueKey /*, userId */); + // TODO check authorization + if (issue == null) { + return Collections.emptyList(); + } + return workflow.outManualTransitions(issue); + } + public Issue executeAction(String issueKey, String action, @Nullable Integer userId) { if (userId == null) { // must be logged diff --git a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java index e2f6e298c35..c02d1a7e1cd 100644 --- a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java +++ b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java @@ -69,19 +69,21 @@ import org.sonar.server.charts.ChartFactory; import org.sonar.server.configuration.Backup; import org.sonar.server.configuration.ProfilesManager; import org.sonar.server.database.EmbeddedDatabaseFactory; -import org.sonar.server.issue.DefaultJRubyIssues; +import org.sonar.server.issue.JRubyApiIssues; +import org.sonar.server.issue.JRubyInternalIssues; import org.sonar.server.issue.ServerIssueActions; import org.sonar.server.issue.ServerIssueFinder; -import org.sonar.server.macro.MacroInterpreter; import org.sonar.server.notifications.NotificationCenter; import org.sonar.server.notifications.NotificationService; import org.sonar.server.notifications.reviews.ReviewsNotificationManager; import org.sonar.server.plugins.*; import org.sonar.server.qualitymodel.DefaultModelManager; -import org.sonar.server.rule.DefaultJRubyRules; +import org.sonar.server.rule.JRubyRules; import org.sonar.server.rules.ProfilesConsole; import org.sonar.server.rules.RulesConsole; import org.sonar.server.startup.*; +import org.sonar.server.text.JRubyText; +import org.sonar.server.text.MacroInterpreter; import org.sonar.server.ui.*; import javax.servlet.ServletContext; @@ -185,7 +187,6 @@ public final class Platform { coreContainer.addSingleton(ThreadLocalDatabaseSessionFactory.class); coreContainer.addPicoAdapter(new DatabaseSessionProvider()); coreContainer.addSingleton(ServerMetadataPersister.class); - coreContainer.addSingleton(MacroInterpreter.class); coreContainer.startComponents(); } @@ -242,10 +243,15 @@ public final class Platform { servicesContainer.addSingleton(IssueWorkflow.class); servicesContainer.addSingleton(ServerIssueActions.class); servicesContainer.addSingleton(ServerIssueFinder.class); - servicesContainer.addSingleton(DefaultJRubyIssues.class); + servicesContainer.addSingleton(JRubyApiIssues.class); + servicesContainer.addSingleton(JRubyInternalIssues.class); // rules - servicesContainer.addSingleton(DefaultJRubyRules.class); + servicesContainer.addSingleton(JRubyRules.class); + + // text + servicesContainer.addSingleton(MacroInterpreter.class); + servicesContainer.addSingleton(JRubyText.class); // Notifications servicesContainer.addSingleton(EmailSettings.class); @@ -329,4 +335,11 @@ public final class Platform { public static Server getServer() { return (Server) getInstance().getComponent(Server.class); } + + /** + * Used by ruby code + */ + public static <T> T component(Class<T> type) { + return getInstance().getContainer().getComponentByType(type); + } } diff --git a/sonar-server/src/main/java/org/sonar/server/platform/UserSession.java b/sonar-server/src/main/java/org/sonar/server/platform/UserSession.java new file mode 100644 index 00000000000..0fb7dd8ddbb --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/platform/UserSession.java @@ -0,0 +1,66 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.platform; + +import com.google.common.base.Objects; + +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; + +public class UserSession { + + private static final ThreadLocal<UserSession> threadLocal = new ThreadLocal<UserSession>(); + private static final UserSession ANONYMOUS = new UserSession(null, null); + + private final Integer userId; + private final String login; + + public UserSession(@Nullable Integer userId, @Nullable String login) { + this.userId = userId; + this.login = login; + } + + @CheckForNull + public String login() { + return login; + } + + @CheckForNull + public Integer userId() { + return userId; + } + + public boolean isLoggedIn() { + return userId != null; + } + + /** + * @return never null + */ + public static UserSession get() { + return Objects.firstNonNull(threadLocal.get(), ANONYMOUS); + } + + static void set(@Nullable UserSession session) { + threadLocal.set(session); + } + +} + diff --git a/sonar-server/src/main/java/org/sonar/server/platform/UserSessionFilter.java b/sonar-server/src/main/java/org/sonar/server/platform/UserSessionFilter.java new file mode 100644 index 00000000000..a63923c5139 --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/platform/UserSessionFilter.java @@ -0,0 +1,53 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.platform; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +public class UserSessionFilter implements Filter { + public void init(FilterConfig filterConfig) throws ServletException { + } + + public void destroy() { + } + + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + try { + HttpServletRequest request = (HttpServletRequest) servletRequest; + HttpSession httpSession = request.getSession(true); + + // See available attributes in authenticated_system.rb, methods + // current_user= and logout_keeping_session! + String login = (String) httpSession.getAttribute("login"); + Long userId = (Long) httpSession.getAttribute("user_id"); + + UserSession.set(new UserSession(userId != null ? userId.intValue() : null, login)); + + filterChain.doFilter(servletRequest, servletResponse); + + } finally { + UserSession.set(null); + } + } + +} diff --git a/sonar-server/src/main/java/org/sonar/server/rule/DefaultJRubyRules.java b/sonar-server/src/main/java/org/sonar/server/rule/JRubyRules.java index 7323d0a2d3c..30d6c3a0e26 100644 --- a/sonar-server/src/main/java/org/sonar/server/rule/DefaultJRubyRules.java +++ b/sonar-server/src/main/java/org/sonar/server/rule/JRubyRules.java @@ -19,9 +19,7 @@ */ package org.sonar.server.rule; -import org.sonar.api.rule.JRubyRules; import org.sonar.api.rule.RuleKey; -import org.sonar.server.ui.JRubyFacades; import org.sonar.server.ui.JRubyI18n; /** @@ -29,17 +27,16 @@ import org.sonar.server.ui.JRubyI18n; * * @since 3.6 */ -public class DefaultJRubyRules implements JRubyRules { +public class JRubyRules { private final JRubyI18n jRubyI18n; - public DefaultJRubyRules(JRubyI18n jRubyI18n) { + public JRubyRules(JRubyI18n jRubyI18n) { this.jRubyI18n = jRubyI18n; - JRubyFacades.setRules(this); } public String ruleName(String rubyLocale, RuleKey ruleKey) { - String l18n = jRubyI18n.getRuleName(rubyLocale, ruleKey.repository(), ruleKey.rule()); + String l18n = jRubyI18n.getRuleName(rubyLocale, ruleKey.repository(), ruleKey.rule()); if (l18n != null) { return l18n; } else { diff --git a/sonar-server/src/main/java/org/sonar/server/text/JRubyText.java b/sonar-server/src/main/java/org/sonar/server/text/JRubyText.java new file mode 100644 index 00000000000..7c8fd2a5dc4 --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/text/JRubyText.java @@ -0,0 +1,51 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.text; + +import org.apache.commons.lang.StringEscapeUtils; +import org.sonar.api.ServerComponent; +import org.sonar.core.source.HtmlSourceDecorator; +import org.sonar.markdown.Markdown; + +import java.util.List; + +public class JRubyText implements ServerComponent { + + private final MacroInterpreter macroInterpreter; + private final HtmlSourceDecorator sourceDecorator; + + public JRubyText(MacroInterpreter macroInterpreter, HtmlSourceDecorator sourceDecorator) { + this.macroInterpreter = macroInterpreter; + this.sourceDecorator = sourceDecorator; + } + + public String interpretMacros(String text) { + return macroInterpreter.interpret(text); + } + + public String markdownToHtml(String markdown) { + // TODO move HTML escaping to sonar-markdown + return Markdown.convertToHtml(StringEscapeUtils.escapeHtml(markdown)); + } + + public List<String> highlightedSourceLines(long snapshotId) { + return sourceDecorator.getDecoratedSourceAsHtml(snapshotId); + } +} diff --git a/sonar-server/src/main/java/org/sonar/server/macro/Macro.java b/sonar-server/src/main/java/org/sonar/server/text/Macro.java index 91bd8410655..8b0a10fd75f 100644 --- a/sonar-server/src/main/java/org/sonar/server/macro/Macro.java +++ b/sonar-server/src/main/java/org/sonar/server/text/Macro.java @@ -18,7 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.sonar.server.macro; +package org.sonar.server.text; public interface Macro { diff --git a/sonar-server/src/main/java/org/sonar/server/macro/MacroInterpreter.java b/sonar-server/src/main/java/org/sonar/server/text/MacroInterpreter.java index 6c85ff35777..9f55e385b4b 100644 --- a/sonar-server/src/main/java/org/sonar/server/macro/MacroInterpreter.java +++ b/sonar-server/src/main/java/org/sonar/server/text/MacroInterpreter.java @@ -18,33 +18,27 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.sonar.server.macro; +package org.sonar.server.text; +import com.google.common.collect.ImmutableList; import org.sonar.api.ServerComponent; import javax.servlet.ServletContext; - import java.util.List; -import static com.google.common.collect.Lists.newArrayList; - public class MacroInterpreter implements ServerComponent { - private ServletContext servletContext; - private List<Macro> macroList; + private final List<Macro> macros; public MacroInterpreter(ServletContext servletContext) { - this.servletContext = servletContext; - this.macroList = newArrayList(); - } - - public void start(){ - macroList.add(new RuleMacro(servletContext.getContextPath())); + this.macros = ImmutableList.<Macro>of( + new RuleMacro(servletContext.getContextPath()) + ); } - public String interpret(String text){ + public String interpret(String text) { String textReplaced = text; - for (Macro macro : macroList) { + for (Macro macro : macros) { textReplaced = textReplaced.replaceAll(macro.getRegex(), macro.getReplacement()); } return textReplaced; diff --git a/sonar-server/src/main/java/org/sonar/server/macro/RuleMacro.java b/sonar-server/src/main/java/org/sonar/server/text/RuleMacro.java index df48a37d626..e0209ef5699 100644 --- a/sonar-server/src/main/java/org/sonar/server/macro/RuleMacro.java +++ b/sonar-server/src/main/java/org/sonar/server/text/RuleMacro.java @@ -18,13 +18,13 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.sonar.server.macro; +package org.sonar.server.text; -public class RuleMacro implements Macro{ +class RuleMacro implements Macro { private final String contextPath; - public RuleMacro(String contextPath){ + RuleMacro(String contextPath) { this.contextPath = contextPath; } @@ -35,7 +35,7 @@ public class RuleMacro implements Macro{ return "\\{rule:([a-zA-Z0-9._-]++):([a-zA-Z0-9._-]++)\\}"; } - public String getReplacement(){ + public String getReplacement() { return "<a class='open-modal rule-modal' modal-width='800' href='" + contextPath + "/rules/show/$1:$2?modal=true&layout=false'>$1:$2</a>"; } } diff --git a/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java b/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java index 0e16d6329d7..fc5a1d470d8 100644 --- a/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java +++ b/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java @@ -56,13 +56,10 @@ import org.sonar.core.persistence.DryRunDatabaseFactory; import org.sonar.core.purge.PurgeDao; import org.sonar.core.resource.ResourceIndexerDao; import org.sonar.core.resource.ResourceKeyUpdaterDao; -import org.sonar.core.source.HtmlSourceDecorator; import org.sonar.core.timemachine.Periods; import org.sonar.core.workflow.WorkflowEngine; -import org.sonar.markdown.Markdown; import org.sonar.server.configuration.Backup; import org.sonar.server.configuration.ProfilesManager; -import org.sonar.server.macro.MacroInterpreter; import org.sonar.server.notifications.reviews.ReviewsNotificationManager; import org.sonar.server.platform.*; import org.sonar.server.plugins.*; @@ -73,7 +70,6 @@ import org.sonar.updatecenter.common.UpdateCenter; import org.sonar.updatecenter.common.Version; import javax.annotation.Nullable; - import java.net.InetAddress; import java.sql.Connection; import java.util.*; @@ -89,11 +85,7 @@ public final class JRubyFacade { return SINGLETON; } - public static String markdownToHtml(String input) { - return Markdown.convertToHtml(input); - } - - private <T> T get(Class<T> componentType) { + <T> T get(Class<T> componentType) { return getContainer().getComponentByType(componentType); } @@ -317,7 +309,7 @@ public final class JRubyFacade { public void ruleSeverityChanged(int parentProfileId, int activeRuleId, int oldSeverityId, int newSeverityId, String userName) { getProfilesManager().ruleSeverityChanged(parentProfileId, activeRuleId, RulePriority.values()[oldSeverityId], - RulePriority.values()[newSeverityId], userName); + RulePriority.values()[newSeverityId], userName); } public void ruleDeactivated(int parentProfileId, int deactivatedRuleId, String userName) { @@ -513,10 +505,10 @@ public final class JRubyFacade { // notifier is null when creating the administrator in the migration script 011. if (notifier != null) { notifier.onNewUser(NewUserHandler.Context.builder() - .setLogin(fields.get("login")) - .setName(fields.get("name")) - .setEmail(fields.get("email")) - .build()); + .setLogin(fields.get("login")) + .setName(fields.get("name")) + .setEmail(fields.get("email")) + .build()); } } @@ -555,12 +547,4 @@ public final class JRubyFacade { public Testable testable(String componentKey) { return get(SnapshotPerspectives.class).as(MutableTestable.class, componentKey); } - - public MacroInterpreter getMacroInterpreter(){ - return get(MacroInterpreter.class); - } - - public Collection<String> getHighlightedSourceLines(long snapshotId) { - return get(HtmlSourceDecorator.class).getDecoratedSourceAsHtml(snapshotId); - } } diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/authentication_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/authentication_controller.rb index 78f30d8e632..a27a930cdc5 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/authentication_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/authentication_controller.rb @@ -55,7 +55,7 @@ class Api::AuthenticationController < Api::ApiController end def anonymous? - !session.has_key?(:user_id) + !session.has_key?('user_id') end def set_cache_buster diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/issues_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/issues_controller.rb index d5350a804f1..b73e015ec80 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/issues_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/issues_controller.rb @@ -22,13 +22,31 @@ class Api::IssuesController < Api::ApiController # GET /api/issues/search?<parameters> def search - user_id = current_user ? current_user.id : nil - results = Api.issues.find(params, user_id) - render :json => jsonp(results_to_json(results)) + results = Api.issues.find(params) + render :json => jsonp( + { + :securityExclusions => results.securityExclusions, + :paging => paging_to_json(results.paging), + :issues => results.issues.map { |issue| issue_to_json(issue) } + } + ) end - # POST /api/issues/change?key=<issue key>&<newSeverity=xxx>&<newResolution=xxx>... - def change + # GET /api/issues/transitions?issue=<key> + def transitions + # TODO deal with errors (404, ...) + require_parameters :issue + issue_key = params[:issue] + transitions = Internal.issues.listTransitions(issue_key) + render :json => jsonp( + { + :transitions => transitions.map { |t| t.key() } + } + ) + end + + # POST /api/issues/transition?issue=<key>&transition=<key>&comment=<optional comment> + def transition verify_post_request access_denied unless logged_in? @@ -47,21 +65,13 @@ class Api::IssuesController < Api::ApiController private - def results_to_json(results) - json = {} - json[:issues] = results.issues.map { |issue| issue_to_json(issue) } - json[:paging] = pagination_to_json(results.paging) - json[:securityExclusions] = results.securityExclusions - json - end - def issue_to_json(issue) json = { - :key => issue.key, - :component => issue.componentKey, - :rule => issue.ruleKey.toString(), - :resolution => issue.resolution, - :status => issue.status + :key => issue.key, + :component => issue.componentKey, + :rule => issue.ruleKey.toString(), + :resolution => issue.resolution, + :status => issue.status } json[:severity] = issue.severity if issue.severity json[:desc] = issue.description if issue.description @@ -76,14 +86,13 @@ class Api::IssuesController < Api::ApiController json end - def pagination_to_json(paging) - json = { - :pageIndex => paging.pageIndex, - :pageSize => paging.pageSize, - :total => paging.total, - :pages => paging.pages + def paging_to_json(paging) + { + :pageIndex => paging.pageIndex, + :pageSize => paging.pageSize, + :total => paging.total, + :pages => paging.pages } - json end def format_java_datetime(java_date) diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb index af2ad7ab831..3a19d5890e5 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb @@ -22,16 +22,9 @@ class IssuesController < ApplicationController def index page_index = params[:page_index] || 1 - issues_result = find_issues({'pageSize' => 25, 'pageIndex' => page_index}) + issues_result = Api.issues.find({'pageSize' => 25, 'pageIndex' => page_index}) @paging = issues_result.paging @issues = issues_result.issues.collect {|issue| issue} end - protected - - def find_issues(map) - user = current_user ? current_user.id : nil - Api.issues.find(map, user) - end - end
\ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb b/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb index a16f41d5098..450f07d2257 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb @@ -828,6 +828,7 @@ module ApplicationHelper html end + # TODO move to Api def to_date(java_date) java_date ? Time.at(java_date.time/1000) : nil end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/helpers/source_helper.rb b/sonar-server/src/main/webapp/WEB-INF/app/helpers/source_helper.rb index 2b50ec23f6c..3a56cd84f10 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/helpers/source_helper.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/helpers/source_helper.rb @@ -73,7 +73,7 @@ module SourceHelper end panel.html_lines=[] - html_source_lines = snapshot.highlighting_data || snapshot.source.syntax_highlighted_lines() + html_source_lines = snapshot.highlighted_source_lines || snapshot.source.syntax_highlighted_lines() line_range=sanitize_range(options[:line_range], 1..html_source_lines.length) html_source_lines.each_with_index do |source, index| diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/api.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/api.rb index 478d9a3a591..101ef78aa3d 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/api.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/api.rb @@ -18,16 +18,13 @@ # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # +# Entry points to Java API. All other Ruby classes are not considered +# as an API and can evolve through time. class Api # since 3.6 def self.issues - Java::OrgSonarServerUi::JRubyFacades.issues() - end - - # since 3.6 - def self.rules - Java::OrgSonarServerUi::JRubyFacades.rules() + Internal.issues_api end end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/api/utils.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/api/utils.rb index d22f095e580..14eae5135c0 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/api/utils.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/api/utils.rb @@ -52,8 +52,8 @@ class Api::Utils false end - def self.markdown_to_html(markdown) - markdown ? Java::OrgSonarServerUi::JRubyFacade.markdownToHtml(ERB::Util.html_escape(markdown)) : '' + def self.markdown_to_html(markdown='') + Internal.text.markdownToHtml(markdown) end # Splits a string into an array of lines diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/macro_interpreter.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/internal.rb index 852ed29c2a7..332bc95fdc2 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/macro_interpreter.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/internal.rb @@ -18,10 +18,28 @@ # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # -class MacroInterpreter +# All the Java components that are not published to public plugin API. +# Must NOT be used by plugins. Forward-compatibility is NOT guaranteed. +class Internal - def self.interpret_macro(text) - Java::OrgSonarServerUi::JRubyFacade.getInstance().getMacroInterpreter().interpret(text) + def self.issues + component(Java::OrgSonarServerIssue::JRubyInternalIssues.java_class) end + def self.issues_api + component(Java::OrgSonarApiIssue::JRubyIssues.java_class) + end + + def self.text + component(Java::OrgSonarServerText::JRubyText.java_class) + end + + def self.rules + component(Java::OrgSonarServerRule::JRubyRules.java_class) + end + + private + def self.component(component_java_class) + Java::OrgSonarServerPlatform::Platform.component(component_java_class) + end end
\ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/snapshot.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/snapshot.rb index a59ce9f9d25..ec55b8a46d2 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/snapshot.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/snapshot.rb @@ -252,8 +252,8 @@ class Snapshot < ActiveRecord::Base end end - def highlighting_data - Java::OrgSonarServerUi::JRubyFacade.getInstance().getHighlightedSourceLines(id) + def highlighted_source_lines + Internal.text.highlightedSourceLines(id) end def has_source diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_issue.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_issue.html.erb index d32da0dc041..fb18dabbf95 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_issue.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_issue.html.erb @@ -59,7 +59,7 @@ </tr> <% # TODO action plan %> <% if rule %> - <% rule_name = Api.rules.rule_name(I18n.locale, rule.rule_key) %> + <% rule_name = Internal.rules.ruleName(I18n.locale, rule.rule_key) %> <tr> <td class="key"> <%= message('rule') -%>: diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/rules/_show.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/rules/_show.html.erb index c4e6d9b174a..1d4a91542d3 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/rules/_show.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/rules/_show.html.erb @@ -19,9 +19,9 @@ <div class="modal-body rule_detail"> <% if @rule.description.strip.start_with?('<p>') %> - <%= MacroInterpreter.interpret_macro @rule.description %> + <%= Internal.text.interpretMacros(@rule.description) %> <% else %> - <p><%= MacroInterpreter.interpret_macro @rule.description %></p> + <p><%= Internal.text.interpretMacros(@rule.description) %></p> <% end %> <% if @rule.note && !@rule.note.text.strip.blank? %> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/rules/show.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/rules/show.html.erb index bbb02e8141f..ab37ce9e1df 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/rules/show.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/rules/show.html.erb @@ -17,9 +17,9 @@ <div class="rule_detail"> <% if @rule.description.strip.start_with?('<p>') %> - <%= MacroInterpreter.interpret_macro @rule.description %> + <%= Internal.text.interpretMacros(@rule.description) %> <% else %> - <p><%= MacroInterpreter.interpret_macro @rule.description %></p> + <p><%= Internal.text.interpretMacros(@rule.description) %></p> <% end %> <% if @rule.note && !@rule.note.text.strip.blank? %> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/rules_configuration/_rule_note.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/rules_configuration/_rule_note.html.erb index 86c598fc31b..cd389daecca 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/rules_configuration/_rule_note.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/rules_configuration/_rule_note.html.erb @@ -10,9 +10,9 @@ <div id="<%= note_detail_div_id -%>"> <div> <% if rule.description.strip.start_with?('<p>') %> - <%= MacroInterpreter.interpret_macro rule.description %> + <%= Internal.text.interpretMacros(rule.description) %> <% else %> - <p><%= MacroInterpreter.interpret_macro rule.description %></p> + <p><%= Internal.text.interpretMacros(rule.description) %></p> <% end %> </div> diff --git a/sonar-server/src/main/webapp/WEB-INF/lib/authenticated_system.rb b/sonar-server/src/main/webapp/WEB-INF/lib/authenticated_system.rb index dd97c70bac5..f8b17a9ac6a 100644 --- a/sonar-server/src/main/webapp/WEB-INF/lib/authenticated_system.rb +++ b/sonar-server/src/main/webapp/WEB-INF/lib/authenticated_system.rb @@ -13,8 +13,17 @@ module AuthenticatedSystem # Store the given user id in the session. def current_user=(new_user) - session[:user_id] = (new_user ? new_user.id : nil) - @current_user = new_user || false + # Do not use ruby symbols, else they can't be accessed from Java Servlet Filter + # (see UserSessionFilter + if new_user + session['user_id'] = new_user.id + session['login'] = new_user.login + @current_user = new_user + else + session['user_id'] = nil + session['login'] = nil + @current_user = false + end end # Check if the user is authorized @@ -107,7 +116,7 @@ module AuthenticatedSystem # Called from #current_user. First attempt to login by the user id stored in the session. def login_from_session - self.current_user = User.find_by_id(session[:user_id]) if session[:user_id] + self.current_user = User.find_by_id(session['user_id']) if session['user_id'] end # Called from #current_user. Now, attempt to login by basic authentication information. @@ -140,7 +149,11 @@ module AuthenticatedSystem @current_user.forget_me if @current_user.is_a? User @current_user = false # not logged in, and don't do it for me kill_remember_cookie! # Kill client-side auth cookie - session[:user_id] = nil # keeps the session but kill our variable + + # Do not use ruby symbols, else they can't be accessed from Java Servlet Filter + # (see UserSessionFilter) + session['user_id'] = nil # keeps the session but kill our variable + session['login'] = nil # keeps the session but kill our variable # explicitly kill any other session variables you set end diff --git a/sonar-server/src/main/webapp/WEB-INF/web.xml b/sonar-server/src/main/webapp/WEB-INF/web.xml index b2683b72a0c..55b93f2f7da 100644 --- a/sonar-server/src/main/webapp/WEB-INF/web.xml +++ b/sonar-server/src/main/webapp/WEB-INF/web.xml @@ -41,6 +41,10 @@ <filter-class>org.sonar.server.ui.DatabaseSessionFilter</filter-class> </filter> <filter> + <filter-name>UserSessionFilter</filter-name> + <filter-class>org.sonar.server.platform.UserSessionFilter</filter-class> + </filter> + <filter> <filter-name>RackFilter</filter-name> <filter-class>org.jruby.rack.RackFilter</filter-class> </filter> @@ -65,6 +69,10 @@ <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> + <filter-name>UserSessionFilter</filter-name> + <url-pattern>/*</url-pattern> + </filter-mapping> + <filter-mapping> <filter-name>ServletFilters</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> diff --git a/sonar-server/src/test/java/org/sonar/server/issue/DefaultJRubyIssuesTest.java b/sonar-server/src/test/java/org/sonar/server/issue/JRubyApiIssuesTest.java index 38b7d784aa6..b8468d72427 100644 --- a/sonar-server/src/test/java/org/sonar/server/issue/DefaultJRubyIssuesTest.java +++ b/sonar-server/src/test/java/org/sonar/server/issue/JRubyApiIssuesTest.java @@ -39,21 +39,20 @@ import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.*; -public class DefaultJRubyIssuesTest { +public class JRubyApiIssuesTest { IssueFinder finder = mock(IssueFinder.class); - ServerIssueActions changes = mock(ServerIssueActions.class); - DefaultJRubyIssues facade = new DefaultJRubyIssues(finder, changes); + JRubyApiIssues facade = new JRubyApiIssues(finder); @Test public void test_find() throws Exception { - facade.find(ImmutableMap.<String, Object>of("keys", Lists.newArrayList("ABCDE")), 123); + facade.find(ImmutableMap.<String, Object>of("keys", Lists.newArrayList("ABCDE"))); verify(finder).find(argThat(new ArgumentMatcher<IssueQuery>() { @Override public boolean matches(Object o) { return ((IssueQuery) o).keys().contains("ABCDE"); } - }), eq(123), eq(UserRole.CODEVIEWER)); + }), anyInt(), eq(UserRole.CODEVIEWER)); } @Test @@ -73,7 +72,7 @@ public class DefaultJRubyIssuesTest { map.put("pageSize", 10l); map.put("pageIndex", 50); - IssueQuery query = new DefaultJRubyIssues(finder, changes).toQuery(map); + IssueQuery query = new JRubyApiIssues(finder).toQuery(map); assertThat(query.keys()).containsOnly("ABCDE1234"); assertThat(query.severities()).containsOnly("MAJOR", "MINOR"); assertThat(query.statuses()).containsOnly("CLOSED"); @@ -91,20 +90,20 @@ public class DefaultJRubyIssuesTest { @Test public void should_parse_list_of_rules() { - assertThat(DefaultJRubyIssues.toRules(null)).isNull(); - assertThat(DefaultJRubyIssues.toRules("")).isEmpty(); - assertThat(DefaultJRubyIssues.toRules("squid:AvoidCycle")).containsOnly(RuleKey.of("squid", "AvoidCycle")); - assertThat(DefaultJRubyIssues.toRules("squid:AvoidCycle,findbugs:NullRef")).containsOnly(RuleKey.of("squid", "AvoidCycle"), RuleKey.of("findbugs", "NullRef")); - assertThat(DefaultJRubyIssues.toRules(asList("squid:AvoidCycle", "findbugs:NullRef"))).containsOnly(RuleKey.of("squid", "AvoidCycle"), RuleKey.of("findbugs", "NullRef")); + assertThat(JRubyApiIssues.toRules(null)).isNull(); + assertThat(JRubyApiIssues.toRules("")).isEmpty(); + assertThat(JRubyApiIssues.toRules("squid:AvoidCycle")).containsOnly(RuleKey.of("squid", "AvoidCycle")); + assertThat(JRubyApiIssues.toRules("squid:AvoidCycle,findbugs:NullRef")).containsOnly(RuleKey.of("squid", "AvoidCycle"), RuleKey.of("findbugs", "NullRef")); + assertThat(JRubyApiIssues.toRules(asList("squid:AvoidCycle", "findbugs:NullRef"))).containsOnly(RuleKey.of("squid", "AvoidCycle"), RuleKey.of("findbugs", "NullRef")); } @Test public void should_parse_list_of_strings() { - assertThat(DefaultJRubyIssues.toStrings(null)).isNull(); - assertThat(DefaultJRubyIssues.toStrings("")).isEmpty(); - assertThat(DefaultJRubyIssues.toStrings("foo")).containsOnly("foo"); - assertThat(DefaultJRubyIssues.toStrings("foo,bar")).containsOnly("foo", "bar"); - assertThat(DefaultJRubyIssues.toStrings(asList("foo", "bar"))).containsOnly("foo", "bar"); + assertThat(JRubyApiIssues.toStrings(null)).isNull(); + assertThat(JRubyApiIssues.toStrings("")).isEmpty(); + assertThat(JRubyApiIssues.toStrings("foo")).containsOnly("foo"); + assertThat(JRubyApiIssues.toStrings("foo,bar")).containsOnly("foo", "bar"); + assertThat(JRubyApiIssues.toStrings(asList("foo", "bar"))).containsOnly("foo", "bar"); } diff --git a/sonar-server/src/test/java/org/sonar/server/platform/UserSessionFilterTest.java b/sonar-server/src/test/java/org/sonar/server/platform/UserSessionFilterTest.java new file mode 100644 index 00000000000..55399dada36 --- /dev/null +++ b/sonar-server/src/test/java/org/sonar/server/platform/UserSessionFilterTest.java @@ -0,0 +1,107 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.platform; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.*; + +public class UserSessionFilterTest { + + @Before + public void setUp() { + // for test isolation + UserSession.set(null); + } + + @Test + public void should_load_user_session() throws Exception { + HttpSession httpSession = mock(HttpSession.class); + // JRuby sets a long but not an integer + when(httpSession.getAttribute("user_id")).thenReturn(123L); + when(httpSession.getAttribute("login")).thenReturn("karadoc"); + HttpServletRequest httpRequest = mock(HttpServletRequest.class); + when(httpRequest.getSession(true)).thenReturn(httpSession); + ServletResponse httpResponse = mock(ServletResponse.class); + + FilterChain chain = mock(FilterChain.class); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + assertThat(UserSession.get()).isNotNull(); + assertThat(UserSession.get().login()).isEqualTo("karadoc"); + assertThat(UserSession.get().userId()).isEqualTo(123); + assertThat(UserSession.get().isLoggedIn()).isTrue(); + return null; + } + }).when(chain).doFilter(httpRequest, httpResponse); + + UserSessionFilter filter = new UserSessionFilter(); + filter.doFilter(httpRequest, httpResponse, chain); + + verify(chain).doFilter(httpRequest, httpResponse); + } + + /** + * UserSession should always be set, even when end-user is not logged in. + */ + @Test + public void should_load_anonymous_session() throws Exception { + HttpSession httpSession = mock(HttpSession.class); + HttpServletRequest httpRequest = mock(HttpServletRequest.class); + when(httpRequest.getSession(true)).thenReturn(httpSession); + ServletResponse httpResponse = mock(ServletResponse.class); + + FilterChain chain = mock(FilterChain.class); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + assertThat(UserSession.get()).isNotNull(); + assertThat(UserSession.get().login()).isNull(); + assertThat(UserSession.get().userId()).isNull(); + assertThat(UserSession.get().isLoggedIn()).isFalse(); + return null; + } + }).when(chain).doFilter(httpRequest, httpResponse); + + UserSessionFilter filter = new UserSessionFilter(); + filter.doFilter(httpRequest, httpResponse, chain); + + verify(chain).doFilter(httpRequest, httpResponse); + } + + @Test + public void just_for_fun_and_coverage() throws Exception { + UserSessionFilter filter = new UserSessionFilter(); + filter.init(mock(FilterConfig.class)); + filter.destroy(); + // do not fail + } +} diff --git a/sonar-server/src/test/java/org/sonar/server/rule/DefaultJRubyRulesTest.java b/sonar-server/src/test/java/org/sonar/server/rule/JRubyRulesTest.java index 67820369694..ef68be157b7 100644 --- a/sonar-server/src/test/java/org/sonar/server/rule/DefaultJRubyRulesTest.java +++ b/sonar-server/src/test/java/org/sonar/server/rule/JRubyRulesTest.java @@ -28,15 +28,15 @@ import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class DefaultJRubyRulesTest { +public class JRubyRulesTest { - private DefaultJRubyRules defaultJRubyRules; + private JRubyRules JRubyRules; private JRubyI18n jRubyI18n; @Before public void before() { jRubyI18n = mock(JRubyI18n.class); - defaultJRubyRules = new DefaultJRubyRules(jRubyI18n); + JRubyRules = new JRubyRules(jRubyI18n); } @Test @@ -45,7 +45,7 @@ public class DefaultJRubyRulesTest { String locale = "en"; RuleKey ruleKey = RuleKey.of("squid", "AvoidCycle"); when(jRubyI18n.getRuleName(locale, "squid", "AvoidCycle")).thenReturn(ruleName); - assertThat(defaultJRubyRules.ruleName(locale, ruleKey)).isEqualTo(ruleName); + assertThat(JRubyRules.ruleName(locale, ruleKey)).isEqualTo(ruleName); } @Test @@ -54,7 +54,7 @@ public class DefaultJRubyRulesTest { RuleKey ruleKey = RuleKey.of("squid", "AvoidCycle"); when(jRubyI18n.getRuleName("fr", "squid", "AvoidCycle")).thenReturn(null); when(jRubyI18n.getRuleName("en", "squid", "AvoidCycle")).thenReturn(englishRuleName); - assertThat(defaultJRubyRules.ruleName("fr", ruleKey)).isEqualTo(englishRuleName); + assertThat(JRubyRules.ruleName("fr", ruleKey)).isEqualTo(englishRuleName); } } diff --git a/sonar-server/src/test/java/org/sonar/server/text/JRubyTextTest.java b/sonar-server/src/test/java/org/sonar/server/text/JRubyTextTest.java new file mode 100644 index 00000000000..feb71d9972d --- /dev/null +++ b/sonar-server/src/test/java/org/sonar/server/text/JRubyTextTest.java @@ -0,0 +1,59 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.text; + +import org.junit.Test; +import org.sonar.core.source.HtmlSourceDecorator; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.*; + +public class JRubyTextTest { + + MacroInterpreter macroInterpreter = mock(MacroInterpreter.class); + HtmlSourceDecorator sourceDecorator = mock(HtmlSourceDecorator.class); + JRubyText text = new JRubyText(macroInterpreter, sourceDecorator); + + @Test + public void interpretMacros() throws Exception { + text.interpretMacros("text with macros"); + verify(macroInterpreter, times(1)).interpret("text with macros"); + verifyZeroInteractions(sourceDecorator); + } + + @Test + public void markdownToHtml() throws Exception { + String html = text.markdownToHtml("some *markdown*"); + assertThat(html).isEqualTo("some <em>markdown</em>"); + } + + @Test + public void should_escape_markdown_input() throws Exception { + String html = text.markdownToHtml("a > b"); + assertThat(html).isEqualTo("a > b"); + } + + @Test + public void highlightedSourceLines() throws Exception { + text.highlightedSourceLines(123L); + verify(sourceDecorator, times(1)).getDecoratedSourceAsHtml(123L); + verifyZeroInteractions(macroInterpreter); + } +} diff --git a/sonar-server/src/test/java/org/sonar/server/ui/MacroInterpreterTest.java b/sonar-server/src/test/java/org/sonar/server/text/MacroInterpreterTest.java index 218fee698be..b23f84c0741 100644 --- a/sonar-server/src/test/java/org/sonar/server/ui/MacroInterpreterTest.java +++ b/sonar-server/src/test/java/org/sonar/server/text/MacroInterpreterTest.java @@ -18,11 +18,10 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.sonar.server.ui; +package org.sonar.server.text; import org.junit.Before; import org.junit.Test; -import org.sonar.server.macro.MacroInterpreter; import javax.servlet.ServletContext; @@ -32,12 +31,11 @@ import static org.mockito.Mockito.when; public class MacroInterpreterTest { - private MacroInterpreter interpreter; - private String path; + String path = "http://sonar"; + MacroInterpreter interpreter; @Before - public void before() { - path = "http://sonar"; + public void setUp() { ServletContext servletContext = mock(ServletContext.class); when(servletContext.getContextPath()).thenReturn(path); interpreter = new MacroInterpreter(servletContext); @@ -46,16 +44,6 @@ public class MacroInterpreterTest { @Test public void should_do_nothing_if_no_macro_detected() { String origin = "nothing to do"; - interpreter.start(); - String result = interpreter.interpret(origin); - assertThat(result).isEqualTo(origin); - } - - @Test - public void should_do_nothing_if_not_started() { - String ruleKey = "repo:key"; - String origin = "{rule:"+ ruleKey + "}"; - String result = interpreter.interpret(origin); assertThat(result).isEqualTo(origin); } @@ -63,18 +51,16 @@ public class MacroInterpreterTest { @Test public void should_replace_rule_macro() { String ruleKey = "repo:key"; - String origin = "See {rule:"+ ruleKey + "} for detail."; - interpreter.start(); + String origin = "See {rule:" + ruleKey + "} for detail."; String result = interpreter.interpret(origin); - assertThat(result).isEqualTo("See <a class='open-modal rule-modal' modal-width='800' href='"+ path + "/rules/show/"+ ruleKey + "?modal=true&layout=false'>" + ruleKey +"</a> for detail."); + assertThat(result).isEqualTo("See <a class='open-modal rule-modal' modal-width='800' href='" + path + "/rules/show/" + ruleKey + "?modal=true&layout=false'>" + ruleKey + "</a> for detail."); } @Test public void should_replace_rule_macro_containing_digit_and_dash() { String ruleKey = "my-repo1:my-key1"; - String origin = "See {rule:"+ ruleKey + "} for detail."; - interpreter.start(); + String origin = "See {rule:" + ruleKey + "} for detail."; String result = interpreter.interpret(origin); - assertThat(result).isEqualTo("See <a class='open-modal rule-modal' modal-width='800' href='"+ path + "/rules/show/"+ ruleKey + "?modal=true&layout=false'>" + ruleKey +"</a> for detail."); + assertThat(result).isEqualTo("See <a class='open-modal rule-modal' modal-width='800' href='" + path + "/rules/show/" + ruleKey + "?modal=true&layout=false'>" + ruleKey + "</a> for detail."); } } diff --git a/sonar-server/src/test/java/org/sonar/server/ui/JRubyFacadesTest.java b/sonar-server/src/test/java/org/sonar/server/ui/JRubyFacadesTest.java deleted file mode 100644 index c4b34d7a4e3..00000000000 --- a/sonar-server/src/test/java/org/sonar/server/ui/JRubyFacadesTest.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2013 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.server.ui; - -import org.junit.Test; -import org.sonar.server.issue.DefaultJRubyIssues; - -import static org.fest.assertions.Assertions.assertThat; -import static org.mockito.Mockito.mock; - -public class JRubyFacadesTest { - - @Test - public void register_issues_facade_on_creation() throws Exception { - DefaultJRubyIssues issues = mock(DefaultJRubyIssues.class); - JRubyFacades.setIssues(issues); - assertThat(JRubyFacades.issues()).isSameAs(issues); - } -} |