Browse Source

Merge branch 'main' into lang_de, working on further translations

lang_de
Stephan Richter 2 years ago
parent
commit
b6e33c2119
  1. 2
      pom.xml
  2. 4
      src/main/java/de/srsoftware/widerhall/Configuration.java
  3. 22
      src/main/java/de/srsoftware/widerhall/web/Rest.java
  4. 8
      src/main/java/de/srsoftware/widerhall/web/TemplateServlet.java
  5. 80
      src/main/java/de/srsoftware/widerhall/web/Web.java
  6. 6
      src/test/java/de/srsoftware/widerhall/data/DatabaseTest.java
  7. 24
      static/templates/add_list.st
  8. 2
      static/templates/footer.st
  9. 29
      static/templates/frontpage.st
  10. 2
      static/templates/index.st
  11. 2
      static/templates/inspect.st
  12. 4
      static/templates/js.st
  13. 4
      static/templates/listadminlist.st
  14. 10
      static/templates/listlist.st
  15. 6
      static/templates/listmembers.st
  16. 2
      static/templates/login.st

2
pom.xml

@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
<groupId>org.example</groupId>
<artifactId>Widerhall</artifactId>
<version>0.0.11</version>
<version>0.0.12</version>
<build>
<plugins>
<plugin>

4
src/main/java/de/srsoftware/widerhall/Configuration.java

@ -36,7 +36,7 @@ public class Configuration { @@ -36,7 +36,7 @@ public class Configuration {
var newVals = (JSONObject) new JSONParser().parse(Files.readString(file.toPath()));
data.putAll(newVals);
} catch (ParseException | IOException e){
LOG.warn("Was not able to load configuration from {}:",file,e);
LOG.warn("Konnte Konfiguration nicht aus {} laden:",file,e);
}
return this;
}
@ -47,7 +47,7 @@ public class Configuration { @@ -47,7 +47,7 @@ public class Configuration {
}
public Configuration save() throws IOException {
if (file == null) throw new NullPointerException("Cannot save configuration: file is null!");
if (file == null) throw new NullPointerException("Konnte Konfiguration nicht speichern: Datei ist null!");
file.getParentFile().mkdirs();
Files.writeString(file.toPath(),data.toJSONString());
return this;

22
src/main/java/de/srsoftware/widerhall/web/Rest.java

@ -213,35 +213,35 @@ public class Rest extends HttpServlet { @@ -213,35 +213,35 @@ public class Rest extends HttpServlet {
return Map.of(SUCCESS,t("Mailing-List '{}' wurde {}!",listEmail,enable ? "aktiviert" : "inaktiviert"));
} catch (SQLException e) {
LOG.error("Aktivieren/Inaktivieren der Mailing-Liste fehlgeschlagen: ",e);
return Map.of("error",t("Failed to update list '{}'",listEmail));
return Map.of(ERROR,t("Aktualisieren der Liste '{}' fehlgeschlagen!",listEmail));
}
}
return Map.of("error",t("You are not allowed to edit '{}'",listEmail));
return Map.of(ERROR,t("Sie haben nicht die Berechtigng, '{}' zu bearbeiten",listEmail));
}
private Map<String, String> hideList(String listEmail, User user, boolean hide) {
if (listEmail == null || listEmail.isBlank()) return Map.of(ERROR,"no list email provided!");
if (listEmail == null || listEmail.isBlank()) return Map.of(ERROR,"Keine Listen-Email übergeben!");
if (user.hashPermission(User.PERMISSION_ADMIN) || ListMember.listsOwnedBy(user).contains(listEmail)){
try {
MailingList.load(listEmail).hide(hide);
return Map.of(SUCCESS,t("Mailing list '{}' was {}!",listEmail,hide ? "hidden" : "made public"));
return Map.of(SUCCESS,t("Mailing-List '{}' wurde {}!",listEmail,hide ? "versteckt" : "veröffentlicht"));
} catch (SQLException e) {
LOG.error("Failed to (un)hide mailing list: ",e);
return Map.of("error",t("Failed to update list '{}'",listEmail));
LOG.error("Verstecken/Veröffentlichen der Mailinglist fehlgeschlagen: ",e);
return Map.of("error",t("Aktualisieren der Liste '{}' fehlgeschlagen",listEmail));
}
}
return Map.of("error",t("You are not allowed to edit '{}'",listEmail));
return Map.of(ERROR,t("Sie haben nicht die Berechtigng, '{}' zu bearbeiten",listEmail));
}
private Map testList(String listEmail, User user) {
if (listEmail == null || listEmail.isBlank()) return Map.of(ERROR,"no list email provided!");
if (listEmail == null || listEmail.isBlank()) return Map.of(ERROR,"Keine Listen-Email übergeben!");
try {
MailingList.load(listEmail).test(user);
return Map.of(SUCCESS,t("Sent test email to {}",user.email()));
return Map.of(SUCCESS,t("Test-Email an {} gesendet",user.email()));
} catch (Exception e) {
LOG.warn("Failed to send test email",e);
return Map.of(ERROR,t("Failed to send test email to {}",user.email()));
LOG.warn("Senden der Test-Email fehlgeschlagen",e);
return Map.of(ERROR,t("Senden der Test-Email an {} fehlgeschlagen",user.email()));
}
}
}

8
src/main/java/de/srsoftware/widerhall/web/TemplateServlet.java

@ -26,12 +26,12 @@ public abstract class TemplateServlet extends HttpServlet { @@ -26,12 +26,12 @@ public abstract class TemplateServlet extends HttpServlet {
protected String loadFile(String filename, HttpServletResponse resp) {
var path = String.join(File.separator,baseDir,"static",filename);
var file = new File(path);
if (!file.exists()) return t("File {} does not exist!",filename);
if (!file.exists()) return t("Datei {} existiert nicht!",filename);
try {
var content = Files.readString(file.toPath());
resp.getWriter().println(content);
} catch (IOException e) {
return t("Failed to load file '{}'!",filename);
return t("Ladend der Datei '{}' fehlgeschlagen!",filename);
}
return null;
}
@ -44,10 +44,10 @@ public abstract class TemplateServlet extends HttpServlet { @@ -44,10 +44,10 @@ public abstract class TemplateServlet extends HttpServlet {
resp.getWriter().println(template.render());
return null;
} catch (IOException e) {
return t("Failed to load template '{}'",path);
return t("Laden der Vorlage '{}' fehlgeschlagen",path);
}
}
return t("No template for path '{}'!",path);
return t("Keine Vorlage für den Pfad '{}' vorhanden!",path);
}
protected void loadTemplates() {

80
src/main/java/de/srsoftware/widerhall/web/Web.java

@ -60,7 +60,7 @@ public class Web extends TemplateServlet { @@ -60,7 +60,7 @@ public class Web extends TemplateServlet {
data.put(USER, user);
if (!user.hashPermission(User.PERMISSION_CREATE_LISTS)){
data.put(ERROR,t("You are not allowed to create new mailing lists!"));
data.put(ERROR,t("Ihnen ist es nicht gestattet, neue Mailinglisten anzulegen!"));
return loadTemplate(ADMIN,data,resp);
}
@ -88,17 +88,17 @@ public class Web extends TemplateServlet { @@ -88,17 +88,17 @@ public class Web extends TemplateServlet {
data.put(SMTP_PORT, smtpPort);
if (name == null || name.isBlank() || email == null || email.isBlank()) {
data.put(ERROR, "List name and address are required!");
data.put(ERROR, "Name und Adresse der Liste sind notwendige Felder!");
return loadTemplate(ADD_LIST, data, resp);
}
if (!Util.isEmail(email)) {
data.put(ERROR, t("List email ({}) is not a valid email address!", email));
data.put(ERROR, t("Listen-E-Mail-Adresse ({}) ist keine gültige E-Mail-Adresse!", email));
return loadTemplate(ADD_LIST, data, resp);
}
if (imapHost == null || imapHost.isBlank() || imapUser == null || imapUser.isBlank() || imapPass == null || imapPass.isBlank()) {
data.put(ERROR, "IMAP credentials are required!");
data.put(ERROR, "IMAP-Zugangsdaten sind erforderlich!");
return loadTemplate(ADD_LIST, data, resp);
}
@ -107,12 +107,12 @@ public class Web extends TemplateServlet { @@ -107,12 +107,12 @@ public class Web extends TemplateServlet {
imapPort = Integer.parseInt(req.getParameter(IMAP_PORT));
data.put(IMAP_PORT, imapPort);
} catch (NumberFormatException nfe) {
data.put(ERROR, t("'{}' is not a proper port number!", req.getParameter(IMAP_PORT)));
data.put(ERROR, t("'{}' ist keine gültige Port-Nummer!", req.getParameter(IMAP_PORT)));
return loadTemplate(ADD_LIST, data, resp);
}
if (smtpHost == null || smtpHost.isBlank() || smtpUser == null || smtpUser.isBlank() || smtpPass == null || smtpPass.isBlank()) {
data.put(ERROR, "SMTP credentials are required!");
data.put(ERROR, "SMTP-Zugangsdaten sind erforderlich!");
return loadTemplate(ADD_LIST, data, resp);
}
@ -120,7 +120,7 @@ public class Web extends TemplateServlet { @@ -120,7 +120,7 @@ public class Web extends TemplateServlet {
smtpPort = Integer.parseInt(req.getParameter(SMTP_PORT));
data.put(SMTP_PORT, smtpPort);
} catch (NumberFormatException nfe) {
data.put(ERROR, t("'{}' is not a proper port number!", req.getParameter(SMTP_PORT)));
data.put(ERROR, t("'{}' ist keine gültige Port-Nummer!", req.getParameter(SMTP_PORT)));
return loadTemplate(ADD_LIST, data, resp);
}
@ -129,20 +129,20 @@ public class Web extends TemplateServlet { @@ -129,20 +129,20 @@ public class Web extends TemplateServlet {
ListMember.create(list, user, ListMember.STATE_OWNER);
return redirectTo(INDEX, resp);
} catch (SQLException e) {
return t("Failed to create list '{}': {}", name, e.getMessage());
return t("Erzeugen der Liste '{}' fehlgeschlagen: {}", name, e.getMessage());
}
}
private String confirm(HttpServletRequest req, HttpServletResponse resp) {
try {
var token = req.getParameter(TOKEN);
if (token== null || token.isBlank()) return t("Invalid or missing token!");
if (token== null || token.isBlank()) return t("Ungültiger oder fehlender Token!");
var user = ListMember.confirm(token);
if (user != null) return loadTemplate(INDEX,Map.of(USER,user.safeMap(),NOTES,"Confirmed list subscription!"),resp);
return t("Unknown user or token");
if (user != null) return loadTemplate(INDEX,Map.of(USER,user.safeMap(),NOTES,"Listen-Mitgliedschaft bestätigt!"),resp);
return t("Nutzer oder Token unbekannt");
} catch (Exception e) {
LOG.debug("Failed to confirm list membership:",e);
return t("Confirmation of list membership failed!");
LOG.debug("Bestätigung des Listen-Abonnements fehlgeschlagen:",e);
return t("Bestätigung des Listen-Abonnements fehlgeschlagen!");
}
}
@ -188,7 +188,7 @@ public class Web extends TemplateServlet { @@ -188,7 +188,7 @@ public class Web extends TemplateServlet {
return confirm(req,resp);
case RELOAD:
loadTemplates();
data.put(NOTES,t("Templates have been reloaded"));
data.put(NOTES,t("Vorlagen wurden neu geladen"));
path = INDEX;
case "css":
case INDEX:
@ -199,16 +199,16 @@ public class Web extends TemplateServlet { @@ -199,16 +199,16 @@ public class Web extends TemplateServlet {
data.put(LIST,listEmail);
return loadTemplate(path, data, resp);
}
return t("You are not allowed to subscribe to '{}'!",list.email());
return t("Es ist ihnen nicht gestattet, '{}' zu abonnieren!",list.email());
case "js":
resp.setContentType("text/javascript");
return loadTemplate(path,data,resp);
case LOGIN:
try {
if (User.noUsers()) return loadTemplate(REGISTER, Map.of(NOTES,t("User database is empty. Create admin user first:")), resp);
if (User.noUsers()) return loadTemplate(REGISTER, Map.of(NOTES,t("Nutzer-Datenbank ist leer. Admin-Nutzer wird hiermit angelegt:")), resp);
return loadTemplate(path,null,resp);
} catch (SQLException e) {
return "Error reading user database!";
return "Fehler beim Lesen der Datenbank!";
}
case LOGOUT:
req.getSession().invalidate();
@ -231,8 +231,8 @@ public class Web extends TemplateServlet { @@ -231,8 +231,8 @@ public class Web extends TemplateServlet {
private String handleLogin(HttpServletRequest req, HttpServletResponse resp) {
var email = req.getParameter("email");
var pass = req.getParameter("pass");
if (email == null || pass == null) return loadTemplate("login", Map.of("error",t("Missing username or password!")), resp);
if (!Util.isEmail(email)) return loadTemplate("login", Map.of("error",t("'{}' is not a valid email address!",email)), resp);
if (email == null || pass == null) return loadTemplate("login", Map.of("error",t("Nutzername oder Passwort fehlen!")), resp);
if (!Util.isEmail(email)) return loadTemplate("login", Map.of("error",t("'{}' ist keine gültige Mailadresse!",email)), resp);
try {
var user = User.loadUser(email,pass);
req.getSession().setAttribute("user",user);
@ -240,10 +240,10 @@ public class Web extends TemplateServlet { @@ -240,10 +240,10 @@ public class Web extends TemplateServlet {
resp.sendRedirect(String.join("/",WEB_ROOT,"admin"));
} catch (Exception e) {
try {
LOG.warn("Static.handleLogin failed:",e);
LOG.warn("Static.handleLogin fehlgeschlagen:",e);
Thread.sleep(10000);
} finally {
return loadTemplate("login", Map.of(ERROR,t("Invalid username/password"),EMAIL,email), resp);
return loadTemplate("login", Map.of(ERROR,t("Ungültiger Nutzername oder ungültiges Passwort!"),EMAIL,email), resp);
}
}
return null;
@ -265,7 +265,7 @@ public class Web extends TemplateServlet { @@ -265,7 +265,7 @@ public class Web extends TemplateServlet {
return unsubscribe(req,resp);
}
return t("No handler for path {}!",path);
return t("Kein Handler für den Pfad '{}'!",path);
}
@ -277,7 +277,7 @@ public class Web extends TemplateServlet { @@ -277,7 +277,7 @@ public class Web extends TemplateServlet {
resp.sendRedirect(String.join("/",WEB_ROOT,page));
return null;
} catch (IOException e) {
return t("Was not able to redirect to {} page: {}", page, e.getMessage());
return t("Weiterleitung nach {} fehlgeschlagen: {}", page, e.getMessage());
}
}
@ -293,15 +293,15 @@ public class Web extends TemplateServlet { @@ -293,15 +293,15 @@ public class Web extends TemplateServlet {
if (email == null || email.isBlank() ||
name == null || name.isBlank() ||
pass == null || pass.isBlank() ||
pass_repeat == null || pass_repeat.isBlank()) return loadTemplate(REGISTER,Map.of(ERROR,"Fill all fields, please!",NAME,name,EMAIL,email),resp);
if (!pass.equals(pass_repeat)) return loadTemplate(REGISTER,Map.of(ERROR,"Passwords do not match!",NAME,name,EMAIL,email),resp);
if (Util.simplePassword(pass)) return loadTemplate(REGISTER,Map.of(ERROR,"Password to short or to simple!",NAME,name,EMAIL,email),resp);
pass_repeat == null || pass_repeat.isBlank()) return loadTemplate(REGISTER,Map.of(ERROR,"Bitte alle Felder ausfüllen!",NAME,name,EMAIL,email),resp);
if (!pass.equals(pass_repeat)) return loadTemplate(REGISTER,Map.of(ERROR,"Passworte stimmen nicht überein!",NAME,name,EMAIL,email),resp);
if (Util.simplePassword(pass)) return loadTemplate(REGISTER,Map.of(ERROR,"Passwort zu kurz oder zu einfach!",NAME,name,EMAIL,email),resp);
var firstUser = false;
try {
firstUser = User.noUsers();
} catch (SQLException e) {
return t("Failed to access user database: {}",e.getMessage());
return t("Fehler beim Zugriff auf die Nutzer-Datenbank: {}",e.getMessage());
}
@ -311,8 +311,8 @@ public class Web extends TemplateServlet { @@ -311,8 +311,8 @@ public class Web extends TemplateServlet {
req.getSession().setAttribute("user",user);
return redirectTo(INDEX,resp);
} catch (SQLException e) {
LOG.warn("Failed to create new user:",e);
return t("Failed to create new user: {}",e.getMessage());
LOG.warn("Erzeugen des neuen Nutzers fehlgeschlagen:",e);
return t("Erzeugen des neuen Nutzers fehlgeschlagen: {}",e.getMessage());
}
}
@ -330,12 +330,12 @@ public class Web extends TemplateServlet { @@ -330,12 +330,12 @@ public class Web extends TemplateServlet {
var list = MailingList.load(listEmail);
if (list == null){
data.put(ERROR,"No list provided by form data!");
data.put(ERROR,"Formular-Daten enthalten keine Liste!");
return loadTemplate(SUBSCRIBE,data,resp);
}
if (name == null || name.isBlank() || email == null || email.isBlank()){
data.put(ERROR,"Name and email are required fields for list subscription!");
data.put(ERROR,"Name und E-Mail-Adresse sind für das Abonnieren der Mailingliste erforderlich!");
return loadTemplate(SUBSCRIBE,data,resp);
}
if (pass != null && pass.isBlank()) pass = null;
@ -352,36 +352,36 @@ public class Web extends TemplateServlet { @@ -352,36 +352,36 @@ public class Web extends TemplateServlet {
// success → subscribe
} catch (InvalidKeyException | SQLException e) {
// invalid credentials
data.put(ERROR,t("'{}' already in database, but with different password!",email));
data.put(ERROR,t("'{}' gibt es schon in der Datenbank, hat dort aber ein anderes Passwort!",email));
return loadTemplate(SUBSCRIBE,data,resp);
}
}
data.put(USER,user.safeMap());
if (!list.isOpenFor(user)){
data.put(ERROR,t("You are not allowed to join {}!",list.email()));
data.put(ERROR,t("Ihnen ist es nicht gestattet, '{}' zu abonnieren!",list.email()));
return loadTemplate(SUBSCRIBE,data,resp);
}
try {
list.requestSubscription(user,skipConfirmation);
if (skipConfirmation) {
data.put(NOTES, t("Successfully subscribed '{}' to '{}'.", user.email(), list.email()));
data.put(NOTES, t("'{}' hat die Mailingliste '{}' erfolgreich abonniert.", user.email(), list.email()));
} else {
data.put(NOTES, t("Sent confirmation mail to '{}.", user.email()));
data.put(NOTES, t("Bestätigungs-Email wurde an '{} versendet.", user.email()));
}
return loadTemplate(INDEX,data,resp);
} catch (SQLException sqle) {
LOG.debug("List subscription failed: ",sqle);
LOG.debug("Abonnieren der Liste fehlgeschlagen: ",sqle);
var cause = getCausingException(sqle);
int code = cause.getErrorCode();
if (code == PRIMARY_KEY_CONSTRAINT) {// user already exists
data.put(ERROR,t("You already are member of this list!",sqle.getMessage()));
} else data.put(ERROR,t("Subscription failed: {}",sqle.getMessage()));
data.put(ERROR,t("Sie haben diese Liste bereits abonniert!",sqle.getMessage()));
} else data.put(ERROR,t("Abonnieren der Liste fehlgeschlagen: {}",sqle.getMessage()));
return loadTemplate(SUBSCRIBE,data,resp);
} catch (MessagingException e) {
LOG.warn("Failed to send request confirmation email:",e);
data.put(ERROR,t("Failed to send request confirmation email: {}",e.getMessage()));
LOG.warn("Senden der Bestätigungs-Email fehlgeschlagen:",e);
data.put(ERROR,t("Senden der Bestätigungs-Email fehlgeschlagen: {}",e.getMessage()));
return loadTemplate(SUBSCRIBE,data,resp);
}
}

6
src/test/java/de/srsoftware/widerhall/data/DatabaseTest.java

@ -50,8 +50,8 @@ public class DatabaseTest extends TestCase { @@ -50,8 +50,8 @@ public class DatabaseTest extends TestCase {
}
public void testUpdate(){
assertEquals("UPDATE Test",Database.open().update("Test").sql());
assertEquals("UPDATE Test SET x = 5",Database.open().update("Test").set("x",5).sql());
assertEquals("UPDATE Test SET x = 5, y = 6",Database.open().update("Test").set("x",5).set("y",6).sql());
assertEquals("UPDATE Test",Database.open().update("Test").compile().toString());
assertEquals("UPDATE Test SET x = 5",Database.open().update("Test").set("x",5).compile().toString());
assertEquals("UPDATE Test SET x = 5, y = 6",Database.open().update("Test").set("x",5).set("y",6).compile().toString());
}
}

24
static/templates/add_list.st

@ -9,24 +9,24 @@ @@ -9,24 +9,24 @@
<body id="login">
«navigation()»
«userinfo()»
<h1>Widerhall List Creation</h1>
<h1>Widerhall Listen-Erzeugung</h1>
«messages()»
<form method="POST" action="add_list">
<fieldset>
<legend>List configuration</legend>
<legend>Listen-Konfiguration</legend>
<fieldset>
<legend>Basic data</legend>
<legend>Basis-Daten</legend>
<label>
<input type="text" name="name" value="«data.name»" id="name" />
List name
Name der ML
</label>
<label>
<input type="text" name="email" value="«data.email»" id="email" />
List E-Mail Address
Email-Adresse
</label>
</fieldset>
<fieldset>
<legend>IMAP protocol</legend>
<legend>IMAP-Protokoll</legend>
<label>
<input type="text" name="imap_host" value="«data.imap_host»" id="imap_host" />
Hostname
@ -37,15 +37,15 @@ @@ -37,15 +37,15 @@
</label>
<label>
<input type="text" name="imap_user" value="«data.imap_user»" id="imap_user" />
Username
Benutzername
</label>
<label>
<input type="password" name="imap_pass" value="«data.imap_pass»" id="imap_pass" />
Password
Passwort
</label>
</fieldset>
<fieldset>
<legend>SMTP protocol</legend>
<legend>SMTP-Protokoll</legend>
<label>
<input type="text" name="smtp_host" value="«data.smtp_host»" id="smtp_host" />
Hostname
@ -56,14 +56,14 @@ @@ -56,14 +56,14 @@
</label>
<label>
<input type="text" name="smtp_user" value="«data.smtp_user»" id="smtp_user" />
Username
Benutzername
</label>
<label>
<input type="password" name="smtp_pass" value="«data.smtp_pass»" id="smtp_pass" />
Password
Passwort
</label>
</fieldset>
<button type="submit">Save new mailing list</button>
<button type="submit">neue ML speichern</button>
</fieldset>
</form>
</body>

2
static/templates/footer.st

@ -1,3 +1,3 @@ @@ -1,3 +1,3 @@
<div class="footer">
Widerhall Mail Distributor. Get the sources at <a target="_blank" href="https://git.srsoftware.de/StephanRichter/Widerhall">git.srsoftware.de</a>
Widerhall Mail-Verteiler. Hol die den Quellcode auf <a target="_blank" href="https://git.srsoftware.de/StephanRichter/Widerhall">git.srsoftware.de</a>
</div>

29
static/templates/frontpage.st

@ -1,39 +1,38 @@ @@ -1,39 +1,38 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link rel="stylesheet" href="css" />
</head>
<body id="login">
<h1>Widerhall front page</h1>
If you are looking for you mailing lists, <a href="web/index">Go to the /web page</a>...
<h1>Widerhall Startseite</h1>
Falls du zu den Mailing-Listen willst, <a href="web/index">Gehe zur Seite /web</a>...
<fieldset>
<legend>What is <em>Widerhall</em>?</legend>
<legend>Was ist <em>Widerhall</em>?</legend>
<p>
Widerhall is a mailing list system written in Java.
It allows to maintain a set of mailing lists with the option to make (some of) them publicy subscribable.
Widerhall ist ein in Java geschriebenes Mailing-List-System.
Es erlaubd die Pflege con Mailverteilern mit der Option diese für Jedermann abonnierbar zu machen.
</p>
<p>
<em>Widerhall</em> is very lightweight, as does not include a full email server stack.
<em>Widerhall</em> ist sehr leichtgewichtig, da es keinen vollständigen Mailserver enthält.
</p>
</fieldset>
<fieldset>
<legend>Why should I use <em>Widerhall</em>?</legend>
<legend>Warum sollte ich <em>Widerhall</em> nutzen?</legend>
<p>
Compared to other mailing list systems, widerhall is very lightweight:
Im Vergleich mit anderen Mailing-Listen-Systemen ist <em>Widerhall</em> sehr schlank:
<p>
It contains not mailserver stack. It does not even require you to set up a mailserver!
Es enthält keinen eigenen Mailserver. Für <em>Widerhall</em> musst du nichtmal einen eigenen Mailserver aufsetzen!
</p>
</fieldset>
<fieldset>
<legend>How does it work?</legend>
<legend>Wie funktioniert das?</legend>
<p>
Widerhall works by just letting you set up any IMAP/SMTP enabled email address with a provider of your choice.
It then connects to the inbox of you selected email address and watches for incoming messages.
Upon message reception, it forwards the message to all subscribers of the mailing list.
Bei Widerhall kannst du einfach eine IMAP/SMTP-fähige Emailadresse bei einem beliebigen Anbierter anlegen.
Danach verbindet sich Widerhall mit dem Posteingang der entsprechenden Email-Adresse und wartet auf dort eingehende Nachrichten.
Sobald eine Nachricht empfangen wird, wird diese an alle Abonnenten der Mailing-Liste weitergeleitet.
</p>
<p>
That's it.
Das ist alles.
</p>
</fieldset>
</body>

2
static/templates/index.st

@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
«navigation()»
«userinfo()»
«messages()»
<h1>Widerhall Index page</h1>
<h1>Widerhall Index-Seite</h1>
«listlist()»
«footer()»
</body>

2
static/templates/inspect.st

@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
«navigation()»
«userinfo()»
«messages()»
<h1>Widerhall '«data.list»' Details</h1>
<h1>Widerhall '«data.list»'-Details</h1>
«listmembers()»
</body>
</html>

4
static/templates/js.st

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
function addPermission(userEmail,permission){
if (confirm("Really give permission to "+userEmail+"?")){
if (confirm("Wirklich Berechtigung an "+userEmail+" geben?")){
$.post('/api/user/addpermission',{email:userEmail,permissions:permission},reload,'json');
}
}
@ -13,7 +13,7 @@ function dropList(listEmail){ @@ -13,7 +13,7 @@ function dropList(listEmail){
}
function dropPermission(userEmail,permission){
if (confirm("Really withdraw permission from "+userEmail+"?")){
if (confirm("Wirklich Berechtigung von "+userEmail+" wegnehmen?")){
$.post('/api/user/droppermission',{email:userEmail,permissions:permission},reload,'json');
}
}

4
static/templates/listadminlist.st

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
<fieldset>
<legend>List of (editable) mailinglists</legend>
<legend>Liste der (bearbeitbaren) Mailing-Listen</legend>
<table id="listlist">
<tr>
<th colspan="4">List</th>
@ -19,7 +19,7 @@ @@ -19,7 +19,7 @@
<th>User</th>
</tr>
</table>
<a href="add_list">Add new mailing list</a>
<a href="add_list">Neue Mailing-Liste anlegen</a>
<script type="text/javascript">
loadListOfEditableLists();
</script>

10
static/templates/listlist.st

@ -1,11 +1,11 @@ @@ -1,11 +1,11 @@
<fieldset>
<legend>List of (public) mailinglists</legend>
<legend>Liste der (frei abonnierbaren) Mailing-Listen</legend>
<table id="listlist">
<tr>
<th>List Name</th>
<th colspan="3">List Address</th>
<th>State</th>
<th>Actions</th>
<th>Listen-Name</th>
<th colspan="3">Listen-Adresse</th>
<th>Status</th>
<th>Aktionen</th>
</tr>
</table>
<script type="text/javascript">

6
static/templates/listmembers.st

@ -1,10 +1,10 @@ @@ -1,10 +1,10 @@
<fieldset>
<legend>Members of «data.list»</legend>
<legend>Abonnenten von «data.list»</legend>
<table id="memberlist">
<tr>
<th>Name</th>
<th>Email</th>
<th>State</th>
<th>E-Mail</th>
<th>Status</th>
</tr>
</table>
<script type="text/javascript">

2
static/templates/login.st

@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
<body id="login">
«navigation()»
«messages()»
<h1>Widerhall login</h1>
<h1>Widerhall Login</h1>
<form method="POST">
<fieldset>
<legend>Login-Daten</legend>

Loading…
Cancel
Save