Implement a Template-Foreach (and use in "new email certificate")
authorFelix Dörre <felix@dogcraft.de>
Sat, 12 Jul 2014 14:40:03 +0000 (16:40 +0200)
committerFelix Dörre <felix@dogcraft.de>
Sat, 12 Jul 2014 14:40:03 +0000 (16:40 +0200)
doc/TemplateSyntax.txt
src/org/cacert/gigi/output/template/ForeachStatement.java [new file with mode: 0644]
src/org/cacert/gigi/output/template/IterableDataset.java [new file with mode: 0644]
src/org/cacert/gigi/output/template/Template.java
src/org/cacert/gigi/pages/account/MailCertificateAdd.java
src/org/cacert/gigi/pages/account/MailCertificateAdd.templ

index 3b4a07ca1c0f1962b248be2e7fee91edde56bb5d..ab4cc37d37060a2e0b229629bf70df791df0a1c8 100644 (file)
@@ -12,3 +12,10 @@ A template is constructed from a charstream. Everything that is not in "<?" to "
 - <? if($variable) { ?>
   Output/execute the text until "<? } ?>" only if $variable is boolean and true.
   
+- <? foreach($variable) { ?>
+  If $variable is an "IterableDataset"
+  Output/execute the text until "<? } ?>" repeated as $variable suggests. 
+  Special variables that $variable defines can be used in the inner text.
+  
+  
\ No newline at end of file
diff --git a/src/org/cacert/gigi/output/template/ForeachStatement.java b/src/org/cacert/gigi/output/template/ForeachStatement.java
new file mode 100644 (file)
index 0000000..0b3c526
--- /dev/null
@@ -0,0 +1,30 @@
+package org.cacert.gigi.output.template;
+
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.cacert.gigi.Language;
+import org.cacert.gigi.output.Outputable;
+
+final class ForeachStatement implements Outputable {
+       private final String variable;
+       private final TemplateBlock body;
+
+       ForeachStatement(String variable, TemplateBlock body) {
+               this.variable = variable;
+               this.body = body;
+       }
+
+       @Override
+       public void output(PrintWriter out, Language l, Map<String, Object> vars) {
+               Object o = vars.get(variable);
+               if (o instanceof IterableDataset) {
+                       IterableDataset id = (IterableDataset) o;
+                       Map<String, Object> subcontext = new HashMap<String, Object>(vars);
+                       while (id.next(subcontext)) {
+                               body.output(out, l, subcontext);
+                       }
+               }
+       }
+}
\ No newline at end of file
diff --git a/src/org/cacert/gigi/output/template/IterableDataset.java b/src/org/cacert/gigi/output/template/IterableDataset.java
new file mode 100644 (file)
index 0000000..d908fcc
--- /dev/null
@@ -0,0 +1,19 @@
+package org.cacert.gigi.output.template;
+
+import java.util.Map;
+
+/**
+ * Represents some kind of data, that may be iterated over in a template.
+ */
+public interface IterableDataset {
+       /**
+        * Moves to the next Dataset.
+        * 
+        * @param vars
+        *            the variables used in this template. They need to be updated
+        *            for each line.
+        * @return true, iff there was a data-line "installed". False of this set is
+        *         already empty.
+        */
+       public boolean next(Map<String, Object> vars);
+}
index bfff646f8fe833164ea30e6129275828045c7b24..5a82cf7d81151799aa1c29e87a0997a756d62f25 100644 (file)
@@ -24,7 +24,7 @@ public class Template implements Outputable {
        long lastLoaded;
        File source;
 
-       private static final Pattern IF_PATTERN = Pattern.compile(" ?if\\(\\$([^)]+)\\) ?\\{ ?");
+       private static final Pattern CONTROL_PATTERN = Pattern.compile(" ?([a-z]+)\\(\\$([^)]+)\\) ?\\{ ?");
 
        public Template(URL u) {
                try {
@@ -79,11 +79,18 @@ public class Template implements Outputable {
                        buf.delete(buf.length() - 2, buf.length());
                        String com = buf.toString().replace("\n", "");
                        buf.delete(0, buf.length());
-                       Matcher m = IF_PATTERN.matcher(com);
+                       Matcher m = CONTROL_PATTERN.matcher(com);
                        if (m.matches()) {
-                               final String variable = m.group(1);
-                               final TemplateBlock body = parse(r);
-                               commands.add(new IfStatement(variable, body));
+                               String type = m.group(1);
+                               String variable = m.group(2);
+                               TemplateBlock body = parse(r);
+                               if (type.equals("if")) {
+                                       commands.add(new IfStatement(variable, body));
+                               } else if (type.equals("foreach")) {
+                                       commands.add(new ForeachStatement(variable, body));
+                               } else {
+                                       throw new IOException("Syntax error: unknown control structure: " + type);
+                               }
                                continue;
                        }
                        if (com.matches(" ?\\} ?")) {
index 836f48c4f13c1ff1e035ff5a9f7accb4d20ee1e8..769f9e1ad0d8aaf60de7f1d2ef7fedd744ff7403 100644 (file)
@@ -2,14 +2,20 @@ package org.cacert.gigi.pages.account;
 
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.HashMap;
+import java.util.Map;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.cacert.gigi.Certificate;
+import org.cacert.gigi.User;
+import org.cacert.gigi.database.DatabaseConnection;
 import org.cacert.gigi.output.ClientCSRGenerate;
+import org.cacert.gigi.output.template.IterableDataset;
 import org.cacert.gigi.pages.LoginPage;
 import org.cacert.gigi.pages.Page;
 
@@ -24,7 +30,35 @@ public class MailCertificateAdd extends Page {
        public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
                HashMap<String, Object> vars = new HashMap<String, Object>();
                vars.put("CCA", "<a href='/policy/CAcertCommunityAgreement.html'>CCA</a>");
-               getDefaultTemplate().output(resp.getWriter(), getLanguage(req), vars);
+
+               User u = LoginPage.getUser(req);
+               try {
+                       PreparedStatement ps = DatabaseConnection.getInstance().prepare(
+                               "SELECT `id`,`email` from `email` WHERE `memid`=? AND `deleted`=0");
+                       ps.setInt(1, u.getId());
+                       final ResultSet rs = ps.executeQuery();
+                       vars.put("emails", new IterableDataset() {
+
+                               @Override
+                               public boolean next(Map<String, Object> vars) {
+                                       try {
+                                               if (!rs.next()) {
+                                                       return false;
+                                               }
+                                               vars.put("id", rs.getString(1));
+                                               vars.put("value", rs.getString(2));
+                                               return true;
+                                       } catch (SQLException e) {
+                                               e.printStackTrace();
+                                       }
+                                       return false;
+                               }
+                       });
+                       getDefaultTemplate().output(resp.getWriter(), getLanguage(req), vars);
+                       rs.close();
+               } catch (SQLException e) {
+                       e.printStackTrace();
+               }
        }
 
        @Override
index 51a7e6958f73fa262a4aea09a02db2d7fbe6ef77..6ce1b15b1597fe104570f4b62d3cc3f4300cfe09 100644 (file)
     <td><?=_Add?></td>
     <td><?=_Address?></td>
   </tr>
-<!-- For each mail -->
+<? foreach($emails) { ?>
   <tr>
-    <td><input type="checkbox" id="addid<=intval($row['id'])>" name="addid[]" value="<=intval($row['id'])>"></td>
-    <td align="left"><label for="addid<=intval($row['id'])>"><=sanitizeHTML($row['email'])></label></td>
+    <td><input type="checkbox" id="addid<?=$id?>" name="addid[]" value="<?=$id?>"></td>
+    <td align="left"><label for="addid<?=$id?>"><?=$value?></label></td>
   </tr>
-<!-- For each mail -->
+<? } ?>
+
 <? if($points50) { ?>
   <tr>
     <td colspan="2" align="left">