Merge branch 'main' into lang_de
This commit is contained in:
@@ -17,6 +17,45 @@ public class Configuration {
|
||||
private JSONObject data;
|
||||
private File file;
|
||||
|
||||
public File archiveDir() {
|
||||
var locations = locations();
|
||||
if (!locations.containsKey(ARCHIVE)) locations.put(ARCHIVE, String.join(File.separator,baseDir(),"archive"));
|
||||
return new File((String) locations.get(ARCHIVE));
|
||||
}
|
||||
|
||||
public String baseDir() {
|
||||
var locations = locations();
|
||||
if (!locations.containsKey(BASE)) locations.put(BASE,System.getProperty("user.dir"));
|
||||
return (String) locations.get(BASE);
|
||||
}
|
||||
|
||||
public String baseUrl() {
|
||||
if (!data.containsKey(BASE_URL)) data.put(BASE_URL,"http://localhost");
|
||||
return (String) data.get(BASE_URL);
|
||||
}
|
||||
|
||||
public File configFile() {
|
||||
var locations = locations();
|
||||
if (!locations.containsKey(CONFIG)) locations.put(CONFIG, String.join(File.separator,baseDir(),"config","config.json"));
|
||||
return new File((String) locations.get(CONFIG));
|
||||
}
|
||||
|
||||
public File dbFile() {
|
||||
var locations = locations();
|
||||
if (!locations.containsKey(DB)) locations.put(DB, String.join(File.separator,baseDir(),"db","db.sqlite3"));
|
||||
return new File((String) locations.get(DB));
|
||||
}
|
||||
|
||||
public Configuration dbFile(File dbFile){
|
||||
var locations = locations();
|
||||
locations.put(DB,dbFile.toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
public File file() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public static Configuration instance() {
|
||||
if (singleton == null) singleton = new Configuration().setDefaults();
|
||||
return singleton;
|
||||
@@ -37,18 +76,24 @@ public class Configuration {
|
||||
var newVals = (JSONObject) new JSONParser().parse(Files.readString(file.toPath()));
|
||||
data.putAll(newVals);
|
||||
} catch (ParseException | IOException e){
|
||||
LOG.warn("Konnte Konfiguration nicht aus {} laden:",file,e);
|
||||
LOG.warn("Was not able to load configuration from {}:",file,e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private JSONObject locations() {
|
||||
Object o = data.get(LOCATIONS);
|
||||
if (!(o instanceof JSONObject)) data.put(LOCATIONS,o = new JSONObject());
|
||||
return (JSONObject) o;
|
||||
}
|
||||
|
||||
public Configuration save(File file) throws IOException {
|
||||
this.file = file;
|
||||
return save();
|
||||
}
|
||||
|
||||
public Configuration save() throws IOException {
|
||||
if (file == null) throw new NullPointerException("Konnte Konfiguration nicht speichern: Datei ist null!");
|
||||
if (file == null) throw new NullPointerException("Cannot save configuration: file is null!");
|
||||
file.getParentFile().mkdirs();
|
||||
Files.writeString(file.toPath(),data.toJSONString());
|
||||
return this;
|
||||
@@ -64,57 +109,9 @@ public class Configuration {
|
||||
return this;
|
||||
}
|
||||
|
||||
private JSONObject locations() {
|
||||
Object o = data.get(LOCATIONS);
|
||||
if (!(o instanceof JSONObject)) data.put(LOCATIONS,o = new JSONObject());
|
||||
return (JSONObject) o;
|
||||
}
|
||||
|
||||
public String baseDir() {
|
||||
var locations = locations();
|
||||
if (!locations.containsKey(BASE)) locations.put(BASE,System.getProperty("user.dir"));
|
||||
return (String) locations.get(BASE);
|
||||
}
|
||||
|
||||
public File configFile() {
|
||||
var locations = locations();
|
||||
if (!locations.containsKey(CONFIG)) locations.put(CONFIG, String.join(File.separator,baseDir(),"config","config.json"));
|
||||
return new File((String) locations.get(CONFIG));
|
||||
}
|
||||
|
||||
public File dbFile() {
|
||||
var locations = locations();
|
||||
if (!locations.containsKey(DB)) locations.put(DB, String.join(File.separator,baseDir(),"db","db.sqlite3"));
|
||||
return new File((String) locations.get(DB));
|
||||
}
|
||||
|
||||
public Configuration dbFile(File dbFile){
|
||||
var locations = locations();
|
||||
locations.put(DB,dbFile.toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
public File archiveDir() {
|
||||
var locations = locations();
|
||||
if (!locations.containsKey(ARCHIVE)) locations.put(ARCHIVE, String.join(File.separator,baseDir(),"archive"));
|
||||
return new File((String) locations.get(ARCHIVE));
|
||||
}
|
||||
|
||||
|
||||
public int serverPort() {
|
||||
if (!data.containsKey(PORT)) data.put(PORT,80L);
|
||||
var o = data.get(PORT);
|
||||
return (int) (long) o;
|
||||
}
|
||||
|
||||
public String baseUrl() {
|
||||
if (!data.containsKey(BASE_URL)) data.put(BASE_URL,"http://localhost");
|
||||
return (String) data.get(BASE_URL);
|
||||
}
|
||||
|
||||
|
||||
public File file() {
|
||||
return file;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,92 +28,16 @@ public class Util {
|
||||
private static final MessageDigest SHA256 = getSha256();
|
||||
private static final String EMAIL_PATTERN = "^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^-]+(?:\\.[a-zA-Z0-9_!#$%&'*+/=?`{|}~^-]+)*@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*$";
|
||||
|
||||
public static String urlEncode(Map<String, Object> data) {
|
||||
String params = data.entrySet()
|
||||
.stream()
|
||||
.map(entry -> encode(entry.getKey()) + "=" + encode(entry.getValue()))
|
||||
.collect(Collectors.joining("&"));
|
||||
return params;
|
||||
public static String dropEmail(String tx) {
|
||||
return tx.replaceAll( "[.\\-\\w]+@[.\\-\\w]+", "[email_removed]");
|
||||
}
|
||||
|
||||
private static String encode(Object value) {
|
||||
return URLEncoder.encode(value.toString(), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
|
||||
public static MessageDigest getSha256() {
|
||||
try {
|
||||
return MessageDigest.getInstance("SHA-256");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String sha256(String s) {
|
||||
byte[] bytes = SHA256.digest(s.getBytes(StandardCharsets.UTF_8));
|
||||
return hex(bytes);
|
||||
}
|
||||
|
||||
private static String hex(byte[] bytes) {
|
||||
StringBuffer buf = new StringBuffer(bytes.length*2);
|
||||
for (var byt : bytes) buf.append(hex(byt));
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static String hex(int b){
|
||||
int lower = b & 0x0F;
|
||||
int upper = (b & 0xF0) >> 4;
|
||||
return (char)(upper < 10 ? '0'+upper : 'A'+upper-10)+""+(char)(lower < 10 ? '0'+lower : 'A'+lower-10);
|
||||
}
|
||||
|
||||
public static String t(String tx, Object ... fills){
|
||||
return Translation.get(Application.class,tx,fills);
|
||||
}
|
||||
|
||||
public static boolean isEmail(String email) {
|
||||
return email.matches(EMAIL_PATTERN);
|
||||
}
|
||||
|
||||
public static boolean simplePassword(String pass) {
|
||||
if (pass.length() < 6) return true;
|
||||
if (pass.length() < 8){
|
||||
for (int i=0; i<pass.length();i++){
|
||||
if (!Character.isLetterOrDigit(pass.charAt(i))) return false; // password contains special character
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (pass.length() < 10){
|
||||
var digit = false;
|
||||
var letter = false;
|
||||
for (int i=0; i<pass.length();i++){
|
||||
char c = pass.charAt(i);
|
||||
if (!Character.isLetterOrDigit(c)) return false; // password contains special character
|
||||
digit |= Character.isDigit(c);
|
||||
letter |= Character.isLetter(c);
|
||||
if (letter && digit) return false; // password contains letters and digits
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int unset(int value, int...flags) {
|
||||
for (int flag : flags){
|
||||
if ((value & flag) > 0) value ^= flag;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static User getUser(HttpServletRequest req) {
|
||||
var o = req.getSession().getAttribute(USER);
|
||||
return o instanceof User ? (User) o : null;
|
||||
}
|
||||
|
||||
public static String getPath(HttpServletRequest req) {
|
||||
var path = req.getPathInfo();
|
||||
return path == null ? INDEX : path.substring(1);
|
||||
|
||||
public static boolean getCheckbox(HttpServletRequest req, String key) {
|
||||
return "on".equals(req.getParameter(key));
|
||||
}
|
||||
|
||||
public static MailingList getMailingList(HttpServletRequest req) {
|
||||
@@ -122,8 +46,22 @@ public class Util {
|
||||
return MailingList.load(listEmail);
|
||||
}
|
||||
|
||||
public static boolean getCheckbox(HttpServletRequest req, String key) {
|
||||
return "on".equals(req.getParameter(key));
|
||||
public static <T> T getNullable(ResultSet rs, String colName) throws SQLException {
|
||||
final T val = (T) rs.getObject(colName);
|
||||
return rs.wasNull() ? null : val;
|
||||
}
|
||||
public static String getPath(HttpServletRequest req) {
|
||||
var path = req.getPathInfo();
|
||||
return path == null ? INDEX : path.substring(1);
|
||||
|
||||
}
|
||||
public static MessageDigest getSha256() {
|
||||
try {
|
||||
return MessageDigest.getInstance("SHA-256");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -157,16 +95,75 @@ public class Util {
|
||||
if (s != null) return s;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String dropEmail(String tx) {
|
||||
return tx.replaceAll( "[.\\-\\w]+@[.\\-\\w]+", "[email_removed]");
|
||||
public static User getUser(HttpServletRequest req) {
|
||||
var o = req.getSession().getAttribute(USER);
|
||||
return o instanceof User ? (User) o : null;
|
||||
}
|
||||
|
||||
public static <T> T getNullable(ResultSet rs, String colName) throws SQLException {
|
||||
final T val = (T) rs.getObject(colName);
|
||||
return rs.wasNull() ? null : val;
|
||||
private static String hex(byte[] bytes) {
|
||||
StringBuffer buf = new StringBuffer(bytes.length*2);
|
||||
for (var byt : bytes) buf.append(hex(byt));
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static String hex(int b){
|
||||
int lower = b & 0x0F;
|
||||
int upper = (b & 0xF0) >> 4;
|
||||
return (char)(upper < 10 ? '0'+upper : 'A'+upper-10)+""+(char)(lower < 10 ? '0'+lower : 'A'+lower-10);
|
||||
}
|
||||
|
||||
public static boolean isEmail(String email) {
|
||||
return email.matches(EMAIL_PATTERN);
|
||||
}
|
||||
|
||||
public static String sha256(String s) {
|
||||
byte[] bytes = SHA256.digest(s.getBytes(StandardCharsets.UTF_8));
|
||||
return hex(bytes);
|
||||
}
|
||||
|
||||
public static boolean simplePassword(String pass) {
|
||||
if (pass.length() < 6) return true;
|
||||
if (pass.length() < 8){
|
||||
for (int i=0; i<pass.length();i++){
|
||||
if (!Character.isLetterOrDigit(pass.charAt(i))) return false; // password contains special character
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (pass.length() < 10){
|
||||
var digit = false;
|
||||
var letter = false;
|
||||
for (int i=0; i<pass.length();i++){
|
||||
char c = pass.charAt(i);
|
||||
if (!Character.isLetterOrDigit(c)) return false; // password contains special character
|
||||
digit |= Character.isDigit(c);
|
||||
letter |= Character.isLetter(c);
|
||||
if (letter && digit) return false; // password contains letters and digits
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String t(String tx, Object ... fills){
|
||||
return Translation.get(Application.class,tx,fills);
|
||||
}
|
||||
|
||||
public static String urlEncode(Map<String, Object> data) {
|
||||
String params = data.entrySet()
|
||||
.stream()
|
||||
.map(entry -> encode(entry.getKey()) + "=" + encode(entry.getValue()))
|
||||
.collect(Collectors.joining("&"));
|
||||
return params;
|
||||
}
|
||||
|
||||
|
||||
public static int unset(int value, int...flags) {
|
||||
for (int flag : flags){
|
||||
if ((value & flag) > 0) value ^= flag;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,13 +46,13 @@ public class Database {
|
||||
* @throws SQLException
|
||||
*/
|
||||
public ResultSet exec() throws SQLException {
|
||||
LOG.debug("Führe {} aus",this);
|
||||
LOG.debug("Executing {}",this);
|
||||
try {
|
||||
var stmt = conn.prepareStatement(sql);
|
||||
for (int i = 0; i < args.size(); i++) stmt.setObject(i+1, args.get(i));
|
||||
return stmt.executeQuery();
|
||||
} catch (SQLException sqle) { // add sql to the exception
|
||||
throw new SQLException(t("Query '{}' fehlgeschlagen:",this),sqle);
|
||||
throw new SQLException(t("Query '{}' failed:",this),sqle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,13 +61,13 @@ public class Database {
|
||||
* @throws SQLException
|
||||
*/
|
||||
public void run() throws SQLException {
|
||||
LOG.debug("Führe {} aus",this);
|
||||
LOG.debug("Running {}",this);
|
||||
try {
|
||||
var stmt = conn.prepareStatement(sql);
|
||||
for (int i = 0; i < args.size(); i++) stmt.setObject(i+1, args.get(i));
|
||||
stmt.execute();
|
||||
} catch (SQLException sqle) {
|
||||
throw new SQLException(t("Query '{}' fehlgeschlagen:",this),sqle);
|
||||
throw new SQLException(t("Query '{}' failed:",this),sqle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,8 +193,6 @@ public class Database {
|
||||
return new CompiledRequest(sql.toString(),args);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Request groupBy(String column) {
|
||||
groupBy = column;
|
||||
return this;
|
||||
@@ -354,7 +352,7 @@ public class Database {
|
||||
Configuration config = Configuration.instance();
|
||||
var dbFile = config.dbFile();
|
||||
String url = "jdbc:sqlite:"+dbFile;
|
||||
LOG.debug("Öffne {}",url);
|
||||
LOG.debug("Opening {}",url);
|
||||
dbFile.getParentFile().mkdirs();
|
||||
try {
|
||||
singleton = new Database(DriverManager.getConnection(url));
|
||||
@@ -410,7 +408,7 @@ public class Database {
|
||||
rs.close();
|
||||
return val > 0;
|
||||
} catch (SQLException e) {
|
||||
throw new SQLException(t("Konnte Existenz der Tabelle {} nicht prüfen!",tbName),e);
|
||||
throw new SQLException(t("Was not able to check existence of table {}!",tbName),e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,22 +50,22 @@ public class ListMember {
|
||||
}
|
||||
|
||||
public String addNewModerator(String userEmail) {
|
||||
if (!isAllowedToEditMods()) return t("Es ist dir nicht gestattet, neue Moderatoren für {} zu ernennen!",list.email());
|
||||
if (!isAllowedToEditMods()) return t("You are not allowed to nominate new mods for {}",list.email());
|
||||
User moderator = null;
|
||||
try {
|
||||
moderator = User.load(userEmail);
|
||||
} catch (SQLException e) {
|
||||
LOG.warn("Laden des Nutzers zu {} fehlgeschlagen",userEmail,e);
|
||||
return t("Laden des Nutzers zu {} fehlgeschlagen",userEmail);
|
||||
LOG.warn("Failed to load user for {}",userEmail,e);
|
||||
return t("Failed to load user for {}",userEmail);
|
||||
}
|
||||
if (moderator == null) return t("Kein solcher Nutzer: {}",userEmail);
|
||||
if (moderator == null) return t("No such user: {}",userEmail);
|
||||
|
||||
ListMember member = null;
|
||||
try {
|
||||
member = ListMember.load(list,moderator);
|
||||
} catch (SQLException e) {
|
||||
LOG.warn("Laden der Mitgliedschaft zu {}/{} fehlgeschlagen",moderator.email(),list.email(),e);
|
||||
return t("Laden der Mitgliedschaft zu {}/{} fehlgeschlagen",moderator.email(),list.email());
|
||||
LOG.warn("Failed to load list member for {}/{}",moderator.email(),list.email(),e);
|
||||
return t("Failed to load list member for {}/{}",moderator.email(),list.email());
|
||||
}
|
||||
try {
|
||||
if (member == null) {
|
||||
@@ -74,8 +74,8 @@ public class ListMember {
|
||||
member.setState(Util.unset(member.state|STATE_MODERATOR,STATE_AWAITING_CONFIRMATION));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOG.warn("Ernennen von {} zum Moderator von {} fehlgeschlagen",moderator.email(),list.email(),e);
|
||||
return t("Ernennen von {} zum Moderator von {} fehlgeschlagen",moderator.email(),list.email());
|
||||
LOG.warn("Failed to make {} a moderator of {}",moderator.email(),list.email(),e);
|
||||
return t("Failed to make {} a moderator of {}",moderator.email(),list.email());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -112,20 +112,6 @@ public class ListMember {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void sendConfirmationMail(ST template) throws SQLException, MessagingException {
|
||||
var subject = t("[{}] Abonnement abgeschlossen!",list.name());
|
||||
var data = new HashMap<String,Object>();
|
||||
data.put(USER,user.safeMap());
|
||||
data.put(LIST,list.minimalMap());
|
||||
data.put(URL,Configuration.instance().baseUrl()+"/web/index");
|
||||
if (list.isOpenForSubscribers()) data.put("open_list",true);
|
||||
var text = template.add("data",data).render();
|
||||
try {
|
||||
list.smtp().send(list.email(),list.name(),user.email(),subject,text);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
LOG.warn("Failed to send list subscription confirmation!",e);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Create a new list member entry in the database.
|
||||
* If the member has the state AWAITING_CONFIRMATION, a token is assigned with the member, too.
|
||||
@@ -160,44 +146,44 @@ public class ListMember {
|
||||
}
|
||||
|
||||
public String dropMember(String userEmail) {
|
||||
if (!isModerator()) return t("Es ist dir nicht erlaubt, Mitglieder von {} zu entfernen.",list.email());
|
||||
if (!isModerator()) return t("You are not allowed to remove members of {}",list.email());
|
||||
User user = null;
|
||||
try {
|
||||
user = User.load(userEmail);
|
||||
} catch (SQLException e) {
|
||||
LOG.warn("Laden des Nutzers zu {} fehlgeschlagen",userEmail,e);
|
||||
return t("Laden des Nutzers zu {} fehlgeschlagen",userEmail);
|
||||
LOG.warn("Failed to load user for {}",userEmail,e);
|
||||
return t("Failed to load user for {}",userEmail);
|
||||
}
|
||||
if (user == null) return t("Kein solcher Nutzer: {}",userEmail);
|
||||
if (user == null) return t("No such user: {}",userEmail);
|
||||
|
||||
ListMember member = null;
|
||||
try {
|
||||
member = ListMember.load(list,user);
|
||||
} catch (SQLException e) {
|
||||
LOG.warn("Laden der Mitgliedschaft zu {}/{} fehlgeschlagen",user.email(),list.email(),e);
|
||||
return t("Laden der Mitgliedschaft zu {}/{} fehlgeschlagen",user.email(),list.email());
|
||||
LOG.warn("Failed to load list member for {}/{}",user.email(),list.email(),e);
|
||||
return t("Failed to load list member for {}/{}",user.email(),list.email());
|
||||
}
|
||||
|
||||
if (member == null) return t("{} it nicht Mitglied von {}",user.email(),list.email());
|
||||
if (member.isOwner()) return t("Du kannst den Listen-Besitzer nicht entfernen!");
|
||||
if (member == null) return t("{} is no member of {}",user.email(),list.email());
|
||||
if (member.isOwner()) return t("You are not allowed to remvoe the list owner!");
|
||||
|
||||
try {
|
||||
member.unsubscribe();
|
||||
} catch (SQLException e) {
|
||||
LOG.warn("Abbestellen von {} / {} nicht fehlgeschlagen",user.email(),list.email(),e);
|
||||
return t("Abbestellen von {} / {} nicht fehlgeschlagen",user.email(),list.email());
|
||||
LOG.warn("Failed to un-subscribe {} from {}",user.email(),list.email(),e);
|
||||
return t("Failed to un-subscribe {} from {}",user.email(),list.email());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String dropModerator(String userEmail) {
|
||||
if (!isAllowedToEditMods()) return t("Es ist dir nicht gestattet, die Moderatoren von {} zu verändern",list.email());
|
||||
if (!isAllowedToEditMods()) return t("You are not allowed to edit mods of {}",list.email());
|
||||
User moderator = null;
|
||||
try {
|
||||
moderator = User.load(userEmail);
|
||||
} catch (SQLException e) {
|
||||
LOG.warn("Laden des Nutzers zu {} fehlgeschlagen",userEmail,e);
|
||||
return t("Laden des Nutzers zu {} fehlgeschlagen",userEmail);
|
||||
LOG.warn("Failed to load user for {}",userEmail,e);
|
||||
return t("Failed to load user for {}",userEmail);
|
||||
}
|
||||
if (moderator == null) return t("No such user: {}",userEmail);
|
||||
|
||||
@@ -205,8 +191,8 @@ public class ListMember {
|
||||
try {
|
||||
member = ListMember.load(list,moderator);
|
||||
} catch (SQLException e) {
|
||||
LOG.warn("Laden der Mitgliedschaft zu {}/{} fehlgeschlagen",moderator.email(),list.email(),e);
|
||||
return t("Laden der Mitgliedschaft zu {}/{} fehlgeschlagen",moderator.email(),list.email());
|
||||
LOG.warn("Failed to load list member for {}/{}",moderator.email(),list.email(),e);
|
||||
return t("Failed to load list member for {}/{}",moderator.email(),list.email());
|
||||
}
|
||||
try {
|
||||
if (member == null) {
|
||||
@@ -215,8 +201,8 @@ public class ListMember {
|
||||
member.setState(Util.unset(member.state,STATE_MODERATOR));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOG.warn("Ernennen von {} zum normalen Abonnenten von {} fehlgeschlagen",moderator.email(),list.email(),e);
|
||||
return t("Ernennen von {} zum normalen Abonnenten von {} fehlgeschlagen",moderator.email(),list.email());
|
||||
LOG.warn("Failed to make {} a subscriber of {}",moderator.email(),list.email(),e);
|
||||
return t("Failed to make {} a subscriber of {}",moderator.email(),list.email());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -283,7 +269,7 @@ public class ListMember {
|
||||
var rs = request.compile().exec();
|
||||
while (rs.next()) listEmails.add(rs.getString(LIST_EMAIL));
|
||||
} catch (SQLException e) {
|
||||
LOG.warn("Sammeln der Listen von {} fehlgeschlagen: ",user.email(),e);
|
||||
LOG.warn("Collecting lists of {} failed: ",user.email(),e);
|
||||
}
|
||||
var lists = MailingList.loadAll(listEmails);
|
||||
var result = new HashSet<ListMember>();
|
||||
@@ -309,7 +295,7 @@ public class ListMember {
|
||||
var rs = request.compile().exec();
|
||||
while (rs.next()) list.add(rs.getString(LIST_EMAIL));
|
||||
} catch (SQLException e) {
|
||||
LOG.warn("Sammeln der Listen von {} fehlgeschlagen: ",user.email(),e);
|
||||
LOG.warn("Collecting lists of {} failed: ",user.email(),e);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
@@ -374,6 +360,21 @@ public class ListMember {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void sendConfirmationMail(ST template) throws SQLException, MessagingException {
|
||||
var subject = t("[{}] Subscription complete!",list.name());
|
||||
var data = new HashMap<String,Object>();
|
||||
data.put(USER,user.safeMap());
|
||||
data.put(LIST,list.minimalMap());
|
||||
data.put(URL,Configuration.instance().baseUrl()+"/web/index");
|
||||
if (list.isOpenForSubscribers()) data.put("open_list",true);
|
||||
var text = template.add("data",data).render();
|
||||
try {
|
||||
list.smtp().send(list.email(),list.name(),user.email(),subject,text);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
LOG.warn("Failed to send list subscription confirmation!",e);
|
||||
}
|
||||
}
|
||||
|
||||
public ListMember setState(int newState) throws SQLException {
|
||||
Database.open()
|
||||
.update(TABLE_NAME)
|
||||
@@ -391,10 +392,10 @@ public class ListMember {
|
||||
*/
|
||||
public String stateText() {
|
||||
var words = new ArrayList<String>();
|
||||
if (isSubscriber()) words.add("Abonniert");
|
||||
if (isOwner()) words.add("Besitzer");
|
||||
if (isAwaiting()) words.add("erwartet Bestätigung");
|
||||
if (isModerator()) words.add("Moderator");
|
||||
if (isAwaiting()) words.add("awaiting confirmation");
|
||||
if (isModerator()) words.add("moderator");
|
||||
if (isOwner()) words.add("owner");
|
||||
if (isSubscriber()) words.add("subscriber");
|
||||
return String.join(", ",words);
|
||||
}
|
||||
|
||||
|
||||
@@ -270,7 +270,7 @@ public class MailingList implements MessageHandler, ProblemListener {
|
||||
var member = ListMember.load(this,user);
|
||||
return member.hasState(ListMember.STATE_OWNER|ListMember.STATE_SUBSCRIBER); // owners may subscribe their own mailing lists
|
||||
} catch (SQLException e) {
|
||||
LOG.warn("Konnte Listen-Mitglied nicht laden: ",e);
|
||||
LOG.warn("Was not able to load ListMember: ",e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -303,7 +303,7 @@ public class MailingList implements MessageHandler, ProblemListener {
|
||||
ml.lastError = rs.getString(LAST_ERROR);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOG.debug("Konnte Mailing-Liste nicht laden: ",e);
|
||||
LOG.debug("Failed to load MailingList: ",e);
|
||||
}
|
||||
return ml;
|
||||
}
|
||||
@@ -325,7 +325,7 @@ public class MailingList implements MessageHandler, ProblemListener {
|
||||
.compile().exec();
|
||||
while (rs.next()) list.add(MailingList.from(rs));
|
||||
} catch (SQLException e) {
|
||||
LOG.debug("Konnte Mailing-Listen nicht laden: ",e);
|
||||
LOG.debug("Failed to load MailingLists: ",e);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
@@ -336,7 +336,7 @@ public class MailingList implements MessageHandler, ProblemListener {
|
||||
try {
|
||||
if (ListMember.load(this,user).isModerator()) return true;
|
||||
} catch (SQLException e) {
|
||||
LOG.debug("Fehler beim Laden des Listenmitglieds für ({}, {})",user.email(),email());
|
||||
LOG.debug("Error loading list member for ({}, {})",user.email(),email());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -346,7 +346,7 @@ public class MailingList implements MessageHandler, ProblemListener {
|
||||
try {
|
||||
if (ListMember.load(this,user).isOwner()) return true;
|
||||
} catch (SQLException e) {
|
||||
LOG.debug("Fehler beim Laden des Listenmitglieds für ({}, {})",user.email(),email());
|
||||
LOG.debug("Error loading list member for ({}, {})",user.email(),email());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -360,7 +360,7 @@ public class MailingList implements MessageHandler, ProblemListener {
|
||||
try {
|
||||
if (ListMember.load(this,user).isOwner()) return true;
|
||||
} catch (SQLException e) {
|
||||
LOG.debug("Fehler beim Laden des Listenmitglieds für ({}, {})",user.email(),email());
|
||||
LOG.debug("Error loading list member for ({}, {})",user.email(),email());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -422,7 +422,7 @@ public class MailingList implements MessageHandler, ProblemListener {
|
||||
|
||||
@Override
|
||||
public void onMessageReceived(Message message) throws MessagingException {
|
||||
LOG.info("Nachricht empfangen: {}",message.getFrom());
|
||||
LOG.info("Message received: {}",message.getFrom());
|
||||
String subject = message.getSubject();
|
||||
|
||||
try {
|
||||
@@ -487,7 +487,7 @@ public class MailingList implements MessageHandler, ProblemListener {
|
||||
while (rs.next()) list.add(MailingList.from(rs));
|
||||
rs.close();
|
||||
} catch (SQLException e) {
|
||||
LOG.warn("Auflisten der Mailinglisten fehlgeschlagen: ", e);
|
||||
LOG.warn("Listing mailing lists failed: ", e);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
@@ -574,13 +574,13 @@ public class MailingList implements MessageHandler, ProblemListener {
|
||||
.map(ListMember::user)
|
||||
.map(User::email)
|
||||
.collect(Collectors.joining(", "));
|
||||
var subject = t("Liste '{}' erfordert Aufmerksamkeit!",name());
|
||||
var text = t("Diese Liste hat eine E-Mail von {} empfangen. Der Absender ist nicht Mitglied der Liste.\nDie Email wurde in den '{}'-Ordner verschoben.\nSie können die Nachricht manuell weiterleiten oder verwerfen.",senderEmail,RETAINED_FOLDER);
|
||||
var subject = t("List '{}' requires attention!",name());
|
||||
var text = t("This list received an email from {}, who is not member of the list.\nThe email has been moved to the '{}' folder.\nYou may manually forward this message or drop it.",senderEmail,RETAINED_FOLDER);
|
||||
smtp.send(email(), name(), receivers,subject,text);
|
||||
|
||||
subject = t("Ihre Nachricht an {} wurde zurückgewiesen!",email());
|
||||
text = t("Sie haben versucht, eine Nachricht an die Liste '{}' zu senden. Das wurde verweigert, da Sie kein Mitglied der Liste (mit entsprechenden Berechtigungen) sind.\n",name());
|
||||
if (hasState(STATE_PUBLIC)) text += t("Sie können zu {} gehen und die Liste abonnieren. Versuchen Sie es danach erneut.",Configuration.instance().baseUrl());
|
||||
subject = t("Your message to {} was rejected!",email());
|
||||
text = t("You have tried to send a message to the list '{}', which failed. This is because you are not a (privileged) member of this list.\n",name());
|
||||
if (hasState(STATE_PUBLIC)) text += t("You may go to {} and subscribe to the list, then try again.",Configuration.instance().baseUrl());
|
||||
smtp.send(email(), name(), senderEmail,subject,text);
|
||||
} catch (SQLException e){
|
||||
LOG.error("Failed to load list of owners of mailing list. Retention notification was not sent to owners of {}",email(),e);
|
||||
@@ -646,7 +646,7 @@ public class MailingList implements MessageHandler, ProblemListener {
|
||||
rs.close();
|
||||
return result;
|
||||
} catch (SQLException e) {
|
||||
LOG.warn("Lesen der abbonnierbaren Mailinglisten von {} fehlgeschlagen.",user,e);
|
||||
LOG.warn("Failed to read subscribable mailinglists for {}",user,e);
|
||||
return Set.of();
|
||||
}
|
||||
}
|
||||
@@ -671,11 +671,11 @@ public class MailingList implements MessageHandler, ProblemListener {
|
||||
try {
|
||||
var config = Configuration.instance();
|
||||
var url = new StringBuilder(config.baseUrl()).append("/web/confirm?token=").append(member.token()).toString();
|
||||
var subject = t("[{}] Bitte bestätigen Sie Ihr Listen-Abonnement",name());
|
||||
var subject = t("[{}] Please confirm your list subscription",name());
|
||||
var text = template.add(URL,url).add(LIST_NAME,name()).render();
|
||||
smtp.send(email(),name(),user.email(),subject,text);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new MessagingException(t("Senden der Email an {} fehlgeschlagen",user.email()),e);
|
||||
throw new MessagingException(t("Failed to send email to {}",user.email()),e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -711,8 +711,8 @@ public class MailingList implements MessageHandler, ProblemListener {
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
public void test(User user) throws MessagingException, UnsupportedEncodingException {
|
||||
var subject = t("[{}] Test-Mail",name());
|
||||
var text = "Wenn Sie diese Nachricht empfangen haben, sind die SMTP-Einstellungen Ihrer Mailing-Liste korrekt.";
|
||||
var subject = t("[{}]: test mail",name());
|
||||
var text = "If you received this mail, the SMTP settings of your mailing list are correct.";
|
||||
smtp.login().send(email(),name(),user.email(),subject,text);
|
||||
}
|
||||
|
||||
@@ -720,7 +720,7 @@ public class MailingList implements MessageHandler, ProblemListener {
|
||||
try {
|
||||
return Arrays.asList(InternetAddress.parse(email)).stream();
|
||||
} catch (AddressException e) {
|
||||
LOG.debug("Parsen von {} fehlgeschlagen",email,e);
|
||||
LOG.debug("Was not able to parse {}",email,e);
|
||||
return new ArrayList<InternetAddress>().stream();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,24 @@ public class Post {
|
||||
return new File(filename);
|
||||
}
|
||||
|
||||
public static ArrayList<Post> find(MailingList list, String month, List<String> allowedSenders) throws SQLException {
|
||||
public static ArrayList<Post> find(MailingList list, String month) throws SQLException {
|
||||
var rs = Database.open()
|
||||
.select(TABLE_NAME,"*","strftime('%Y-%m',date/1000,'unixepoch') as month")
|
||||
.where(LIST,list.email())
|
||||
.where(MONTH,month)
|
||||
.sort(DATE)
|
||||
.compile()
|
||||
.exec();
|
||||
try {
|
||||
var result = new ArrayList<Post>();
|
||||
while (rs.next()) result.add(Post.from(rs));
|
||||
return result;
|
||||
} finally {
|
||||
rs.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static ArrayList<Post> find(MailingList list, String month, List<String> allowedSenders) throws SQLException {
|
||||
var query = Database.open()
|
||||
.select(TABLE_NAME,"*","strftime('%Y-%m',date/1000,'unixepoch') as month")
|
||||
.where(LIST,list.email())
|
||||
|
||||
@@ -268,7 +268,7 @@ public class User {
|
||||
* @return
|
||||
*/
|
||||
public Map<String,String> safeMap(){
|
||||
return Map.of(NAME,name,EMAIL,email,PERMISSIONS,permissionList(),PASSWORD,hashedPassword() == null ? "nein" : "ja");
|
||||
return Map.of(NAME,name,EMAIL,email,PERMISSIONS,permissionList(),PASSWORD,hashedPassword() == null ? "no" : "yes");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,44 +33,20 @@ public class ImapClient {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ListeningThread doStop() {
|
||||
stopped = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ListeningThread dropListeners() {
|
||||
listeners.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (!stopped) {
|
||||
try {
|
||||
sleep(5000);
|
||||
} catch (InterruptedException interruptedException) {
|
||||
interruptedException.printStackTrace();
|
||||
}
|
||||
try {
|
||||
openInbox();
|
||||
} catch (MessagingException e){
|
||||
LOG.warn("Verbindung-Problem:",e);
|
||||
problemListener.onImapException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void openInbox() throws MessagingException {
|
||||
LOG.debug("Verbinden und Einloggen…");
|
||||
Properties props = imapProps();
|
||||
session = Session.getInstance(props);
|
||||
Store store = session.getStore(Constants.IMAPS);
|
||||
store.connect(host,username,password);
|
||||
LOG.debug("Verbunden. Öffne {}:",folderName);
|
||||
inbox = (IMAPFolder)store.getFolder(folderName);
|
||||
inbox.open(IMAPFolder.READ_WRITE);
|
||||
|
||||
while (!stopped){
|
||||
handleMessages();
|
||||
problemListener.clearProblems();
|
||||
LOG.debug("Warte.");
|
||||
inbox.idle(true);
|
||||
}
|
||||
private void handle(Message message) throws MessagingException {
|
||||
LOG.debug("Handling {}",message.getSubject());
|
||||
for (MessageHandler listener : listeners) listener.onMessageReceived(message);
|
||||
}
|
||||
|
||||
private void handleMessages() throws MessagingException {
|
||||
@@ -85,35 +61,64 @@ public class ImapClient {
|
||||
}
|
||||
}
|
||||
|
||||
private void handle(Message message) throws MessagingException {
|
||||
LOG.debug("Verarbeite {}",message.getSubject());
|
||||
for (MessageHandler listener : listeners) listener.onMessageReceived(message);
|
||||
}
|
||||
|
||||
private Properties imapProps() {
|
||||
Properties props = new Properties();
|
||||
props.put(Constants.PROTOCOL,Constants.IMAPS);
|
||||
return props;
|
||||
}
|
||||
|
||||
public ListeningThread doStop() {
|
||||
stopped = true;
|
||||
return this;
|
||||
private void openInbox() throws MessagingException {
|
||||
LOG.debug("Connecting and logging in…");
|
||||
Properties props = imapProps();
|
||||
session = Session.getInstance(props);
|
||||
Store store = session.getStore(Constants.IMAPS);
|
||||
store.connect(host,username,password);
|
||||
LOG.debug("Connected, opening {}:",folderName);
|
||||
inbox = (IMAPFolder)store.getFolder(folderName);
|
||||
inbox.open(IMAPFolder.READ_WRITE);
|
||||
|
||||
while (!stopped){
|
||||
handleMessages();
|
||||
problemListener.clearProblems();
|
||||
LOG.debug("Idling.");
|
||||
inbox.idle(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (!stopped) {
|
||||
try {
|
||||
sleep(5000);
|
||||
} catch (InterruptedException interruptedException) {
|
||||
interruptedException.printStackTrace();
|
||||
}
|
||||
try {
|
||||
openInbox();
|
||||
} catch (MessagingException e){
|
||||
LOG.warn("Connection problem:",e);
|
||||
problemListener.onImapException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class Heartbeat extends Thread{
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Heartbeat.class);
|
||||
private boolean stopped = false;
|
||||
|
||||
public Heartbeat doStop() {
|
||||
stopped = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (!stopped){
|
||||
try {
|
||||
sleep(300034);
|
||||
if (inbox != null) continue;
|
||||
LOG.debug("Sende NOOP");
|
||||
LOG.debug("sending NOOP");
|
||||
inbox.doCommand(protocol -> {
|
||||
protocol.simpleCommand("NOOP",null);
|
||||
return null;
|
||||
@@ -123,11 +128,6 @@ public class ImapClient {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Heartbeat doStop() {
|
||||
stopped = true;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public ImapClient(String host, int port, String username, String password, String folderName,ProblemListener listener) {
|
||||
@@ -148,7 +148,7 @@ public class ImapClient {
|
||||
public void dropMailsOlderThan(Integer holdTime) throws MessagingException {
|
||||
var now = new Date();
|
||||
if (holdTime == null) return;
|
||||
LOG.info("Removing mails older than {} days:",holdTime);
|
||||
LOG.debug("Removing mails older than {} days:",holdTime);
|
||||
if (!inbox.isOpen()) inbox.open(IMAPFolder.READ_WRITE);
|
||||
for (Message message : inbox.getMessages()){
|
||||
Date receivedDate = message.getReceivedDate();
|
||||
@@ -165,27 +165,15 @@ public class ImapClient {
|
||||
inbox.expunge();
|
||||
}
|
||||
|
||||
public String folderName(){
|
||||
return folderName;
|
||||
}
|
||||
|
||||
|
||||
public String host(){
|
||||
return host;
|
||||
}
|
||||
|
||||
public String username(){
|
||||
return username;
|
||||
}
|
||||
|
||||
public String password(){
|
||||
return password;
|
||||
}
|
||||
|
||||
public int port(){
|
||||
return port;
|
||||
}
|
||||
|
||||
public String folderName(){
|
||||
return folderName;
|
||||
}
|
||||
|
||||
public ImapClient move(Message message, String destinationFolder) throws MessagingException {
|
||||
if (listeningThread == null || listeningThread.stopped) throw new IllegalStateException("IMAP client not connected!");
|
||||
var source = message.getFolder();
|
||||
@@ -200,14 +188,22 @@ public class ImapClient {
|
||||
return this;
|
||||
}
|
||||
|
||||
public String password(){
|
||||
return password;
|
||||
}
|
||||
|
||||
public int port(){
|
||||
return port;
|
||||
}
|
||||
|
||||
|
||||
public ImapClient start() {
|
||||
stop();
|
||||
|
||||
LOG.info("Erzeuge ListeningThread für {}…",username);
|
||||
LOG.info("Creating ListeningThread for {}…",username);
|
||||
(listeningThread = new ListeningThread()).start();
|
||||
|
||||
LOG.info("Erzeuge Heartbeat für {}…",username);
|
||||
LOG.info("Creating Heartbeat for {}…",username);
|
||||
(heartbeat = new Heartbeat()).start();
|
||||
|
||||
return this;
|
||||
@@ -215,7 +211,7 @@ public class ImapClient {
|
||||
|
||||
public ImapClient stop(){
|
||||
if (listeningThread != null) {
|
||||
LOG.info("Stoppe alten ListeningThread für {}…",username);
|
||||
LOG.info("Stopping old ListeningThread for {}…",username);
|
||||
listeningThread.dropListeners().doStop();
|
||||
listeningThread = null;
|
||||
}
|
||||
@@ -225,4 +221,8 @@ public class ImapClient {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public String username(){
|
||||
return username;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.mail.*;
|
||||
import javax.mail.internet.*;
|
||||
import javax.ws.rs.HEAD;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@@ -63,7 +62,7 @@ public class SmtpClient {
|
||||
MimeMultipart multipart = new MimeMultipart();
|
||||
if (forwardAsAttachment){
|
||||
MimeBodyPart bodyPart = new MimeBodyPart();
|
||||
bodyPart.setText("Die weitergeleitete Nachricht findest du im Anhang dieser E-Mail!\n");
|
||||
bodyPart.setText("Find the forwarded message in the attachment(s)!\n");
|
||||
multipart.addBodyPart(bodyPart);
|
||||
|
||||
// create another body part to contain the message to be forwarded
|
||||
@@ -82,6 +81,9 @@ public class SmtpClient {
|
||||
send(forward);
|
||||
}
|
||||
|
||||
public String host() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public SmtpClient login(){
|
||||
if (session == null) {
|
||||
@@ -93,11 +95,25 @@ public class SmtpClient {
|
||||
props.put(ENVELOPE_FROM,from);
|
||||
|
||||
session = Session.getInstance(props);
|
||||
LOG.debug("Neue Session erzeugt: {}", session);
|
||||
LOG.debug("Created new session: {}", session);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public String password() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public int port() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void send(Message message) throws MessagingException {
|
||||
LOG.debug("Versende Mail…");
|
||||
Transport.send(message,username,password);
|
||||
LOG.debug("…versendet");
|
||||
}
|
||||
|
||||
public void send(String senderAdress, String senderName, String receivers, String subject, String content) throws MessagingException, UnsupportedEncodingException {
|
||||
login();
|
||||
MimeMessage message = new MimeMessage(session);
|
||||
@@ -114,27 +130,7 @@ public class SmtpClient {
|
||||
send(message);
|
||||
}
|
||||
|
||||
public void send(Message message) throws MessagingException {
|
||||
LOG.debug("Versende Mail…");
|
||||
Transport.send(message,username,password);
|
||||
LOG.debug("…versendet");
|
||||
|
||||
}
|
||||
|
||||
public String host() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public int port() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public String username() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String password() {
|
||||
return password;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.time.Month;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -48,22 +47,21 @@ public class Rest extends HttpServlet {
|
||||
private static final String SUCCESS = "success";
|
||||
|
||||
private Map addPermission(String userEmail, String permissions) {
|
||||
if (userEmail == null || userEmail.isBlank()) return Map.of(ERROR,"E-Mail-Adresse des Listenmitglieds nicht angegeben!");
|
||||
if (userEmail == null || userEmail.isBlank()) return Map.of(ERROR,"missing user email address!");
|
||||
try {
|
||||
int perm = Integer.parseInt(permissions);
|
||||
var user = User.loadAll(List.of(userEmail)).stream().findAny().orElse(null);
|
||||
if (user == null) return Map.of(ERROR,t("Laden des Nutzers für die Adresse {} fehlgeschlagen",userEmail));
|
||||
if (user == null) return Map.of(ERROR,t("Failed to load user for address {}",userEmail));
|
||||
user.addPermission(perm);
|
||||
} catch (NumberFormatException nfe){
|
||||
return Map.of(ERROR,"Keine gültigen Berechtigungen übergeben!");
|
||||
return Map.of(ERROR,"no valid permissions provided!");
|
||||
} catch (SQLException e) {
|
||||
LOG.debug("Laden des Nutzers für die Adresse {} fehlgeschlagen",userEmail,e);
|
||||
return Map.of(ERROR,t("Laden des Nutzers für die Adresse {} fehlgeschlagen",userEmail));
|
||||
LOG.debug("Failed to load user for address {}",userEmail,e);
|
||||
return Map.of(ERROR,t("Failed to load user for address {}",userEmail));
|
||||
}
|
||||
return Map.of(SUCCESS,"Nutzer-Berechtigungen aktualisiert");
|
||||
return Map.of(SUCCESS,"Updated user permissions");
|
||||
}
|
||||
|
||||
|
||||
private Map<String,Object> archive(HttpServletRequest req, User user) throws SQLException {
|
||||
var list = Util.getMailingList(req);
|
||||
if (list == null) throw new IllegalArgumentException(t("You are trying to access a non-existing list!"));
|
||||
@@ -100,7 +98,7 @@ public class Rest extends HttpServlet {
|
||||
} catch (SQLException e) {
|
||||
LOG.warn("Was not able to load listmember for {}/{}",list.email(),user.email(),e);
|
||||
}
|
||||
if (!allowed) return Map.of(ERROR,"Es ist dir nicht gestattet, diese Liste zu löschen!");
|
||||
if (!allowed) return Map.of(ERROR,"You are not allowed to remove this list!");
|
||||
try {
|
||||
list.hide(true).enable(false).openForGuests(false).openForSubscribers(false);
|
||||
list.members().forEach(listMember -> {
|
||||
@@ -114,7 +112,7 @@ public class Rest extends HttpServlet {
|
||||
} catch (Exception e) {
|
||||
LOG.debug("Disabling and hiding of {} failed",list.email(),e);
|
||||
}
|
||||
return Map.of(SUCCESS,t("Liste {} deaktiviert, Abonnement gesperrt, Liste de-publiziert. Mitglieder wurden entfernt.",list.email()));
|
||||
return Map.of(SUCCESS,t("List {} disabled, closed for subscribers and hidden. Members have been removed.",list.email()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -139,30 +137,30 @@ public class Rest extends HttpServlet {
|
||||
}
|
||||
|
||||
private Map dropPermission(String userEmail, String permissions) {
|
||||
if (userEmail == null || userEmail.isBlank()) return Map.of(ERROR,"Nutzer-Emailadresse fehlt!");
|
||||
if (userEmail == null || userEmail.isBlank()) return Map.of(ERROR,"missing user email address!");
|
||||
try {
|
||||
int perm = Integer.parseInt(permissions);
|
||||
var user = User.loadAll(List.of(userEmail)).stream().findAny().orElse(null);
|
||||
if (user == null) return Map.of(ERROR,t("Laden des Nutzers für die Adresse {} fehlgeschlagen",userEmail));
|
||||
if (user == null) return Map.of(ERROR,t("Failed to load user for address {}",userEmail));
|
||||
user.dropPermission(perm);
|
||||
} catch (NumberFormatException nfe){
|
||||
return Map.of(ERROR,"Keine gültigen Berechtigungen übergeben!");
|
||||
return Map.of(ERROR,"no valid permissions provided!");
|
||||
} catch (SQLException e) {
|
||||
LOG.debug("Laden des Nutzers für die Adresse {} fehlgeschlagen",userEmail,e);
|
||||
return Map.of(ERROR,t("Laden des Nutzers für die Adresse {} fehlgeschlagen",userEmail));
|
||||
LOG.debug("Failed to load user for address {}",userEmail,e);
|
||||
return Map.of(ERROR,t("Failed to load user for address {}",userEmail));
|
||||
}
|
||||
return Map.of(SUCCESS,"Nutzer-Berechtigungen aktualisiert");
|
||||
return Map.of(SUCCESS,t("Updated user permissions"));
|
||||
}
|
||||
|
||||
private Map enableList(MailingList list, User user, boolean enable) {
|
||||
if (list == null) return Map.of(ERROR,"Keine Listen-Email übertragen!");
|
||||
if (!list.mayBeAlteredBy(user)) Map.of(ERROR,t("Du bist nicht berechtigt, '{}' zu bearbeiten!",list.email()));
|
||||
if (list == null) return Map.of(ERROR,"no list email provided!");
|
||||
if (!list.mayBeAlteredBy(user)) Map.of(ERROR,t("You are not allowed to edit '{}'",list.email()));
|
||||
try {
|
||||
list.enable(enable);
|
||||
return Map.of(SUCCESS,t("Mailing-Liste '{}' wurde {}!",list.email(),enable ? "aktiviert" : "inaktiviert"));
|
||||
return Map.of(SUCCESS,t("Mailing list '{}' was {}!",list.email(),enable ? "enabled" : "disabled"));
|
||||
} catch (SQLException e) {
|
||||
LOG.error("Aktivieren/Inaktivieren der Mailing-Liste fehlgeschlagen: ",e);
|
||||
return Map.of(ERROR,t("Aktualisieren der Liste '{}' fehlgeschlagen",list.email()));
|
||||
LOG.error("Failed to enable/disable mailing list: ",e);
|
||||
return Map.of(ERROR,t("Failed to update list '{}'",list.email()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,8 +180,8 @@ public class Rest extends HttpServlet {
|
||||
try {
|
||||
json.put("users", (user.hashPermission(User.PERMISSION_ADMIN) ? User.loadAll() : List.of(user)).stream().map(User::safeMap).toList());
|
||||
} catch (SQLException e) {
|
||||
LOG.debug("Laden der Nutzerliste fehlgeschlagen:",e);
|
||||
json.put(ERROR,"Laden der Nutzerliste fehlgeschlagen");
|
||||
LOG.debug("Failed to load user list:",e);
|
||||
json.put(ERROR,"failed to load user list");
|
||||
}
|
||||
break;
|
||||
case LIST_MODERATED:
|
||||
@@ -193,7 +191,7 @@ public class Rest extends HttpServlet {
|
||||
json.put("lists", MailingList.subscribable(user).stream().map(MailingList::minimalMap).toList());
|
||||
break;
|
||||
default:
|
||||
json.put(ERROR,t("Kein Handler für den Pfad '{}'!",path));
|
||||
json.put(ERROR,t("No handler for path '{}'!",path));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@@ -205,7 +203,7 @@ public class Rest extends HttpServlet {
|
||||
json.put("lists", MailingList.subscribable().stream().map(MailingList::minimalMap).toList());
|
||||
break;
|
||||
default:
|
||||
json.put(ERROR,"Nicht eingeloggt!");
|
||||
json.put(ERROR,"Not logged in!");
|
||||
}
|
||||
}
|
||||
try {
|
||||
@@ -213,7 +211,7 @@ public class Rest extends HttpServlet {
|
||||
resp.getWriter().println(json.toJSONString());
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
return t("Konnte Anfrage nicht verarbeiten: {}",e.getMessage());
|
||||
return t("Failed to handle request: {}",e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,38 +270,38 @@ public class Rest extends HttpServlet {
|
||||
case USER_ADD_PERMISSION:
|
||||
if (user.hashPermission(User.PERMISSION_ADMIN)){
|
||||
json.putAll(addPermission(userEmail,permissions));
|
||||
} else json.put(ERROR,"Sie haben nicht die Berechtigung, um Berechtigungen zu ändern!");
|
||||
} else json.put(ERROR,"You are not allowed to alter user permissions!");
|
||||
break;
|
||||
case USER_DROP_PERMISSION:
|
||||
if (user.hashPermission(User.PERMISSION_ADMIN)){
|
||||
json.putAll(dropPermission(userEmail,permissions));
|
||||
} else json.put(ERROR,"Sie haben nicht die Berechtigung, um Berechtigungen zu ändern!");
|
||||
} else json.put(ERROR,"You are not allowed to alter user permissions!");
|
||||
break;
|
||||
default:
|
||||
json.put(ERROR,t("Kein Handler für den Pfad '{}'!",path));
|
||||
json.put(ERROR,t("No handler for path '{}'!",path));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
json.put(ERROR,"Nicht eingeloggt!");
|
||||
json.put(ERROR,"Not logged in!");
|
||||
}
|
||||
try {
|
||||
resp.setContentType("application/json");
|
||||
resp.getWriter().println(json.toJSONString());
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
return t("Konnte Anfrage nicht verarbeiten: {}",e.getMessage());
|
||||
return t("Failed to handle request: {}",e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> hideList(MailingList list, User user, boolean hide) {
|
||||
if (list == null) return Map.of(ERROR,"Keine Listen-Email übertragen!");
|
||||
if (list == null) return Map.of(ERROR,"no list email provided!");
|
||||
if (!list.mayBeAlteredBy(user)) Map.of(ERROR,t("You are not allowed to edit '{}'",list.email()));
|
||||
try {
|
||||
list.hide(hide);
|
||||
return Map.of(SUCCESS,t("Mailing-Liste '{}' wurde {}!",list.email(),hide ? "versteckt" : "veröffentlicht"));
|
||||
return Map.of(SUCCESS,t("Mailing list '{}' was {}!",list.email(),hide ? "hidden" : "made public"));
|
||||
} catch (SQLException e) {
|
||||
LOG.error("Veröffentlichen/Verstekcen der Mailing-Liste fehlgeschlagen: ",e);
|
||||
return Map.of(ERROR,t("Aktualisieren der Liste '{}' fehlgeschlagen",list.email()));
|
||||
LOG.error("Failed to (un)hide mailing list: ",e);
|
||||
return Map.of(ERROR,t("Failed to update list '{}'",list.email()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,7 +321,7 @@ public class Rest extends HttpServlet {
|
||||
}
|
||||
|
||||
private Map listDetail(MailingList list, User user) {
|
||||
if (list == null) return Map.of(ERROR,"Keine Listen-Email übertragen!");
|
||||
if (list == null) return Map.of(ERROR,"no list email provided!");
|
||||
var map = new HashMap<>();
|
||||
if (list.hasState(MailingList.STATE_FORWARD_FROM)) map.put(KEY_FORWARD_FROM,true);
|
||||
if (list.hasState(MailingList.STATE_FORWARD_ATTACHED)) map.put(KEY_FORWARD_ATTACHED,true);
|
||||
@@ -368,8 +366,8 @@ public class Rest extends HttpServlet {
|
||||
}
|
||||
|
||||
private Map<String, Object> listMembers(MailingList list, User user) {
|
||||
if (list == null) return Map.of(ERROR,"Keine Listen-Email übertragen!");
|
||||
if (!list.membersMayBeListedBy(user)) Map.of(ERROR,t("Es ist dir nicht gestattet, die Mitglieder von '{}' aufzulisten",list.email()));
|
||||
if (list == null) return Map.of(ERROR,"no list email provided!");
|
||||
if (!list.membersMayBeListedBy(user)) Map.of(ERROR,t("You are not allowed to list members of '{}'",list.email()));
|
||||
try {
|
||||
var members = list.members()
|
||||
.sorted((m1,m2)->m1.user().name().compareTo(m2.user().name()))
|
||||
@@ -377,20 +375,20 @@ public class Rest extends HttpServlet {
|
||||
.toList();
|
||||
return Map.of(MEMBERS,members,LIST,list.minimalMap());
|
||||
} catch (SQLException e) {
|
||||
LOG.error("Laden der Mitglieder-Liste fehlgeschlagen: ",e);
|
||||
return Map.of(ERROR,t("Laden der Mitglieder-Liste von '{}' fehlgeschlagen!",list.email()));
|
||||
LOG.error("Failed to load member list: ",e);
|
||||
return Map.of(ERROR,t("Failed to load member list '{}'",list.email()));
|
||||
}
|
||||
}
|
||||
|
||||
private Map testList(MailingList list, User user) {
|
||||
if (list == null) return Map.of(ERROR,"Keine Listen-Email übertragen!");
|
||||
if (!list.mayBeTestedBy(user)) Map.of(ERROR,t("Es ist dir nicht gestattet, '{}' zu testen",list.email()));
|
||||
if (list == null) return Map.of(ERROR,"no list email provided!");
|
||||
if (!list.mayBeTestedBy(user)) Map.of(ERROR,t("You are not allowed to test '{}'",list.email()));
|
||||
try {
|
||||
list.test(user);
|
||||
return Map.of(SUCCESS,t("Test-Email an {} versendet",user.email()));
|
||||
return Map.of(SUCCESS,t("Sent test email to {}",user.email()));
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Senden der Test-Email fehlgeschlagen",e);
|
||||
return Map.of(ERROR,t("Senden der Test-Email an {} fehlgeschlagen",user.email()));
|
||||
LOG.warn("Failed to send test email",e);
|
||||
return Map.of(ERROR,t("Failed to send test email to {}",user.email()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,14 +31,14 @@ 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("Datei {} existiert nicht!",filename);
|
||||
if (!file.exists()) return t("File {} does not exist!",filename);
|
||||
try {
|
||||
var content = Files.readAllBytes(file.toPath());
|
||||
var out = resp.getOutputStream();
|
||||
out.write(content);
|
||||
out.flush();
|
||||
} catch (IOException e) {
|
||||
return t("Ladend der Datei '{}' fehlgeschlagen!",filename);
|
||||
return t("Failed to load file '{}'!",filename);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -52,10 +52,10 @@ public abstract class TemplateServlet extends HttpServlet {
|
||||
resp.getWriter().println(template.render());
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
return t("Laden der Vorlage '{}' fehlgeschlagen",path);
|
||||
return t("Failed to load template '{}'",path);
|
||||
}
|
||||
}
|
||||
return t("Keine Vorlage für den Pfad '{}' vorhanden!",path);
|
||||
return t("No template for path '{}'!",path);
|
||||
}
|
||||
|
||||
protected void loadTemplates() {
|
||||
|
||||
@@ -11,7 +11,6 @@ import org.slf4j.LoggerFactory;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.ws.rs.HEAD;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.security.InvalidKeyException;
|
||||
@@ -57,7 +56,7 @@ public class Web extends TemplateServlet {
|
||||
data.put(USER, user.safeMap());
|
||||
|
||||
if (!user.hashPermission(User.PERMISSION_CREATE_LISTS)){
|
||||
data.put(ERROR,t("Ihnen ist es nicht gestattet, neue Mailinglisten anzulegen!"));
|
||||
data.put(ERROR,t("You are not allowed to create new mailing lists!"));
|
||||
return loadTemplate(ADMIN,data,resp);
|
||||
}
|
||||
|
||||
@@ -89,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, "Name und Adresse der Liste sind notwendige Felder!");
|
||||
data.put(ERROR, "List name and address are required!");
|
||||
return loadTemplate(ADD_LIST, data, resp);
|
||||
}
|
||||
|
||||
if (!Util.isEmail(email)) {
|
||||
data.put(ERROR, t("Listen-E-Mail-Adresse ({}) ist keine gültige E-Mail-Adresse!", email));
|
||||
data.put(ERROR, t("List email ({}) is not a valid email address!", email));
|
||||
return loadTemplate(ADD_LIST, data, resp);
|
||||
}
|
||||
|
||||
if (imapHost == null || imapHost.isBlank() || imapUser == null || imapUser.isBlank() || imapPass == null || imapPass.isBlank()) {
|
||||
data.put(ERROR, "IMAP-Zugangsdaten sind erforderlich!");
|
||||
data.put(ERROR, "IMAP credentials are required!");
|
||||
return loadTemplate(ADD_LIST, data, resp);
|
||||
}
|
||||
|
||||
@@ -108,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("'{}' ist keine gültige Port-Nummer!", req.getParameter(IMAP_PORT)));
|
||||
data.put(ERROR, t("'{}' is not a proper port number!", 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-Zugangsdaten sind erforderlich!");
|
||||
data.put(ERROR, "SMTP credentials are required!");
|
||||
return loadTemplate(ADD_LIST, data, resp);
|
||||
}
|
||||
|
||||
@@ -121,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("'{}' ist keine gültige Port-Nummer!", req.getParameter(SMTP_PORT)));
|
||||
data.put(ERROR, t("'{}' is not a proper port number!", req.getParameter(SMTP_PORT)));
|
||||
return loadTemplate(ADD_LIST, data, resp);
|
||||
}
|
||||
|
||||
@@ -130,7 +129,7 @@ public class Web extends TemplateServlet {
|
||||
ListMember.create(list, user, ListMember.STATE_OWNER);
|
||||
return redirectTo(ADMIN, resp);
|
||||
} catch (SQLException e) {
|
||||
return t("Erzeugen der Liste '{}' fehlgeschlagen: {}", name, e.getMessage());
|
||||
return t("Failed to create list '{}': {}", name, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,17 +153,17 @@ public class Web extends TemplateServlet {
|
||||
private String confirm(HttpServletRequest req, HttpServletResponse resp) {
|
||||
try {
|
||||
var token = req.getParameter(TOKEN);
|
||||
if (token== null || token.isBlank()) return t("Ungültiger oder fehlender Token!");
|
||||
if (token== null || token.isBlank()) return t("Invalid or missing token!");
|
||||
var listMember = ListMember.confirm(token);
|
||||
if (listMember != null) {
|
||||
listMember.sendConfirmationMail(getTemplate("confirmation_mail"));
|
||||
|
||||
return loadTemplate(INDEX,Map.of(USER,listMember.user().safeMap(),NOTES,"Listen-Mitgliedschaft bestätigt!"),resp);
|
||||
return loadTemplate(INDEX,Map.of(USER,listMember.user().safeMap(),NOTES,"Confirmed list subscription!"),resp);
|
||||
}
|
||||
return t("Nutzer oder Token unbekannt");
|
||||
return t("Unknown user or token");
|
||||
} catch (Exception e) {
|
||||
LOG.debug("Bestätigung des Listen-Abonnements fehlgeschlagen:",e);
|
||||
return t("Bestätigung des Listen-Abonnements fehlgeschlagen!");
|
||||
LOG.debug("Failed to confirm list membership:",e);
|
||||
return t("Confirmation of list membership failed!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,17 +220,17 @@ public class Web extends TemplateServlet {
|
||||
data.put(SMTP_PORT, smtpPort);
|
||||
|
||||
if (name == null || name.isBlank() || email == null || email.isBlank()) {
|
||||
data.put(ERROR, "Listen-Name und -adresse sind erforderlich!");
|
||||
data.put(ERROR, "List name and address are required!");
|
||||
return loadTemplate(EDIT_LIST, data, resp);
|
||||
}
|
||||
|
||||
if (!Util.isEmail(email)) {
|
||||
data.put(ERROR, t("Listen-E-Mail ({}) ist keine gültige Mailadresse!", email));
|
||||
data.put(ERROR, t("List email ({}) is not a valid email address!", email));
|
||||
return loadTemplate(EDIT_LIST, data, resp);
|
||||
}
|
||||
|
||||
if (imapHost == null || imapHost.isBlank() || imapUser == null || imapUser.isBlank() || imapPass == null || imapPass.isBlank()) {
|
||||
data.put(ERROR, "IMAP-Zugangsdaten sind erforderlich!");
|
||||
data.put(ERROR, "IMAP credentials are required!");
|
||||
return loadTemplate(EDIT_LIST, data, resp);
|
||||
}
|
||||
|
||||
@@ -240,12 +239,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("'{}' ist keine gültige Port-Nummer!", req.getParameter(IMAP_PORT)));
|
||||
data.put(ERROR, t("'{}' is not a proper port number!", req.getParameter(IMAP_PORT)));
|
||||
return loadTemplate(EDIT_LIST, data, resp);
|
||||
}
|
||||
|
||||
if (smtpHost == null || smtpHost.isBlank() || smtpUser == null || smtpUser.isBlank() || smtpPass == null || smtpPass.isBlank()) {
|
||||
data.put(ERROR, "SMTP-Zugangsdaten sind erforderlich!");
|
||||
data.put(ERROR, "SMTP credentials are required!");
|
||||
return loadTemplate(EDIT_LIST, data, resp);
|
||||
}
|
||||
|
||||
@@ -253,7 +252,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("'{}' ist keine gültige Port-Nummer!", req.getParameter(SMTP_PORT)));
|
||||
data.put(ERROR, t("'{}' is not a proper port number!", req.getParameter(SMTP_PORT)));
|
||||
return loadTemplate(EDIT_LIST, data, resp);
|
||||
}
|
||||
|
||||
@@ -261,7 +260,7 @@ public class Web extends TemplateServlet {
|
||||
return loadTemplate(ADMIN,data,resp);
|
||||
} catch (SQLException e) {
|
||||
LOG.warn("Editing list {} by {} failed",list.email(),user.email(),e);
|
||||
return t("Bearbeiten der Liste {} durch {} fehlgeschlagen",list.email(),user.email());
|
||||
return t("Editing list {} by {} failed",list.email(),user.email());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,7 +294,7 @@ public class Web extends TemplateServlet {
|
||||
return post(req,resp);
|
||||
case RELOAD:
|
||||
loadTemplates();
|
||||
data.put(NOTES,t("Vorlagen wurden neu geladen"));
|
||||
data.put(NOTES,t("Templates have been reloaded"));
|
||||
path = INDEX;
|
||||
case CSS:
|
||||
case INDEX:
|
||||
@@ -305,16 +304,16 @@ public class Web extends TemplateServlet {
|
||||
data.put(LIST,list.email());
|
||||
return loadTemplate(path, data, resp);
|
||||
}
|
||||
return t("Es ist ihnen nicht gestattet, '{}' zu abonnieren!",list.email());
|
||||
return t("You are not allowed to subscribe to '{}'!",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("Nutzer-Datenbank ist leer. Admin-Nutzer wird hiermit angelegt:")), resp);
|
||||
if (User.noUsers()) return loadTemplate(REGISTER, Map.of(NOTES,t("User database is empty. Create admin user first:")), resp);
|
||||
return loadTemplate(path,null,resp);
|
||||
} catch (SQLException e) {
|
||||
return "Fehler beim Lesen der Datenbank!";
|
||||
return "Error reading user database!";
|
||||
}
|
||||
case LOGOUT:
|
||||
req.getSession().invalidate();
|
||||
@@ -347,8 +346,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("Nutzername oder Passwort fehlen!")), resp);
|
||||
if (!Util.isEmail(email)) return loadTemplate("login", Map.of("error",t("'{}' ist keine gültige Mailadresse!",email)), resp);
|
||||
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);
|
||||
try {
|
||||
var user = User.loadUser(email,pass);
|
||||
req.getSession().setAttribute("user",user);
|
||||
@@ -356,10 +355,10 @@ public class Web extends TemplateServlet {
|
||||
resp.sendRedirect(String.join("/",WEB_ROOT,"admin"));
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
LOG.warn("Static.handleLogin fehlgeschlagen:",e);
|
||||
LOG.warn("Static.handleLogin failed:",e);
|
||||
Thread.sleep(10000);
|
||||
} finally {
|
||||
return loadTemplate("login", Map.of(ERROR,t("Ungültiger Nutzername oder ungültiges Passwort!"),EMAIL,email), resp);
|
||||
return loadTemplate("login", Map.of(ERROR,t("Invalid username/password"),EMAIL,email), resp);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -385,7 +384,7 @@ public class Web extends TemplateServlet {
|
||||
return unsubscribe(req,resp);
|
||||
}
|
||||
|
||||
return t("Kein Handler für den Pfad '{}'!",path);
|
||||
return t("No handler for path {}!",path);
|
||||
}
|
||||
|
||||
private String inspect(HttpServletRequest req, HttpServletResponse resp) {
|
||||
@@ -398,12 +397,12 @@ public class Web extends TemplateServlet {
|
||||
var list = Util.getMailingList(req);
|
||||
if (list == null) {
|
||||
error = true;
|
||||
data.put(ERROR, t("Keine gültige MailingListe übermittelt!"));
|
||||
data.put(ERROR, t("No valid mailing list provided!"));
|
||||
} else data.put(LIST, list.email());
|
||||
|
||||
if (!error && !list.mayBeAlteredBy(user)) {
|
||||
error = true;
|
||||
data.put(ERROR,t("Es ist Ihnen nicht gestattet, die Einselltungen dieser Mailingliste zu verändern!"));
|
||||
data.put(ERROR,t("You are not alter settings of this list!"));
|
||||
}
|
||||
|
||||
if (!error){
|
||||
@@ -417,10 +416,10 @@ public class Web extends TemplateServlet {
|
||||
.openForSubscribers(Util.getCheckbox(req,KEY_OPEN_FOR_SUBSCRIBERS))
|
||||
.archive(Util.getCheckbox(req,KEY_ARCHIVE))
|
||||
.deleteMessages(Util.getCheckbox(req,KEY_DELETE_MESSAGES),req.getParameter(HOLD_TIME));
|
||||
data.put(NOTES,t("Mailing-Liste aktualisiert!"));
|
||||
data.put(NOTES,t("Sucessfully updated MailingList!"));
|
||||
} catch (SQLException e){
|
||||
LOG.warn("Aktualisierung der Mailing-Liste fehlgeschlagen:",e);
|
||||
data.put(ERROR,t("Aktualisierung der Mailing-Liste fehlgeschlagen!"));
|
||||
LOG.warn("Failed to update MailingList:",e);
|
||||
data.put(ERROR,t("Failed to update MailingList!"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,7 +438,7 @@ public class Web extends TemplateServlet {
|
||||
return loadTemplate("post",map,resp);
|
||||
} catch (SQLException | IOException e) {
|
||||
LOG.debug("Failed to load post from file!",e);
|
||||
return t("Laden der Nachricht aus Datei fehlgeschlagen!");
|
||||
return t("Failed to load post from file!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -448,7 +447,7 @@ public class Web extends TemplateServlet {
|
||||
resp.sendRedirect(String.join("/",WEB_ROOT,page));
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
return t("Weiterleitung nach {} fehlgeschlagen: {}", page, e.getMessage());
|
||||
return t("Was not able to redirect to {} page: {}", page, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,15 +463,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,"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);
|
||||
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);
|
||||
|
||||
var firstUser = false;
|
||||
try {
|
||||
firstUser = User.noUsers();
|
||||
} catch (SQLException e) {
|
||||
return t("Fehler beim Zugriff auf die Nutzer-Datenbank: {}",e.getMessage());
|
||||
return t("Failed to access user database: {}",e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
@@ -482,8 +481,8 @@ public class Web extends TemplateServlet {
|
||||
req.getSession().setAttribute("user",user);
|
||||
return redirectTo(INDEX,resp);
|
||||
} catch (SQLException e) {
|
||||
LOG.warn("Erzeugen des neuen Nutzers fehlgeschlagen:",e);
|
||||
return t("Erzeugen des neuen Nutzers fehlgeschlagen: {}",e.getMessage());
|
||||
LOG.warn("Failed to create new user:",e);
|
||||
return t("Failed to create new user: {}",e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,12 +499,12 @@ public class Web extends TemplateServlet {
|
||||
|
||||
|
||||
if (list == null){
|
||||
data.put(ERROR,"Formular-Daten enthalten keine Liste!");
|
||||
data.put(ERROR,"No list provided by form data!");
|
||||
return loadTemplate(SUBSCRIBE,data,resp);
|
||||
|
||||
}
|
||||
if (name == null || name.isBlank() || email == null || email.isBlank()){
|
||||
data.put(ERROR,"Name und E-Mail-Adresse sind für das Abonnieren der Mailingliste erforderlich!");
|
||||
data.put(ERROR,"Name and email are required fields for list subscription!");
|
||||
return loadTemplate(SUBSCRIBE,data,resp);
|
||||
}
|
||||
if (pass != null && pass.isBlank()) pass = null;
|
||||
@@ -522,36 +521,36 @@ public class Web extends TemplateServlet {
|
||||
// success → subscribe
|
||||
} catch (InvalidKeyException | SQLException e) {
|
||||
// invalid credentials
|
||||
data.put(ERROR,t("'{}' gibt es schon in der Datenbank, hat dort aber ein anderes Passwort!",email));
|
||||
data.put(ERROR,t("'{}' already in database, but with different password!",email));
|
||||
return loadTemplate(SUBSCRIBE,data,resp);
|
||||
}
|
||||
}
|
||||
data.put(USER,user.safeMap());
|
||||
|
||||
if (!list.isOpenFor(user)){
|
||||
data.put(ERROR,t("Ihnen ist es nicht gestattet, '{}' zu abonnieren!",list.email()));
|
||||
data.put(ERROR,t("You are not allowed to join {}!",list.email()));
|
||||
return loadTemplate(SUBSCRIBE,data,resp);
|
||||
}
|
||||
|
||||
try {
|
||||
list.requestSubscription(user,skipConfirmation,getTemplate("subscribe_mail"));
|
||||
if (skipConfirmation) {
|
||||
data.put(NOTES, t("'{}' hat die Mailingliste '{}' erfolgreich abonniert.", user.email(), list.email()));
|
||||
data.put(NOTES, t("Successfully subscribed '{}' to '{}'.", user.email(), list.email()));
|
||||
} else {
|
||||
data.put(NOTES, t("Bestätigungs-Email wurde an '{} versendet.", user.email()));
|
||||
data.put(NOTES, t("Sent confirmation mail to '{}.", user.email()));
|
||||
}
|
||||
return loadTemplate(INDEX,data,resp);
|
||||
} catch (SQLException sqle) {
|
||||
LOG.debug("Abonnieren der Liste fehlgeschlagen: ",sqle);
|
||||
LOG.debug("List subscription failed: ",sqle);
|
||||
var cause = getCausingException(sqle);
|
||||
int code = cause.getErrorCode();
|
||||
if (code == PRIMARY_KEY_CONSTRAINT) {// user already exists
|
||||
data.put(ERROR,t("Sie haben diese Liste bereits abonniert!",sqle.getMessage()));
|
||||
} else data.put(ERROR,t("Abonnieren der Liste fehlgeschlagen: {}",sqle.getMessage()));
|
||||
data.put(ERROR,t("You already are member of this list!",sqle.getMessage()));
|
||||
} else data.put(ERROR,t("Subscription failed: {}",sqle.getMessage()));
|
||||
return loadTemplate(SUBSCRIBE,data,resp);
|
||||
} catch (MessagingException e) {
|
||||
LOG.warn("Senden der Bestätigungs-Email fehlgeschlagen:",e);
|
||||
data.put(ERROR,t("Senden der Bestätigungs-Email fehlgeschlagen: {}",e.getMessage()));
|
||||
LOG.warn("Failed to send request confirmation email:",e);
|
||||
data.put(ERROR,t("Failed to send request confirmation email: {}",e.getMessage()));
|
||||
return loadTemplate(SUBSCRIBE,data,resp);
|
||||
}
|
||||
}
|
||||
@@ -566,12 +565,12 @@ public class Web extends TemplateServlet {
|
||||
data.put(EMAIL,email);
|
||||
if (user != null) data.put(USER,user.safeMap());
|
||||
if (list == null){
|
||||
data.put(ERROR,"Keine Mailin-Liste in den Formular-Daten übermittelt!!");
|
||||
data.put(ERROR,"No list provided by form data!");
|
||||
return loadTemplate(UNSUBSCRIBE,data,resp);
|
||||
} else data.put(LIST,list.email());
|
||||
if (user == null) {
|
||||
if (email == null || email.isBlank()) {
|
||||
data.put(ERROR, "Für das Abbestellen ist eine E-Mail-Adresse erforderlich!");
|
||||
data.put(ERROR, "Email is required for list un-subscription!");
|
||||
return loadTemplate(UNSUBSCRIBE, data, resp);
|
||||
}
|
||||
var pass = req.getParameter(PASSWORD);
|
||||
@@ -582,7 +581,7 @@ public class Web extends TemplateServlet {
|
||||
req.getSession().setAttribute(USER,user);
|
||||
data.put(USER,user.safeMap());
|
||||
} catch (InvalidKeyException | SQLException e) {
|
||||
data.put(ERROR,"Ungültige E-Mail-/Passwort-Kombination!");
|
||||
data.put(ERROR,"Invalid email/password combination!");
|
||||
return loadTemplate(UNSUBSCRIBE,data,resp);
|
||||
}
|
||||
}
|
||||
@@ -591,23 +590,22 @@ public class Web extends TemplateServlet {
|
||||
try {
|
||||
member = ListMember.load(list,user);
|
||||
} catch (SQLException e) {
|
||||
LOG.debug("Laden des Listenmitglieds für {}/{} fehlgeschlagen",user.email(),list.email(),e);
|
||||
data.put(ERROR, t("Laden des Listenmitglieds für {}/{} fehlgeschlagen",user.email(),list.email()));
|
||||
LOG.debug("Failed to load list member for {}/{}",user.email(),list.email(),e);
|
||||
data.put(ERROR, t("Failed to load list member for {}/{}",user.email(),list.email()));
|
||||
return loadTemplate(UNSUBSCRIBE,data,resp);
|
||||
}
|
||||
if (member == null){
|
||||
data.put(ERROR, t("{} ist kein Mitglied von {}",user.email(),list.email()));
|
||||
data.put(ERROR, t("{} is no member of {}",user.email(),list.email()));
|
||||
return loadTemplate(UNSUBSCRIBE,data,resp);
|
||||
}
|
||||
// if we get here, we should have a valid member object
|
||||
try {
|
||||
member.unsubscribe();
|
||||
data.put(NOTES,t("'{}' erfolgreich abbestellt.",list.email()));
|
||||
|
||||
data.put(NOTES,t("Sucessfully un-subscribed from '{}'.",list.email()));
|
||||
return loadTemplate(INDEX,data,resp);
|
||||
} catch (SQLException e) {
|
||||
LOG.warn("Es ist ein Problem beim Entfernen von {} aus der Liste {} aufgetreten:",user.email(),list.email(),e);
|
||||
data.put(ERROR,"Abbestellen der Mailin-Liste fehlgeschlagen!");
|
||||
LOG.warn("Problem during unscubsription of {} from {}:",user.email(),list.email(),e);
|
||||
data.put(ERROR,"Failed to unsubscribe!");
|
||||
return loadTemplate(UNSUBSCRIBE,data,resp);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,112 @@
|
||||
[{}] Please confirm your list subscription : [{}] Bitte bestätigen Sie Ihr Listen-Abonnement
|
||||
[{}] Subscription complete! : [{}] Abonnement abgeschlossen!
|
||||
[{}]\: test mail : [{}] Test-Mail
|
||||
'{}' already in database, but with different password! : '{}' gibt es schon in der Datenbank, hat dort aber ein anderes Passwort!
|
||||
{} is no member of {} : {} ist nicht Mitglied von {}!
|
||||
{} is not a member of {} : {} ist nicht Mitglied von {}!
|
||||
'{}' is not a proper port number! : '{}' ist keine gültige Port-Nummer!
|
||||
'{}' is not a valid email address! : '{}' ist keine gültige Mailadresse!
|
||||
{} is now a moderator of {} : {} ist nun ein Moderator der Liste {}
|
||||
archive : Archiv
|
||||
awaiting confirmation : erwartet Bestätigung
|
||||
Confirmation of list membership failed! : Bestätigung des Listen-Abonnements fehlgeschlagen!
|
||||
Confirmed list subscription! : Listen-Mitgliedschaft bestätigt!
|
||||
enabled : aktiviert
|
||||
disabled : deaktiviert
|
||||
Editing list {} by {} failed : Bearbeiten der Liste {} durch {} fehlgeschlagen!
|
||||
Email is required for list un-subscription! : Für das Abbestellen ist eine E-Mail-Adresse erforderlich!
|
||||
Error reading user database! : Fehler beim Lesen der Nutzer-Datenbank!
|
||||
Failed to access user database\: {} : Fehler beim Zugriff auf die Nutzer-Datenbank: {}
|
||||
Failed to create list '{}'\: {} : Erzeugen der Liste '{}' fehlgeschlagen: {}
|
||||
Failed to create new user\: {} : Erzeugen des neuen Nutzers fehlgeschlagen: {}
|
||||
Failed to handle request\: {} : Konnte Anfrage nicht verarbeiten: {}
|
||||
Failed to load file '{}'! : Laden der Datei '{}' fehlgeschlagen!
|
||||
Failed to load list member for {}/{} : Laden der Mitgliedschaft zu {}/{} fehlgeschlagen!
|
||||
Failed to load member list '{}' : Laden der Mitglieder-Liste von '{}' fehlgeschlagen!
|
||||
Failed to load post from file! : Laden der Nachricht aus Datei fehlgeschlagen!
|
||||
Failed to load template '{}' : Laden der Vorlage '{}' fehlgeschlagen!
|
||||
Failed to load user for {} : Laden des Nutzers zu {} fehlgeschlagen!
|
||||
Failed to load user for address {} : Laden des Nutzers für die Adresse {} fehlgeschlagen!
|
||||
Failed to make {} a moderator of {} : Ernennen von {} zum Moderator von {} fehlgeschlagen!
|
||||
Failed to make {} a subscriber of {} : Ernennen von {} zum regulären Abonnenten von {} fehlgeschlagen!
|
||||
Failed to send email to {} : Senden der Email an {} fehlgeschlagen!
|
||||
Failed to send request confirmation email\: {} : Senden der Bestätigungs-Email fehlgeschlagen: {}
|
||||
Failed to send test email to {} : Senden der Test-Email an {} fehlgeschlagen!
|
||||
Failed to (un)hide mailing list\: : Veröffentlichen/Verstekcen der Mailing-Liste fehlgeschlagen:
|
||||
Failed to un-subscribe {} from {} : Abbestellen von {} / {} fehlgeschlagen!
|
||||
Failed to unsubscribe! : Abbestellen der Mailin-Liste fehlgeschlagen!
|
||||
Failed to update list '{}' : Aktualisieren der Liste '{}' fehlgeschlagen!
|
||||
Failed to update MailingList! : Aktualisierung der Mailing-Liste fehlgeschlagen!
|
||||
Fill all fields, please! : Bitte alle Felder ausfüllen!
|
||||
File {} does not exist! : Datei {} existiert nicht!
|
||||
Find the forwarded message in the attachment(s)!\n : Die weitergeleitete Nachricht findest du im Anhang dieser E-Mail!\n
|
||||
forward_attached : als Anhang weiterleiten
|
||||
hidden : versteckt
|
||||
hide_receivers : Empfänger verbergen
|
||||
If you received this mail, the SMTP settings of your mailing list are correct. : Wenn Sie diese Nachricht empfangen haben, sind die SMTP-Einstellungen Ihrer Mailing-Liste korrekt.
|
||||
IMAP credentials are required! : IMAP-Zugangsdaten sind erforderlich!
|
||||
Invalid or missing token : Ungültiger oder fehlender Token!
|
||||
Invalid username/password : Ungültiger Nutzername oder ungültiges Passwort!
|
||||
Invalid email/password combination! : Ungültige E-Mail-/Passwort-Kombination!
|
||||
List '{}' requires attention! : Liste '{}' erfordert Aufmerksamkeit!
|
||||
List {} disabled, closed for subscribers and hidden. Members have been removed. : Liste {} deaktiviert, Abonnement gesperrt, Liste de-publiziert. Mitglieder wurden entfernt.
|
||||
List email ({}) is not a valid email address! : Listen-E-Mail-Adresse ({}) ist keine gültige E-Mail-Adresse!
|
||||
List name and address are required! : Name und Adresse der Liste sind notwendige Felder!
|
||||
made public : veröffentlicht
|
||||
Mailing list '{}' was {}! : Mailing-Liste '{}' wurde {}!
|
||||
missing user email address! : E-Mail-Adresse des Listenmitglieds nicht angegeben!
|
||||
Missing username or password! : Nutzername oder Passwort fehlen!
|
||||
moderator : Moderator
|
||||
Name and email are required fields for list subscription! : Name und E-Mail-Adresse sind für das Abonnieren der Mailingliste erforderlich!
|
||||
No handler for path {}! : Kein Handler für den Pfad '{}'!
|
||||
no list email provided! : Keine Listen-Email übertragen!
|
||||
No list provided by form data! : Formular-Daten enthalten keine Liste!
|
||||
No such user\: {} : Kein solcher Nutzer: {}
|
||||
No template for path '{}'! : Keine Vorlage für den Pfad '{}' vorhanden!
|
||||
No valid mailing list provided! : Keine gültige MailingListe übermittelt!
|
||||
no valid permissions provided! : Keine gültigen Berechtigungen übergeben!
|
||||
Not logged in! : Nicht eingeloggt!
|
||||
open_for_guests : Gästbeiträge erlaubt
|
||||
open_for_subscribers : Selbstregistrierung
|
||||
original_from : ursprünglicher Absender
|
||||
owner : Besitzer
|
||||
Passwords do not match! : Passworte stimmen nicht überein!
|
||||
Password to short or to simple! : Passwort zu kurz oder zu einfach!
|
||||
Problem during unscubsription of {} from {}\: : Es ist ein Problem beim Austragen von {} aus der Liste {} aufgetreten:
|
||||
public : öffentlich
|
||||
Query '{}' failed\: : Query '{}' fehlgeschlagen:
|
||||
reply_to_list : Antwort an Liste
|
||||
Sent confirmation mail to '{}. : Bestätigungs-Email wurde an '{} versendet.
|
||||
SMTP credentials are required! : SMTP-Zugangsdaten sind erforderlich!
|
||||
subscriber : Abonniert
|
||||
Subscription failed\: {} : Abonnieren der Liste fehlgeschlagen: {}
|
||||
Sucessfully updated MailingList! : Mailing-Liste aktualisiert!
|
||||
Successfully subscribed '{}' to '{}'. : '{}' hat die Mailingliste '{}' erfolgreich abonniert.
|
||||
Sucessfully un-subscribed from '{}'. : '{}' erfolgreich abbestellt.
|
||||
Templates have been reloaded : Vorlagen wurden neu geladen!
|
||||
The mailing list you are trying to view does not exist! : Die Mailingliste, auf die Sie zugreifen wollen, gibt es nicht!
|
||||
This list received an email from {}, who is not member of the list.\nThe email has been moved to the '{}' folder.\nYou may manually forward this message or drop it. : Diese Liste hat eine E-Mail von {} empfangen. Der Absender ist nicht Mitglied der Liste.\nDie Email wurde in den '{}'-Ordner verschoben.\nSie können die Nachricht manuell weiterleiten oder verwerfen.
|
||||
Unknown user or token : Nutzer oder Token unbekannt!
|
||||
Updated user permissions : Nutzer-Berechtigungen aktualisiert
|
||||
User database is empty. Create admin user first\: : Nutzer-Datenbank ist leer. Admin-Nutzer wird hiermit angelegt:
|
||||
Was not able to check existence of table {}! : Konnte Existenz der Tabelle {} nicht prüfen!
|
||||
Was not able to redirect to {} page\: {} : Weiterleitung nach {} fehlgeschlagen: {}
|
||||
You already are member of this list! : Sie haben diese Liste bereits abonniert!
|
||||
You are not allowed to access the archive of this list! : Du hast keine Berechtigung, das Archiv dieser Liste anzusehen!
|
||||
You are not allowed to alter user permissions! : Sie haben nicht die Berechtigung, um Berechtigungen zu ändern!
|
||||
You are not allowed to create new mailing lists! : Ihnen ist es nicht gestattet, neue Mailinglisten anzulegen!
|
||||
You are not allowed to edit '{}' : Du bist nicht berechtigt, '{}' zu bearbeiten!
|
||||
You are not allowed to edit mods of {} : Es ist dir nicht gestattet, die Moderatoren von {} zu verändern!
|
||||
You are not allowed to join {}! : Ihnen ist es nicht gestattet, '{}' zu abonnieren!
|
||||
You are not allowed to list members of '{}' : Es ist dir nicht gestattet, die Mitglieder von '{}' aufzulisten!
|
||||
You are not allowed to nominate new mods for {} : Es ist dir nicht gestattet, neue Moderatoren für {} zu ernennen!
|
||||
You are not allowed to remove members of {} : Es ist dir nicht erlaubt, Mitglieder von {} zu entfernen!
|
||||
You are not allowed to remove the list owner! : Du kannst den Listen-Besitzer nicht entfernen!
|
||||
You are not allowed to remove this list! : Es ist dir nicht gestattet, diese Liste zu löschen!
|
||||
You are not allowed to subscribe to '{}'! : Es ist ihnen nicht gestattet, '{}' zu abonnieren!
|
||||
You are not allowed to test '{}' : Es ist dir nicht gestattet, '{}' zu testen
|
||||
You are not alter settings of this list! : Es ist Ihnen nicht gestattet, die Einselltungen dieser Mailingliste zu verändern!
|
||||
You are trying to access a non-existing list! : Du versuchst auf eine nicht existierende Liste zuzugreifen!
|
||||
You have tried to send a message to the list '{}', which failed. This is because you are not a (privileged) member of this list.\n : Sie haben versucht, eine Nachricht an die Liste '{}' zu senden. Das wurde verweigert, da Sie kein Mitglied der Liste (mit entsprechenden Berechtigungen) sind.\n
|
||||
You may go to {} and subscribe to the list, then try again. : Sie können zu {} gehen und die Liste abonnieren. Versuchen Sie es danach erneut.
|
||||
Your message to {} was rejected! : Ihre Nachricht an {} wurde zurückgewiesen!
|
||||
|
||||
Reference in New Issue
Block a user