Hey,

here is a small feature patch that allows users to choose semicolon (";") as an
alternative to comma (",") for the delimiter in all downloadable CSV files that
we generate from the webapp. This seems to be helpful for importing those files
into MS Excel for example.

Unfortunately we had to hack the schema source sanity check in order to not
complain about a ";" in the middle of a table definition.

I hope you like the idea and the patch as well, let me know what you think.

Thanks,
Johannes

-- 
SUSE LINUX Products GmbH, HRB 16746 (AG Nürnberg)
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer
>From 7a446a37f1582321f432d097bd3dabdac8ecb9a2 Mon Sep 17 00:00:00 2001
From: Johannes Renner <jren...@suse.de>
Date: Mon, 19 Aug 2013 13:31:35 +0200
Subject: [PATCH 1/3] Allow users to change the CSV separator (schema changes)

---
 schema/spacewalk/common/tables/rhnUserInfo.sql          |  6 +++++-
 .../014-add-column-csv-separator.sql.oracle             | 16 ++++++++++++++++
 .../014-add-column-csv-separator.sql.postgresql         | 17 +++++++++++++++++
 3 files changed, 38 insertions(+), 1 deletion(-)
 create mode 100644 schema/spacewalk/upgrade/spacewalk-schema-2.0-to-spacewalk-schema-2.1/014-add-column-csv-separator.sql.oracle
 create mode 100644 schema/spacewalk/upgrade/spacewalk-schema-2.0-to-spacewalk-schema-2.1/014-add-column-csv-separator.sql.postgresql

diff --git a/schema/spacewalk/common/tables/rhnUserInfo.sql b/schema/spacewalk/common/tables/rhnUserInfo.sql
index 50989ad..005c840 100644
--- a/schema/spacewalk/common/tables/rhnUserInfo.sql
+++ b/schema/spacewalk/common/tables/rhnUserInfo.sql
@@ -63,7 +63,11 @@ CREATE TABLE rhnUserInfo
                                 DEFAULT (current_timestamp) NOT NULL,
     modified                timestamp with local time zone
                                 DEFAULT (current_timestamp) NOT NULL,
-    preferred_locale        VARCHAR2(8)
+    preferred_locale        VARCHAR2(8),
+    csv_separator           CHAR(1)
+                                DEFAULT (',') NOT NULL
+                                CONSTRAINT rhn_user_info_csv_ck
+                                    CHECK (csv_separator in (',',';'))
 )
 ENABLE ROW MOVEMENT
 ;
diff --git a/schema/spacewalk/upgrade/spacewalk-schema-2.0-to-spacewalk-schema-2.1/014-add-column-csv-separator.sql.oracle b/schema/spacewalk/upgrade/spacewalk-schema-2.0-to-spacewalk-schema-2.1/014-add-column-csv-separator.sql.oracle
new file mode 100644
index 0000000..2b1c796
--- /dev/null
+++ b/schema/spacewalk/upgrade/spacewalk-schema-2.0-to-spacewalk-schema-2.1/014-add-column-csv-separator.sql.oracle
@@ -0,0 +1,16 @@
+--
+-- Copyright (c) 2013 SUSE
+--
+-- This software is licensed to you under the GNU General Public License,
+-- version 2 (GPLv2). There is NO WARRANTY for this software, express or
+-- implied, including the implied warranties of MERCHANTABILITY or FITNESS
+-- FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
+-- along with this software; if not, see
+-- http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+--
+
+-- Create new column for rhnUserInfo
+ALTER TABLE rhnUserInfo ADD csv_separator CHAR(1) DEFAULT (',') NOT NULL
+    CONSTRAINT rhn_user_info_csv_ck
+        CHECK (csv_separator in (',',';'));
+
diff --git a/schema/spacewalk/upgrade/spacewalk-schema-2.0-to-spacewalk-schema-2.1/014-add-column-csv-separator.sql.postgresql b/schema/spacewalk/upgrade/spacewalk-schema-2.0-to-spacewalk-schema-2.1/014-add-column-csv-separator.sql.postgresql
new file mode 100644
index 0000000..588b614
--- /dev/null
+++ b/schema/spacewalk/upgrade/spacewalk-schema-2.0-to-spacewalk-schema-2.1/014-add-column-csv-separator.sql.postgresql
@@ -0,0 +1,17 @@
+-- oracle equivalent source sha1 cfee4377c397d6a17de0fbbce988af873d88ec01
+--
+-- Copyright (c) 2013 SUSE
+--
+-- This software is licensed to you under the GNU General Public License,
+-- version 2 (GPLv2). There is NO WARRANTY for this software, express or
+-- implied, including the implied warranties of MERCHANTABILITY or FITNESS
+-- FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
+-- along with this software; if not, see
+-- http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+--
+
+-- Create new column for rhnUserInfo
+ALTER TABLE rhnUserInfo ADD csv_separator CHAR(1) DEFAULT (',') NOT NULL
+    CONSTRAINT rhn_user_info_csv_ck
+        CHECK (csv_separator in (',',';'));
+
-- 
1.8.1.4

>From 49e2881bf54bb0273c85b9093587df3894a5576a Mon Sep 17 00:00:00 2001
From: Johannes Renner <jren...@suse.de>
Date: Mon, 19 Aug 2013 14:02:18 +0200
Subject: [PATCH 2/3] Allow users to change the CSV separator

---
 java/code/src/com/redhat/rhn/common/util/CSVWriter.java | 17 ++++++++++++++---
 java/code/src/com/redhat/rhn/domain/user/User.java      | 12 ++++++++++++
 .../src/com/redhat/rhn/domain/user/legacy/UserImpl.java | 10 ++++++++++
 .../com/redhat/rhn/domain/user/legacy/UserInfo.hbm.xml  |  1 +
 .../src/com/redhat/rhn/domain/user/legacy/UserInfo.java | 17 +++++++++++++++++
 .../redhat/rhn/frontend/action/CSVDownloadAction.java   |  6 +++++-
 .../action/systems/monitoring/ProbeGraphAction.java     |  6 +++---
 .../redhat/rhn/frontend/action/user/UserPrefAction.java |  1 +
 .../rhn/frontend/action/user/UserPrefSetupAction.java   |  1 +
 .../rhn/frontend/strings/jsp/StringResource_en_US.xml   | 12 ++++++++++++
 .../pages/common/fragments/user/preferences.jspf        |  9 +++++++++
 java/code/webapp/WEB-INF/struts-config.xml              |  1 +
 12 files changed, 86 insertions(+), 7 deletions(-)

diff --git a/java/code/src/com/redhat/rhn/common/util/CSVWriter.java b/java/code/src/com/redhat/rhn/common/util/CSVWriter.java
index c0267ea..f1e30f1 100644
--- a/java/code/src/com/redhat/rhn/common/util/CSVWriter.java
+++ b/java/code/src/com/redhat/rhn/common/util/CSVWriter.java
@@ -37,6 +37,7 @@ public class CSVWriter extends BufferedWriter implements ExportWriter {
     private List <String> columns;
     private Writer contents;
     private String headerText;
+    private char separatorChar = ',';
 
     /**
      * Constructor
@@ -49,6 +50,16 @@ public class CSVWriter extends BufferedWriter implements ExportWriter {
     }
 
     /**
+     * Constructor
+     * @param out Writer to send CSV to
+     * @param separator Separator character to use
+     */
+    public CSVWriter(Writer out, char separator) {
+        this(out);
+        this.separatorChar = separator;
+    }
+
+    /**
      * Set columns
      * @param columnsIn List of Strings containing the names of the columns
      */
@@ -78,7 +89,7 @@ public class CSVWriter extends BufferedWriter implements ExportWriter {
         String hdrStr = headerText;
         if (hdrStr != null) {
             for (int i = 0; i < columns.size() - 1; i++) {
-                hdrStr += ",";
+                hdrStr += separatorChar;
             }
         }
         return hdrStr;
@@ -210,7 +221,7 @@ public class CSVWriter extends BufferedWriter implements ExportWriter {
      */
     public void write(String s) throws IOException {
         // If the string does not contain a comma, just write it out
-        if (s.indexOf(",") == -1 && s.indexOf("\"") == -1) {
+        if (s.indexOf(separatorChar) == -1 && s.indexOf("\"") == -1) {
             super.write(s);
             return;
         }
@@ -240,7 +251,7 @@ public class CSVWriter extends BufferedWriter implements ExportWriter {
      * @throws IOException if there is a Writer error
      */
     public void writeSeparator() throws IOException {
-        super.write(",");
+        super.write(separatorChar);
     }
 
     /**
diff --git a/java/code/src/com/redhat/rhn/domain/user/User.java b/java/code/src/com/redhat/rhn/domain/user/User.java
index 8c911f2..ee8148f 100644
--- a/java/code/src/com/redhat/rhn/domain/user/User.java
+++ b/java/code/src/com/redhat/rhn/domain/user/User.java
@@ -506,6 +506,18 @@ public interface User {
     int getEmailNotify();
 
     /**
+     * Sets the current value of csvSeparator
+     * @param csvSeparatorIn New value for csvSeparator
+     */
+    void setCsvSeparator(char csvSeparatorIn);
+
+    /**
+     * Gets the current value of csvSeparator
+     * @return char the current value
+     */
+    char getCsvSeparator();
+
+    /**
      * Retrieves the set of server groups associated
      * to this user.
      * Note: this is NOT getAllServerGroups
diff --git a/java/code/src/com/redhat/rhn/domain/user/legacy/UserImpl.java b/java/code/src/com/redhat/rhn/domain/user/legacy/UserImpl.java
index 2e1c110..e5c83c4 100644
--- a/java/code/src/com/redhat/rhn/domain/user/legacy/UserImpl.java
+++ b/java/code/src/com/redhat/rhn/domain/user/legacy/UserImpl.java
@@ -438,6 +438,16 @@ public class UserImpl extends BaseDomainHelper implements User {
         return this.userInfo.getPreferredLocale();
     }
 
+    /** {@inheritDoc} */
+    public void setCsvSeparator(char csvSeparator) {
+        this.userInfo.setCsvSeparator(csvSeparator);
+    }
+
+    /** {@inheritDoc} */
+    public char getCsvSeparator() {
+        return this.userInfo.getCsvSeparator();
+    }
+
     /********* PersonalInfo Methods **********/
 
     /**
diff --git a/java/code/src/com/redhat/rhn/domain/user/legacy/UserInfo.hbm.xml b/java/code/src/com/redhat/rhn/domain/user/legacy/UserInfo.hbm.xml
index 5e194ff..e492243 100644
--- a/java/code/src/com/redhat/rhn/domain/user/legacy/UserInfo.hbm.xml
+++ b/java/code/src/com/redhat/rhn/domain/user/legacy/UserInfo.hbm.xml
@@ -19,6 +19,7 @@ PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
         <property name="created" type="timestamp" insert="false" update="false" />
         <property name="modified" type="timestamp" insert="false" update="false" />
         <property name="preferredLocale" column="preferred_locale" type="string" />
+        <property name="csvSeparator" column="csv_separator" type="char" />
 
         <many-to-one name="timeZone" column="timezone_id"
 			class="com.redhat.rhn.domain.user.RhnTimeZone" cascade="none" />
diff --git a/java/code/src/com/redhat/rhn/domain/user/legacy/UserInfo.java b/java/code/src/com/redhat/rhn/domain/user/legacy/UserInfo.java
index 9b64693..30554c9 100644
--- a/java/code/src/com/redhat/rhn/domain/user/legacy/UserInfo.java
+++ b/java/code/src/com/redhat/rhn/domain/user/legacy/UserInfo.java
@@ -34,6 +34,7 @@ public class UserInfo extends AbstractUserChild {
     private Date lastLoggedIn;
     private RhnTimeZone timeZone;
     private User user;
+    private char csvSeparator;
 
     /**
      * Create a new empty user
@@ -161,4 +162,20 @@ public class UserInfo extends AbstractUserChild {
     public void setEmailNotify(int emailNotifyIn) {
         this.emailNotify = emailNotifyIn;
     }
+
+    /**
+     * Getter for csvSeparator
+     * @return the csvSeparator
+     */
+    public char getCsvSeparator() {
+        return csvSeparator;
+    }
+
+    /**
+     * Setter for csvSeparator
+     * @param csvSeparatorIn the csvSeparator to set
+     */
+    public void setCsvSeparator(char csvSeparatorIn) {
+        this.csvSeparator = csvSeparatorIn;
+    }
 }
diff --git a/java/code/src/com/redhat/rhn/frontend/action/CSVDownloadAction.java b/java/code/src/com/redhat/rhn/frontend/action/CSVDownloadAction.java
index ac0110f..1d8b3f6 100644
--- a/java/code/src/com/redhat/rhn/frontend/action/CSVDownloadAction.java
+++ b/java/code/src/com/redhat/rhn/frontend/action/CSVDownloadAction.java
@@ -19,8 +19,10 @@ import com.redhat.rhn.common.db.datasource.DataResult;
 import com.redhat.rhn.common.db.datasource.Elaborator;
 import com.redhat.rhn.common.util.CSVWriter;
 import com.redhat.rhn.common.util.download.ByteArrayStreamInfo;
+import com.redhat.rhn.domain.user.User;
 import com.redhat.rhn.frontend.dto.SystemSearchPartialResult;
 import com.redhat.rhn.frontend.dto.SystemSearchResult;
+import com.redhat.rhn.frontend.struts.RequestContext;
 import com.redhat.rhn.frontend.taglibs.list.TagHelper;
 
 import org.apache.struts.action.ActionForm;
@@ -191,7 +193,9 @@ public class CSVDownloadAction extends DownloadAction {
         String exportColumns = getExportColumns(request, session);
         List pageData = getPageData(request, session);
 
-        CSVWriter expW = new CSVWriter(new StringWriter());
+        // Read the CSV separator from user preferences
+        User user = new RequestContext(request).getCurrentUser();
+        CSVWriter expW = new CSVWriter(new StringWriter(), user.getCsvSeparator());
         String[] columns  = exportColumns.split("\\s*,\\s*");
         expW.setColumns(Arrays.asList(columns));
 
diff --git a/java/code/src/com/redhat/rhn/frontend/action/systems/monitoring/ProbeGraphAction.java b/java/code/src/com/redhat/rhn/frontend/action/systems/monitoring/ProbeGraphAction.java
index 473abfa..f47efcd 100644
--- a/java/code/src/com/redhat/rhn/frontend/action/systems/monitoring/ProbeGraphAction.java
+++ b/java/code/src/com/redhat/rhn/frontend/action/systems/monitoring/ProbeGraphAction.java
@@ -84,7 +84,7 @@ public class ProbeGraphAction extends BaseProbeAction {
                 startts, endts);
 
         if (rctx.isRequestedExport()) {
-            writeExport(tsdList, resp, metrics);
+            writeExport(tsdList, resp, metrics, rctx.getCurrentUser().getCsvSeparator());
         }
         else {
             writeGraph(tsdList, resp, req, metrics, startts, endts);
@@ -128,7 +128,7 @@ public class ProbeGraphAction extends BaseProbeAction {
     }
 
     private void writeExport(List tsdList, HttpServletResponse resp,
-            String[] metrics) throws IOException {
+            String[] metrics, char separator) throws IOException {
         Iterator i = tsdList.iterator();
         while (i.hasNext()) {
             TimeSeriesData[] tsdarr = (TimeSeriesData[]) i.next();
@@ -138,7 +138,7 @@ public class ProbeGraphAction extends BaseProbeAction {
             columns.add("data");
             columns.add("time");
             columns.add("metric");
-            ExportWriter ew = new CSVWriter(new StringWriter());
+            ExportWriter ew = new CSVWriter(new StringWriter(), separator);
             ew.setColumns(columns);
             ServletExportHandler seh = new ServletExportHandler(ew);
             seh.writeExporterToOutput(resp, dtoList);
diff --git a/java/code/src/com/redhat/rhn/frontend/action/user/UserPrefAction.java b/java/code/src/com/redhat/rhn/frontend/action/user/UserPrefAction.java
index b8ddf91..eb24fbb 100644
--- a/java/code/src/com/redhat/rhn/frontend/action/user/UserPrefAction.java
+++ b/java/code/src/com/redhat/rhn/frontend/action/user/UserPrefAction.java
@@ -63,6 +63,7 @@ public class UserPrefAction extends RhnAction {
         user.setEmailNotify(BooleanUtils.toInteger((Boolean) form
                 .get("emailNotif"), 1, 0, 0));
         user.setPageSize(getAsInt(form, "pagesize", 5));
+        user.setCsvSeparator((Character) form.get("csvSeparator"));
 
         handlePanes(form, user);
 
diff --git a/java/code/src/com/redhat/rhn/frontend/action/user/UserPrefSetupAction.java b/java/code/src/com/redhat/rhn/frontend/action/user/UserPrefSetupAction.java
index addcfc4..dffffed 100644
--- a/java/code/src/com/redhat/rhn/frontend/action/user/UserPrefSetupAction.java
+++ b/java/code/src/com/redhat/rhn/frontend/action/user/UserPrefSetupAction.java
@@ -74,6 +74,7 @@ public class UserPrefSetupAction extends RhnAction {
                 .getEmailNotify()));
 
         form.set("pagesize", new Integer(user.getPageSize()));
+        form.set("csvSeparator", user.getCsvSeparator());
 
         setupTasks(form, user);
         request.setAttribute("pagesizes", getPageSizes());
diff --git a/java/code/src/com/redhat/rhn/frontend/strings/jsp/StringResource_en_US.xml b/java/code/src/com/redhat/rhn/frontend/strings/jsp/StringResource_en_US.xml
index 400a089..76782da 100644
--- a/java/code/src/com/redhat/rhn/frontend/strings/jsp/StringResource_en_US.xml
+++ b/java/code/src/com/redhat/rhn/frontend/strings/jsp/StringResource_en_US.xml
@@ -1032,6 +1032,18 @@
           <context context-type="sourcefile">/rhn/users/UserPreferences</context>
         </context-group>
       </trans-unit>
+      <trans-unit id="preferences.jsp.csvtitle">
+        <source>CSV Files</source>
+      </trans-unit>
+      <trans-unit id="preferences.jsp.csvdesc">
+        <source>Configure a separator character to be used in downloadable CSV files:</source>
+      </trans-unit>
+      <trans-unit id="preferences.jsp.csvcomma">
+        <source>Comma (",", default)</source>
+      </trans-unit>
+      <trans-unit id="preferences.jsp.csvsemicolon">
+        <source>Semicolon (";", compatible with Microsoft&#174; Excel&#174;)</source>
+      </trans-unit>
       <trans-unit id="preferences.jsp.submitvalue">
         <source>Save Preferences</source>
         <context-group name="ctx">
diff --git a/java/code/webapp/WEB-INF/pages/common/fragments/user/preferences.jspf b/java/code/webapp/WEB-INF/pages/common/fragments/user/preferences.jspf
index a1bcddb..498ae0d 100644
--- a/java/code/webapp/WEB-INF/pages/common/fragments/user/preferences.jspf
+++ b/java/code/webapp/WEB-INF/pages/common/fragments/user/preferences.jspf
@@ -29,6 +29,15 @@
 </c:forEach>
 </div>
 
+<h2><bean:message key="preferences.jsp.csvtitle" /></h2>
+<p><bean:message key="preferences.jsp.csvdesc" /></p>
+<div class="preference">
+  <html:radio property="csvSeparator" value="," styleId="radio-comma" />
+  <label for="radio-comma"><bean:message key="preferences.jsp.csvcomma" /></label><br />
+  <html:radio property="csvSeparator" value=";" styleId="radio-semicolon" />
+  <label for="radio-semicolon"><bean:message key="preferences.jsp.csvsemicolon" /></label>
+</div>
+
     <input type="hidden" name="pxt:trap" value="rhn:user_prefs_edit_cb" />
     <html:hidden property="uid" />
 
diff --git a/java/code/webapp/WEB-INF/struts-config.xml b/java/code/webapp/WEB-INF/struts-config.xml
index c620467..0006141 100644
--- a/java/code/webapp/WEB-INF/struts-config.xml
+++ b/java/code/webapp/WEB-INF/struts-config.xml
@@ -175,6 +175,7 @@
             <form-property name="possiblePanes"
                            type="org.apache.struts.util.LabelValueBean[]"/>
             <form-property name="selectedPanes" type="java.lang.String[]"/>
+            <form-property name="csvSeparator" type="java.lang.Character"/>
         </form-bean>
         <form-bean name="assignedDefSysGrpForm"
                    type="com.redhat.rhn.frontend.struts.ScrubbingDynaActionForm">
-- 
1.8.1.4

>From 6e6c7992711c9222a685148fd58f49805406d262 Mon Sep 17 00:00:00 2001
From: Johannes Renner <jren...@suse.de>
Date: Mon, 19 Aug 2013 13:35:05 +0200
Subject: [PATCH 3/3] Add a hack to allow the ';' literal in table definitions

---
 schema/spacewalk/schema-source-sanity-check.pl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/schema/spacewalk/schema-source-sanity-check.pl b/schema/spacewalk/schema-source-sanity-check.pl
index 4ebca65..2a79bdb 100644
--- a/schema/spacewalk/schema-source-sanity-check.pl
+++ b/schema/spacewalk/schema-source-sanity-check.pl
@@ -83,7 +83,7 @@ sub check_file_content {
 		}
 		if (not $content =~ /^(--.*\n
 					|\s*\n
-					|(create|alter|comment\s+on)\s+table\s+$name\b[^;]+;
+					|(create|alter|comment\s+on)\s+table\s+$name\b(?:[^;]|';')+;
 					|create\s+(unique\s+)?index\s+\w+\s+on\s+$name[^;]+;
 					|create\s+sequence[^;]+;
 					|comment\s+on\s+column\s+$name\.[^;]+;
-- 
1.8.1.4

_______________________________________________
Spacewalk-devel mailing list
Spacewalk-devel@redhat.com
https://www.redhat.com/mailman/listinfo/spacewalk-devel

Reply via email to