CCM NG: UserAdminForm: E-Mail-Addresses of a user can now be edited, added and deleted

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@3957 8810af33-2d31-482b-a856-94f89814c4df
pull/2/head
jensp 2016-03-23 17:51:06 +00:00
parent b32c0ab6f1
commit b19a347f6e
13 changed files with 695 additions and 248 deletions

View File

@ -52,19 +52,20 @@ import java.util.Iterator;
import java.util.Set; import java.util.Set;
/** /**
* Represents a email message with optional attachments. This class * Represents a email message with optional attachments. This class is a wrapper
* is a wrapper for the JavaMail API that makes it easier for * for the JavaMail API that makes it easier for application developers to
* application developers to create and send email. For simple plain * create and send email. For simple plain text message, there is a static
* text message, there is a static convenience method that does not * convenience method that does not require the construction of an explicit Mail
* require the construction of an explicit Mail object: * object:
* *
* <pre> * <pre>
* Mail.send(to, from, subject, body) * Mail.send(to, from, subject, body)
* </pre> * </pre>
* *
* <p>For more complex messages, the API provides methods to set all * <p>
* standard mail headers, attach other pieces of content, and finally * For more complex messages, the API provides methods to set all standard mail
* invoke the transport process to deliver the message. * headers, attach other pieces of content, and finally invoke the transport
* process to deliver the message.
* *
* @author Ron Henderson * @author Ron Henderson
* @version $Id$ * @version $Id$
@ -74,11 +75,10 @@ public class Mail implements MessageType {
/** /**
* Used for logging. * Used for logging.
*/ */
private static final Logger s_log = private static final Logger s_log = Logger.getLogger(Mail.class);
Logger.getLogger(Mail.class);
private static final InternetAddress[] EMPTY_ADDRESS_LIST = private static final InternetAddress[] EMPTY_ADDRESS_LIST
new InternetAddress[0]; = new InternetAddress[0];
/** /**
* Table of message headers. * Table of message headers.
*/ */
@ -90,11 +90,13 @@ public class Mail implements MessageType {
private InternetAddress[] m_filteredTo = EMPTY_ADDRESS_LIST; private InternetAddress[] m_filteredTo = EMPTY_ADDRESS_LIST;
private InternetAddress[] m_invalidTo = EMPTY_ADDRESS_LIST; private InternetAddress[] m_invalidTo = EMPTY_ADDRESS_LIST;
private static Set s_invalidDomains = new HashSet(); private static Set s_invalidDomains = new HashSet();
static { static {
s_log.debug("Static initalizer starting..."); s_log.debug("Static initalizer starting...");
s_invalidDomains.add("example.com"); s_invalidDomains.add("example.com");
s_log.debug("Static initalizer finished."); s_log.debug("Static initalizer finished.");
} }
/** /**
* Email address the message is being sent from. * Email address the message is being sent from.
*/ */
@ -124,8 +126,8 @@ public class Mail implements MessageType {
*/ */
private String m_alternate; private String m_alternate;
/** /**
* Encoding specification for m_body and m_alternate (optional). * Encoding specification for m_body and m_alternate (optional). Default
* Default value (null) implies "us-ascii" encoding. * value (null) implies "us-ascii" encoding.
*/ */
private String m_encoding; private String m_encoding;
/** /**
@ -141,13 +143,13 @@ public class Mail implements MessageType {
*/ */
private static Session s_session; private static Session s_session;
/** /**
* SMTP host to connect to. Only used to override the default for * SMTP host to connect to. Only used to override the default for testing
* testing purposes. * purposes.
*/ */
private static String s_host; private static String s_host;
/** /**
* SMTP port to connect to. Only used to override the default for * SMTP port to connect to. Only used to override the default for testing
* testing purposes. * purposes.
*/ */
private static String s_port; private static String s_port;
// Constants used by Mail // Constants used by Mail
@ -165,8 +167,8 @@ public class Mail implements MessageType {
public final static String ATTACHMENT = javax.mail.Part.ATTACHMENT; public final static String ATTACHMENT = javax.mail.Part.ATTACHMENT;
/** /**
* Default constructor. Must use the setTo, setSubject (and so on) * Default constructor. Must use the setTo, setSubject (and so on) methods
* methods to create a valid mail message. * to create a valid mail message.
*/ */
public Mail() { public Mail() {
this(null, null, null, null); this(null, null, null, null);
@ -175,8 +177,8 @@ public class Mail implements MessageType {
/** /**
* Constructor used to specify to, from, and subject. * Constructor used to specify to, from, and subject.
* *
* @param to one or more of addresses to send the message to * @param to one or more of addresses to send the message to
* @param from the address the message is being sent from * @param from the address the message is being sent from
* @param subject the subject for the message * @param subject the subject for the message
*/ */
public Mail(String to, public Mail(String to,
@ -188,10 +190,10 @@ public class Mail implements MessageType {
/** /**
* Constructor used to specify to, from, subject, and body. * Constructor used to specify to, from, subject, and body.
* *
* @param to one or more of addresses to send the message to * @param to one or more of addresses to send the message to
* @param from the address the message is being sent from * @param from the address the message is being sent from
* @param subject the subject for the message * @param subject the subject for the message
* @param body the plain text body of the message * @param body the plain text body of the message
*/ */
public Mail(String to, public Mail(String to,
String from, String from,
@ -205,14 +207,13 @@ public class Mail implements MessageType {
} }
/** /**
* Constructor used to specify to, from, subject, body, and * Constructor used to specify to, from, subject, body, and encoding.
* encoding.
* *
* @param to one or more of addresses to send the message to * @param to one or more of addresses to send the message to
* @param from the address the message is being sent from * @param from the address the message is being sent from
* @param subject the subject for the message * @param subject the subject for the message
* @param body is plain text body of the message * @param body is plain text body of the message
* @param enc the encoding of the body * @param enc the encoding of the body
*/ */
public Mail(String to, public Mail(String to,
String from, String from,
@ -226,17 +227,17 @@ public class Mail implements MessageType {
/** /**
* A convenience method to send a simple plain-text message. * A convenience method to send a simple plain-text message.
* *
* @param to one or more of addresses to send the message to * @param to one or more of addresses to send the message to
* @param from the address the message is being sent from * @param from the address the message is being sent from
* @param subject the subject for the message * @param subject the subject for the message
* @param body the plain text body of the message * @param body the plain text body of the message
*/ */
public static void send(String to, public static void send(String to,
String from, String from,
String subject, String subject,
String body) String body)
throws MessagingException, throws MessagingException,
SendFailedException { SendFailedException {
Mail msg = new Mail(to, from, subject, body); Mail msg = new Mail(to, from, subject, body);
msg.send(); msg.send();
} }
@ -245,26 +246,29 @@ public class Mail implements MessageType {
* Sends the message. * Sends the message.
*/ */
public void send() public void send()
throws MessagingException, throws MessagingException,
SendFailedException { SendFailedException {
final Properties properties = MailConfig.getConfig().getJavaMailProperties();
Transport transport = getSession().getTransport(); Transport transport = getSession().getTransport();
transport.connect(); transport.connect(properties.getProperty("mail.smtp.user"),
properties.getProperty("mail.smtp.password"));
send(transport); send(transport);
transport.close(); transport.close();
} }
/** /**
* Sends the message using a given Transport object (package-level * Sends the message using a given Transport object (package-level access).
* access). This method is used when sending multiple messages at * This method is used when sending multiple messages at once with a single
* once with a single connection to the mail server. * connection to the mail server.
* *
* @throws SendFailedException on any kind of MessagingException, * @throws SendFailedException on any kind of MessagingException, also such
* also such returned from the server. Applications might try * returned from the server. Applications might
* to catch this and re-schedule sending the mail. * try to catch this and re-schedule sending the
* mail.
*/ */
void send(Transport transport) void send(Transport transport)
throws MessagingException, throws MessagingException,
SendFailedException { SendFailedException {
Message msg = null; Message msg = null;
if (m_filteredTo.length > 0) { if (m_filteredTo.length > 0) {
msg = getMessage(); msg = getMessage();
@ -275,7 +279,6 @@ public class Mail implements MessageType {
// Close the transport agent and rethrow error for // Close the transport agent and rethrow error for
// detailed message. // detailed message.
transport.close(); transport.close();
throw new SendFailedException("send failed: ", mex); throw new SendFailedException("send failed: ", mex);
@ -283,14 +286,13 @@ public class Mail implements MessageType {
} }
// Write a copy of the message into the log file // Write a copy of the message into the log file
if (MailConfig.getConfig().isDebug()) { if (MailConfig.getConfig().isDebug()) {
if (msg != null) { if (msg != null) {
try { try {
ByteArrayOutputStream os = new ByteArrayOutputStream(); ByteArrayOutputStream os = new ByteArrayOutputStream();
msg.writeTo(os); msg.writeTo(os);
s_log.debug("message sent:\n" + os.toString() s_log.debug("message sent:\n" + os.toString()
+ "\n-- EOT --"); + "\n-- EOT --");
} catch (IOException ex) { } catch (IOException ex) {
s_log.error("unable to log message"); s_log.error("unable to log message");
} }
@ -299,15 +301,16 @@ public class Mail implements MessageType {
} }
} else { } else {
s_log.info("message sent to <" + Arrays.asList(m_filteredTo) s_log.info("message sent to <" + Arrays.asList(m_filteredTo)
+ "> from <" + m_from + "> subject <" + m_subject + ">"); + "> from <" + m_from + "> subject <" + m_subject
+ ">");
s_log.info("messages filtered for <" + Arrays.asList(m_invalidTo) s_log.info("messages filtered for <" + Arrays.asList(m_invalidTo)
+ "> from <" + m_from + "> subject <" + m_subject + ">"); + "> from <" + m_from + "> subject <" + m_subject
+ ">");
} }
} }
/** /**
* Sets the email address that the message is being sent * Sets the email address that the message is being sent to.
* to.
* *
* @param to one or more addresses to send the message to * @param to one or more addresses to send the message to
*/ */
@ -317,8 +320,7 @@ public class Mail implements MessageType {
} }
/** /**
* Sets the email address that the message is being sent * Sets the email address that the message is being sent from.
* from.
* *
* @param from the address the message is sent from * @param from the address the message is sent from
*/ */
@ -365,7 +367,7 @@ public class Mail implements MessageType {
/** /**
* Adds a header (name, value) pair. * Adds a header (name, value) pair.
* *
* @param name the header element name * @param name the header element name
* @param value the header element value * @param value the header element value
*/ */
public void addHeader(String name, String value) { public void addHeader(String name, String value) {
@ -378,6 +380,7 @@ public class Mail implements MessageType {
/** /**
* Sets the email address that is being carbon-copied. * Sets the email address that is being carbon-copied.
*
* @param cc the email address for a carbon copy * @param cc the email address for a carbon copy
*/ */
public void setCc(String cc) { public void setCc(String cc) {
@ -386,6 +389,7 @@ public class Mail implements MessageType {
/** /**
* Sets the email address that is being blind carbon-copied. * Sets the email address that is being blind carbon-copied.
*
* @param bcc the email address for a blind carbon copy * @param bcc the email address for a blind carbon copy
*/ */
public void setBcc(String bcc) { public void setBcc(String bcc) {
@ -394,6 +398,7 @@ public class Mail implements MessageType {
/** /**
* Sets the body of the email to a simple plain text message. * Sets the body of the email to a simple plain text message.
*
* @param body the body of the message in plain text * @param body the body of the message in plain text
*/ */
public void setBody(String body) { public void setBody(String body) {
@ -401,11 +406,11 @@ public class Mail implements MessageType {
} }
/** /**
* Sets the body of the email to an HTML encoded message with a * Sets the body of the email to an HTML encoded message with a plain text
* plain text alternative. * alternative.
* *
* @param body the body of the message in HTML * @param body the body of the message in HTML
* @param alt the alternate message body in plain text * @param alt the alternate message body in plain text
*/ */
public void setBody(String body, String alt) { public void setBody(String body, String alt) {
m_body = body; m_body = body;
@ -423,8 +428,8 @@ public class Mail implements MessageType {
} }
/** /**
* Returns the character encoding that is being used. The default * Returns the character encoding that is being used. The default is
* is "us-ascii". * "us-ascii".
* *
* @return the string value of the character encoding being used * @return the string value of the character encoding being used
*/ */
@ -433,14 +438,14 @@ public class Mail implements MessageType {
} }
/** /**
* Adds an attachment to a message. This method is private but * Adds an attachment to a message. This method is private but is invoked by
* is invoked by all of the other attach methods once they've * all of the other attach methods once they've constructed an appropraite
* constructed an appropraite MimeBodyPart to attach. * MimeBodyPart to attach.
* *
* @param part the message part to attach * @param part the message part to attach
*/ */
private void attach(MimeBodyPart part) private void attach(MimeBodyPart part)
throws MessagingException { throws MessagingException {
if (m_attachments == null) { if (m_attachments == null) {
m_attachments = new MimeMultipart(); m_attachments = new MimeMultipart();
} }
@ -448,27 +453,26 @@ public class Mail implements MessageType {
} }
/** /**
* Adds an attachment with a specified name and description to a * Adds an attachment with a specified name and description to a message by
* message by fetching its content from a URL. Sets the * fetching its content from a URL. Sets the disposition to ATTACHMENT.
* disposition to ATTACHMENT.
* *
* @param url the URL to retreieve the content from * @param url the URL to retreieve the content from
* @param name the name of the attachment * @param name the name of the attachment
* @param description a description of the attachment * @param description a description of the attachment
*/ */
public void attach(URL url, public void attach(URL url,
String name, String name,
String description) String description)
throws MessagingException { throws MessagingException {
attach(url, name, description, Mail.ATTACHMENT); attach(url, name, description, Mail.ATTACHMENT);
} }
/** /**
* Adds an attachment with a specified name, description and * Adds an attachment with a specified name, description and disposition to
* disposition to a message by fetching its content from a URL. * a message by fetching its content from a URL.
* *
* @param url the URL to retreieve the content from * @param url the URL to retreieve the content from
* @param name the name of the attachment * @param name the name of the attachment
* @param description a description of the attachment * @param description a description of the attachment
* @param disposition Mail.ATTACHMENT or Mail.INLINE * @param disposition Mail.ATTACHMENT or Mail.INLINE
*/ */
@ -476,7 +480,7 @@ public class Mail implements MessageType {
String name, String name,
String description, String description,
String disposition) String disposition)
throws MessagingException { throws MessagingException {
MimeBodyPart part = new MimeBodyPart(); MimeBodyPart part = new MimeBodyPart();
attach(part); attach(part);
@ -489,28 +493,27 @@ public class Mail implements MessageType {
} }
/** /**
* Adds an attachment with a specified name and description to a * Adds an attachment with a specified name and description to a message by
* message by fetching its content from a local file. Sets the * fetching its content from a local file. Sets the disposition to
* disposition to ATTACHMENT. * ATTACHMENT.
* *
* @param path the file path to retreieve the content from * @param path the file path to retreieve the content from
* @param name the name of the attachment * @param name the name of the attachment
* @param description a description of the attachment * @param description a description of the attachment
*/ */
public void attach(File path, public void attach(File path,
String name, String name,
String description) String description)
throws MessagingException { throws MessagingException {
attach(path, name, description, ATTACHMENT); attach(path, name, description, ATTACHMENT);
} }
/** /**
* Adds an attachment with a specified name, description and * Adds an attachment with a specified name, description and disposition to
* disposition to a message by fetching its content from a * a message by fetching its content from a local file.
* local file.
* *
* @param path the file path to retreieve the content from * @param path the file path to retreieve the content from
* @param name the name of the attachment * @param name the name of the attachment
* @param description a description of the attachment * @param description a description of the attachment
* @param disposition Mail.ATTACHMENT or Mail.INLINE * @param disposition Mail.ATTACHMENT or Mail.INLINE
*/ */
@ -518,7 +521,7 @@ public class Mail implements MessageType {
String name, String name,
String description, String description,
String disposition) String disposition)
throws MessagingException { throws MessagingException {
MimeBodyPart part = new MimeBodyPart(); MimeBodyPart part = new MimeBodyPart();
attach(part); attach(part);
@ -531,9 +534,8 @@ public class Mail implements MessageType {
} }
/** /**
* Attaches a byte array to a message. Sets the MIME type and * Attaches a byte array to a message. Sets the MIME type and name of the
* name of the attachment, and initializes its disposition to * attachment, and initializes its disposition to ATTACHMENT.
* ATTACHMENT.
* *
* @param data the content of the attachment * @param data the content of the attachment
* @param type the MIME type of the attachment * @param type the MIME type of the attachment
@ -542,19 +544,20 @@ public class Mail implements MessageType {
public void attach(byte[] data, public void attach(byte[] data,
String type, String type,
String name) String name)
throws MessagingException { throws MessagingException {
attach(data, type, name, null, ATTACHMENT); attach(data, type, name, null, ATTACHMENT);
} }
/** /**
* Attaches a byte array to a message. Sets the MIME type, name, * Attaches a byte array to a message. Sets the MIME type, name, description
* description and disposition of the attachment. * and disposition of the attachment.
* *
* @param data the content of the attachment * @param data the content of the attachment
* @param type the MIME type of the attachment * @param type the MIME type of the attachment
* @param name the name of the attachment * @param name the name of the attachment
* @param description a description of the attachment * @param description a description of the attachment
* @param disposition Mail.ATTACHMENT or Mail.INLINE * @param disposition Mail.ATTACHMENT or Mail.INLINE
*
* @throws javax.mail.MessagingException * @throws javax.mail.MessagingException
*/ */
public void attach(byte[] data, public void attach(byte[] data,
@ -562,14 +565,14 @@ public class Mail implements MessageType {
String name, String name,
String description, String description,
String disposition) String disposition)
throws MessagingException { throws MessagingException {
ByteArrayDataSource ds = new ByteArrayDataSource(data, type, name); ByteArrayDataSource ds = new ByteArrayDataSource(data, type, name);
attach(ds, description, disposition); attach(ds, description, disposition);
} }
/** /**
* Attaches a String to a message. Sets the MIME type and name of * Attaches a String to a message. Sets the MIME type and name of the
* the attachment, and initializes the disposition to ATTACHMENT. * attachment, and initializes the disposition to ATTACHMENT.
* *
* @param data the content of the attachment * @param data the content of the attachment
* @param type the MIME type of the attachment * @param type the MIME type of the attachment
@ -578,17 +581,17 @@ public class Mail implements MessageType {
public void attach(String data, public void attach(String data,
String type, String type,
String name) String name)
throws MessagingException { throws MessagingException {
attach(data, type, name, null, ATTACHMENT); attach(data, type, name, null, ATTACHMENT);
} }
/** /**
* Attaches a String to a message. Sets the MIME type, name, * Attaches a String to a message. Sets the MIME type, name, description and
* description and disposition of the attachment. * disposition of the attachment.
* *
* @param data the content of the attachment * @param data the content of the attachment
* @param type the MIME type of the attachment * @param type the MIME type of the attachment
* @param name the name of the attachment * @param name the name of the attachment
* @param description a description of the attachment * @param description a description of the attachment
* @param disposition Mail.ATTACHMENT or Mail.INLINE * @param disposition Mail.ATTACHMENT or Mail.INLINE
*/ */
@ -597,35 +600,34 @@ public class Mail implements MessageType {
String name, String name,
String description, String description,
String disposition) String disposition)
throws MessagingException { throws MessagingException {
ByteArrayDataSource ds = new ByteArrayDataSource(data, type, name); ByteArrayDataSource ds = new ByteArrayDataSource(data, type, name);
attach(ds, description, disposition); attach(ds, description, disposition);
} }
/** /**
* Attaches the content from a ByteArrayInputStream to a message. * Attaches the content from a ByteArrayInputStream to a message. Sets the
* Sets the MIME type and name of the attachment, and initializes * MIME type and name of the attachment, and initializes the disposition to
* the disposition to ATTACHMENT. * ATTACHMENT.
* *
* @param is the input stream to read from. * @param is the input stream to read from.
* @param type the MIME type of the attachment * @param type the MIME type of the attachment
* @param name the name of the attachment * @param name the name of the attachment
*/ */
public void attach(ByteArrayInputStream is, public void attach(ByteArrayInputStream is,
String type, String type,
String name) String name)
throws MessagingException { throws MessagingException {
attach(is, type, name, null, ATTACHMENT); attach(is, type, name, null, ATTACHMENT);
} }
/** /**
* Attaches the content from a ByteArrayInputStream to a message. * Attaches the content from a ByteArrayInputStream to a message. Sets the
* Sets the MIME type, name, description and disposition of the * MIME type, name, description and disposition of the attachment.
* attachment.
* *
* @param is the input stream to read from. * @param is the input stream to read from.
* @param type the MIME type of the attachment * @param type the MIME type of the attachment
* @param name the name of the attachment * @param name the name of the attachment
* @param description a description of the attachment * @param description a description of the attachment
* @param disposition Mail.ATTACHMENT or Mail.INLINE * @param disposition Mail.ATTACHMENT or Mail.INLINE
*/ */
@ -634,25 +636,25 @@ public class Mail implements MessageType {
String name, String name,
String description, String description,
String disposition) String disposition)
throws MessagingException { throws MessagingException {
ByteArrayDataSource ds = new ByteArrayDataSource(is, type, name); ByteArrayDataSource ds = new ByteArrayDataSource(is, type, name);
attach(ds, description, disposition); attach(ds, description, disposition);
} }
/** /**
* Attaches the content from a ByteArrayDataSource to a * Attaches the content from a ByteArrayDataSource to a message. This is
* message. This is used internally by various other methods that * used internally by various other methods that take higher-level object
* take higher-level object types as input. The MIME type and * types as input. The MIME type and name are determined directly from the
* name are determined directly from the dataSource. * dataSource.
* *
* @param dataSource the data source to read from * @param dataSource the data source to read from
* @param description a description of the attachment * @param description a description of the attachment
* @param disposition Mail.ATTACHMENT or Mail.INLINE * @param disposition Mail.ATTACHMENT or Mail.INLINE
*/ */
protected void attach(ByteArrayDataSource dataSource, protected void attach(ByteArrayDataSource dataSource,
String description, String description,
String disposition) String disposition)
throws MessagingException { throws MessagingException {
MimeBodyPart part = new MimeBodyPart(); MimeBodyPart part = new MimeBodyPart();
attach(part); attach(part);
@ -665,29 +667,29 @@ public class Mail implements MessageType {
} }
/** /**
* Attaches content to a message by supplying a DataHandler. All * Attaches content to a message by supplying a DataHandler. All relevant
* relevant parameters (MIME type, name, ...) are determined * parameters (MIME type, name, ...) are determined directly from the
* directly from the DataHandler. * DataHandler.
* *
* @param dh a DataHandler for some piece of content. * @param dh a DataHandler for some piece of content.
*/ */
public void attach(DataHandler dh) public void attach(DataHandler dh)
throws MessagingException { throws MessagingException {
attach(dh, null, ATTACHMENT); attach(dh, null, ATTACHMENT);
} }
/** /**
* Attaches content to a message by supplying a DataHandler. Sets * Attaches content to a message by supplying a DataHandler. Sets the
* the description and disposition of the content. * description and disposition of the content.
* *
* @param dh the data source to read from * @param dh the data source to read from
* @param description a description of the attachment * @param description a description of the attachment
* @param disposition Mail.ATTACHMENT or Mail.INLINE * @param disposition Mail.ATTACHMENT or Mail.INLINE
*/ */
public void attach(DataHandler dh, public void attach(DataHandler dh,
String description, String description,
String disposition) String disposition)
throws MessagingException { throws MessagingException {
MimeBodyPart part = new MimeBodyPart(); MimeBodyPart part = new MimeBodyPart();
attach(part); attach(part);
@ -698,10 +700,9 @@ public class Mail implements MessageType {
} }
/** /**
* Utility function that returns an appropriate Session object for * Utility function that returns an appropriate Session object for sending
* sending mail. This uses the default properties from the Mail * mail. This uses the default properties from the Mail initializer and any
* initializer and any of properties that can be overridden at * of properties that can be overridden at the package level.
* the package level.
*/ */
static synchronized Session getSession() { static synchronized Session getSession() {
@ -721,20 +722,21 @@ public class Mail implements MessageType {
// Set up the session // Set up the session
s_session = Session.getInstance(props, null); s_session = Session.getInstance(props, null);
s_session.setDebug(MailConfig.getConfig().isDebug()); // s_session.setDebug(MailConfig.getConfig().isDebug());
s_session.setDebug(true);
} }
return s_session; return s_session;
} }
/** /**
* Utility function that returns the message part of the mail. * Utility function that returns the message part of the mail. Useful if you
* Useful if you want to build a separate Transport process (for * want to build a separate Transport process (for example, to queue a
* example, to queue a number of messages to send all at once rather * number of messages to send all at once rather than invoke the Mail.send()
* than invoke the Mail.send() method for each instance.) * method for each instance.)
*/ */
private Message getMessage() private Message getMessage()
throws MessagingException { throws MessagingException {
// Create the message // Create the message
MimeMessage msg = new MimeMessage(getSession()); MimeMessage msg = new MimeMessage(getSession());
@ -789,14 +791,13 @@ public class Mail implements MessageType {
} }
// Return the Message object with it's content ready to go. // Return the Message object with it's content ready to go.
return prepareMessageContent(msg); return prepareMessageContent(msg);
} }
/** /**
* Sets the host and port to connect to when sending * Sets the host and port to connect to when sending mail. Package-level
* mail. Package-level access (should only be used for testing). * access (should only be used for testing).
* *
* @param host the SMTP host to connect to * @param host the SMTP host to connect to
* @param port the port number on that host * @param port the port number on that host
@ -811,6 +812,7 @@ public class Mail implements MessageType {
/** /**
* Returns the SMTP mail host for debugging and account information. * Returns the SMTP mail host for debugging and account information.
*
* @return the SMTP mail host for debugging and account information. * @return the SMTP mail host for debugging and account information.
*/ */
public synchronized static String getSmtpServer() { public synchronized static String getSmtpServer() {
@ -818,13 +820,13 @@ public class Mail implements MessageType {
} }
/** /**
* Writes the content of the message to the given output stream. * Writes the content of the message to the given output stream. Useful for
* Useful for debugging. * debugging.
* *
* @param os the output stream to write the message to * @param os the output stream to write the message to
*/ */
public void writeTo(OutputStream os) public void writeTo(OutputStream os)
throws MessagingException { throws MessagingException {
try { try {
getMessage().writeTo(os); getMessage().writeTo(os);
} catch (IOException ex) { } catch (IOException ex) {
@ -946,7 +948,7 @@ public class Mail implements MessageType {
* Utility function to prepare the content of the message. * Utility function to prepare the content of the message.
*/ */
private Message prepareMessageContent(MimeMessage msg) private Message prepareMessageContent(MimeMessage msg)
throws MessagingException { throws MessagingException {
if (m_alternate == null && m_attachments == null) { if (m_alternate == null && m_attachments == null) {
// We have a plain-text message with no attachments. Use // We have a plain-text message with no attachments. Use
@ -959,24 +961,20 @@ public class Mail implements MessageType {
// For anything else the message will be a MIME multipart, // For anything else the message will be a MIME multipart,
// with a subtype of of either "mixed" or "alternative" // with a subtype of of either "mixed" or "alternative"
// depending on whether we have attachments. // depending on whether we have attachments.
String subtype = (m_attachments == null) ? ALTERNATIVE : MIXED; String subtype = (m_attachments == null) ? ALTERNATIVE : MIXED;
// Create a MIME multipart for the content. // Create a MIME multipart for the content.
MimeMultipart mp = new MimeMultipart(subtype); MimeMultipart mp = new MimeMultipart(subtype);
msg.setContent(mp); msg.setContent(mp);
// Next we need to look at whether the message part of the // Next we need to look at whether the message part of the
// content is going to be text/plain or text/html. // content is going to be text/plain or text/html.
MimeBodyPart part = new MimeBodyPart(); MimeBodyPart part = new MimeBodyPart();
if (m_alternate == null) { if (m_alternate == null) {
// No alternate, so it must be text/plain with // No alternate, so it must be text/plain with
// attachments. // attachments.
part.setText(m_body, m_encoding); part.setText(m_body, m_encoding);
part.setHeader(CONTENT_TYPE, MessageType.TEXT_PLAIN); part.setHeader(CONTENT_TYPE, MessageType.TEXT_PLAIN);
mp.addBodyPart(part); mp.addBodyPart(part);
@ -987,12 +985,10 @@ public class Mail implements MessageType {
// the first part and the alternate as the second. // the first part and the alternate as the second.
// The overall MIME subtype is probably ALTERNATE // The overall MIME subtype is probably ALTERNATE
// (depending on whether we have attachments). // (depending on whether we have attachments).
part.setText(m_body, m_encoding); part.setText(m_body, m_encoding);
part.setHeader(CONTENT_TYPE, MessageType.TEXT_HTML); part.setHeader(CONTENT_TYPE, MessageType.TEXT_HTML);
mp.addBodyPart(part); mp.addBodyPart(part);
part = new MimeBodyPart(); part = new MimeBodyPart();
part.setText(m_alternate, m_encoding); part.setText(m_alternate, m_encoding);
part.setHeader(CONTENT_TYPE, MessageType.TEXT_PLAIN); part.setHeader(CONTENT_TYPE, MessageType.TEXT_PLAIN);
@ -1003,11 +999,9 @@ public class Mail implements MessageType {
// Do we have attachments? If so then the MIME subtype // Do we have attachments? If so then the MIME subtype
// must be MIXED and and the attachments need to be // must be MIXED and and the attachments need to be
// transferred to the Message. // transferred to the Message.
if (m_attachments != null) { if (m_attachments != null) {
// Add attachments to the Message content. // Add attachments to the Message content.
for (int i = 0; i < m_attachments.getCount(); i++) { for (int i = 0; i < m_attachments.getCount(); i++) {
mp.addBodyPart(m_attachments.getBodyPart(i)); mp.addBodyPart(m_attachments.getBodyPart(i));
} }
@ -1016,7 +1010,6 @@ public class Mail implements MessageType {
// Save changes to the message. This will update the MIME // Save changes to the message. This will update the MIME
// headers so the message is ready to send. // headers so the message is ready to send.
msg.saveChanges(); msg.saveChanges();
return msg; return msg;
@ -1042,13 +1035,16 @@ public class Mail implements MessageType {
} else { } else {
invalid.add(m_to[i]); invalid.add(m_to[i]);
s_log.debug("filtering message to non-existent email address " s_log.debug("filtering message to non-existent email address "
+ m_to[i]); + m_to[i]);
} }
} }
m_filteredTo = (InternetAddress[]) filtered.toArray(new InternetAddress[filtered. m_filteredTo = (InternetAddress[]) filtered.toArray(
size()]); new InternetAddress[filtered.
m_invalidTo = (InternetAddress[]) invalid.toArray(new InternetAddress[invalid. size()]);
size()]); m_invalidTo = (InternetAddress[]) invalid.toArray(
new InternetAddress[invalid.
size()]);
return m_filteredTo; return m_filteredTo;
} }
} }

View File

@ -72,15 +72,26 @@ public final class MailConfig {
if (javaMailPropertiesFile == null if (javaMailPropertiesFile == null
|| javaMailPropertiesFile.isEmpty()) { || javaMailPropertiesFile.isEmpty()) {
properties.put("mail.transport.protocol", "smtp"); if (System.getProperty("ccm.mail.config") == null) {
properties.put("mail.smtp.host", "localhost"); properties.put("mail.transport.protocol", "smtp");
properties.put("mail.smtp.host", "localhost");
} else {
try {
properties.load(new URL(System
.getProperty("ccm.mail.config")).openStream());
} catch (IOException ex) {
throw new UncheckedWrapperException(String.format(
"Unable to retrieve properties for JavaMail from \"%s\".",
System.getProperty("ccm.mail.config")), ex);
}
}
} else { } else {
try { try {
properties.load(new URL(javaMailPropertiesFile).openStream()); properties.load(new URL(javaMailPropertiesFile).openStream());
} catch (IOException ex) { } catch (IOException ex) {
throw new UncheckedWrapperException(String.format( throw new UncheckedWrapperException(String.format(
"Unable to retrieve properties for JavaMail from \"%s\".", "Unable to retrieve properties for JavaMail from \"%s\".",
javaMailPropertiesFile)); javaMailPropertiesFile), ex);
} }
} }

View File

@ -23,7 +23,6 @@ import com.arsdigita.bebop.BoxPanel;
import com.arsdigita.bebop.Component; import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.ControlLink; import com.arsdigita.bebop.ControlLink;
import com.arsdigita.bebop.Form; import com.arsdigita.bebop.Form;
import com.arsdigita.bebop.FormProcessException;
import com.arsdigita.bebop.Label; import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.Page; import com.arsdigita.bebop.Page;
import com.arsdigita.bebop.PageState; import com.arsdigita.bebop.PageState;
@ -32,26 +31,32 @@ import com.arsdigita.bebop.PropertySheet;
import com.arsdigita.bebop.SaveCancelSection; import com.arsdigita.bebop.SaveCancelSection;
import com.arsdigita.bebop.Table; import com.arsdigita.bebop.Table;
import com.arsdigita.bebop.Text; import com.arsdigita.bebop.Text;
import com.arsdigita.bebop.event.FormProcessListener;
import com.arsdigita.bebop.event.FormSectionEvent;
import com.arsdigita.bebop.event.TableActionEvent; import com.arsdigita.bebop.event.TableActionEvent;
import com.arsdigita.bebop.event.TableActionListener; import com.arsdigita.bebop.event.TableActionListener;
import com.arsdigita.bebop.form.CheckboxGroup; import com.arsdigita.bebop.form.CheckboxGroup;
import com.arsdigita.bebop.form.Option; import com.arsdigita.bebop.form.Option;
import com.arsdigita.bebop.form.Submit; import com.arsdigita.bebop.form.Submit;
import com.arsdigita.bebop.form.TextField; import com.arsdigita.bebop.form.TextField;
import com.arsdigita.bebop.parameters.LongParameter; import com.arsdigita.bebop.parameters.NotEmptyValidationListener;
import com.arsdigita.bebop.parameters.StringParameter; import com.arsdigita.bebop.parameters.StringParameter;
import com.arsdigita.bebop.table.TableCellRenderer; import com.arsdigita.bebop.table.TableCellRenderer;
import com.arsdigita.bebop.table.TableColumn; import com.arsdigita.bebop.table.TableColumn;
import com.arsdigita.bebop.table.TableColumnModel; import com.arsdigita.bebop.table.TableColumnModel;
import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.mail.Mail;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.libreccm.cdi.utils.CdiUtil; import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.core.EmailAddress; import org.libreccm.core.EmailAddress;
import org.libreccm.security.User; import org.libreccm.security.User;
import org.libreccm.security.UserManager;
import org.libreccm.security.UserRepository; import org.libreccm.security.UserRepository;
import java.util.logging.Level;
import javax.mail.MessagingException;
import static com.arsdigita.ui.admin.AdminUiConstants.*; import static com.arsdigita.ui.admin.AdminUiConstants.*;
/** /**
@ -60,7 +65,9 @@ import static com.arsdigita.ui.admin.AdminUiConstants.*;
*/ */
public class UserAdmin extends BoxPanel { public class UserAdmin extends BoxPanel {
private final LongParameter userIdParameter; private static final Logger LOGGER = LogManager.getLogger(UserAdmin.class);
private final StringParameter userIdParameter;
private final StringParameter emailParameter; private final StringParameter emailParameter;
private final ParameterSingleSelectionModel<String> selectedUserId; private final ParameterSingleSelectionModel<String> selectedUserId;
private final ParameterSingleSelectionModel<String> selectedEmailAddress; private final ParameterSingleSelectionModel<String> selectedEmailAddress;
@ -98,7 +105,7 @@ public class UserAdmin extends BoxPanel {
filterForm.add(clearLink); filterForm.add(clearLink);
usersTablePanel.add(filterForm); usersTablePanel.add(filterForm);
userIdParameter = new LongParameter("selected_user_id"); userIdParameter = new StringParameter("selected_user_id");
selectedUserId = new ParameterSingleSelectionModel<>(userIdParameter); selectedUserId = new ParameterSingleSelectionModel<>(userIdParameter);
//selectedUserId = new ParameterSingleSelectionModel<>(USER_ID_PARAM); //selectedUserId = new ParameterSingleSelectionModel<>(USER_ID_PARAM);
@ -159,8 +166,25 @@ public class UserAdmin extends BoxPanel {
final ActionLink generatePasswordLink = new ActionLink( final ActionLink generatePasswordLink = new ActionLink(
new GlobalizedMessage("ui.admin.user_details.generate_password", new GlobalizedMessage("ui.admin.user_details.generate_password",
ADMIN_BUNDLE)); ADMIN_BUNDLE));
generatePasswordLink.setConfirmation(new GlobalizedMessage(
"ui.admin.user_details.generate_password.confirm",
ADMIN_BUNDLE));
generatePasswordLink.addActionListener(e -> { generatePasswordLink.addActionListener(e -> {
//ToDo final UserRepository userRepository = CdiUtil.createCdiUtil().findBean(UserRepository.class);
final User user = userRepository.findById(Long.parseLong(
selectedUserId.getSelectedKey(e.getPageState())));
final Mail mail = new Mail(
user.getPrimaryEmailAddress().getAddress(),
"libreccm.example",
"New password has been generated.");
mail.setBody("Das eine Test-Email");
try {
mail.send();
} catch (MessagingException ex) {
LOGGER.error("Failed to send email to user.", ex);
}
}); });
actionLinks.add(generatePasswordLink); actionLinks.add(generatePasswordLink);
userDetails.add(actionLinks); userDetails.add(actionLinks);
@ -266,7 +290,7 @@ public class UserAdmin extends BoxPanel {
final Object key, final Object key,
final int row, final int row,
final int column) { final int column) {
return new ControlLink((Label) value); return new ControlLink((Component) value);
} }
}); });
@ -282,7 +306,13 @@ public class UserAdmin extends BoxPanel {
final Object key, final Object key,
final int row, final int row,
final int column) { final int column) {
return new ControlLink((Label) value); final ControlLink link = new ControlLink((Component) value);
if (column == UserEmailTableModel.COL_DELETE) {
link.setConfirmation(new GlobalizedMessage(
"ui.admin.user.email_addresses.delete.confirm",
ADMIN_BUNDLE));
}
return link;
} }
}); });
@ -290,7 +320,35 @@ public class UserAdmin extends BoxPanel {
@Override @Override
public void cellSelected(final TableActionEvent event) { public void cellSelected(final TableActionEvent event) {
//ToDo final PageState state = event.getPageState();
final String key = (String) event.getRowKey();
switch (event.getColumn()) {
case UserEmailTableModel.COL_EDIT:
selectedEmailAddress.setSelectedKey(state, key);
showEmailForm(state);
break;
case UserEmailTableModel.COL_DELETE:
final String userIdStr = selectedUserId.getSelectedKey(
state);
final UserRepository userRepository = CdiUtil
.createCdiUtil().findBean(UserRepository.class);
final User user = userRepository.findById(Long
.parseLong(userIdStr));
EmailAddress email = null;
for (EmailAddress current : user.getEmailAddresses()) {
if (current.getAddress().equals(key)) {
email = current;
break;
}
}
if (email != null) {
user.removeEmailAddress(email);
userRepository.save(user);
}
}
} }
@Override @Override
@ -307,7 +365,7 @@ public class UserAdmin extends BoxPanel {
final ActionLink addEmailLink = new ActionLink(new GlobalizedMessage( final ActionLink addEmailLink = new ActionLink(new GlobalizedMessage(
"ui.admin.user.email_addresses.add", ADMIN_BUNDLE)); "ui.admin.user.email_addresses.add", ADMIN_BUNDLE));
addEmailLink.addActionListener(e -> { addEmailLink.addActionListener(e -> {
//ToDo showEmailForm(e.getPageState());
}); });
userDetails.add(addEmailLink); userDetails.add(addEmailLink);
@ -318,6 +376,10 @@ public class UserAdmin extends BoxPanel {
final TextField emailFormAddress = new TextField("email_form_address"); final TextField emailFormAddress = new TextField("email_form_address");
emailFormAddress.setLabel(new GlobalizedMessage( emailFormAddress.setLabel(new GlobalizedMessage(
"ui.admin.user.email_form.address", ADMIN_BUNDLE)); "ui.admin.user.email_form.address", ADMIN_BUNDLE));
emailFormAddress.addValidationListener(new NotEmptyValidationListener(
new GlobalizedMessage("ui.admin.user.email_form.address.not_empty",
ADMIN_BUNDLE)));
emailForm.add(emailFormAddress);
final CheckboxGroup emailFormVerified = new CheckboxGroup( final CheckboxGroup emailFormVerified = new CheckboxGroup(
"email_form_verified"); "email_form_verified");
emailFormVerified.addOption( emailFormVerified.addOption(
@ -325,13 +387,15 @@ public class UserAdmin extends BoxPanel {
new Label(new GlobalizedMessage( new Label(new GlobalizedMessage(
"ui.admin.user.email_form.verified", "ui.admin.user.email_form.verified",
ADMIN_BUNDLE)))); ADMIN_BUNDLE))));
emailForm.add(emailFormVerified);
final CheckboxGroup emailFormBouncing = new CheckboxGroup( final CheckboxGroup emailFormBouncing = new CheckboxGroup(
"email_form_verified"); "email_form_bouncing");
emailFormBouncing.addOption( emailFormBouncing.addOption(
new Option("true", new Option("true",
new Label(new GlobalizedMessage( new Label(new GlobalizedMessage(
"ui.admin.user.email_form.bouncing", "ui.admin.user.email_form.bouncing",
ADMIN_BUNDLE)))); ADMIN_BUNDLE))));
emailForm.add(emailFormBouncing);
emailForm.add(new SaveCancelSection()); emailForm.add(new SaveCancelSection());
@ -370,21 +434,65 @@ public class UserAdmin extends BoxPanel {
}); });
emailForm.addProcessListener(e -> { emailForm.addProcessListener(e -> {
final PageState state = e.getPageState();
final String selected = selectedEmailAddress.getSelectedKey(state);
final String userIdStr = selectedUserId.getSelectedKey(state);
final UserRepository userRepository = CdiUtil.createCdiUtil()
.findBean(UserRepository.class);
final User user = userRepository.findById(Long.parseLong(
userIdStr));
EmailAddress email = null;
if (selected == null) {
email = new EmailAddress();
user.addEmailAddress(email);
} else if (user.getPrimaryEmailAddress().getAddress().equals(
selected)) {
email = user.getPrimaryEmailAddress();
} else {
for (EmailAddress current : user.getEmailAddresses()) {
if (current.getAddress().equals(selected)) {
email = current;
break;
}
}
}
if (email != null) {
email.setAddress((String) emailFormAddress.getValue(state));
final String[] verifiedValues = (String[]) emailFormVerified
.getValue(state);
if (verifiedValues != null && verifiedValues.length > 0) {
if ("true".equals(verifiedValues[0])) {
email.setVerified(true);
} else {
email.setVerified(false);
}
} else {
email.setVerified(false);
}
final String[] bouncingValues = (String[]) emailFormBouncing
.getValue(state);
if (bouncingValues != null && bouncingValues.length > 0) {
if ("true".equals(bouncingValues[0])) {
email.setBouncing(true);
} else {
email.setBouncing(false);
}
} else {
email.setBouncing(false);
}
}
userRepository.save(user);
closeEmailForm(e.getPageState()); closeEmailForm(e.getPageState());
}); });
emailForm.addCancelListener(e -> closeEmailForm(e.getPageState())); emailForm.addCancelListener(e -> closeEmailForm(e.getPageState()));
// emailFormAddress.setLabel(new GlobalizedMessage(
// "ui.admin.user.email_form.verified",
// ADMIN_BUNDLE));
// emailForm.add(new Label(new GlobalizedMessage(
// "ui.admin.user.email_form.verified",
// ADMIN_BUNDLE)));
//
// emailForm.add(new Label(new GlobalizedMessage(
// "ui.admin.user.email_form.bouncing",
// ADMIN_BUNDLE)));
add(emailForm); add(emailForm);
add(userDetails); add(userDetails);

View File

@ -42,7 +42,7 @@ public class UserEmailTableModel implements TableModel {
protected static final int COL_DELETE = 4; protected static final int COL_DELETE = 4;
private final List<EmailAddress> emailAddresses; private final List<EmailAddress> emailAddresses;
private int index; private int index = -1;
private boolean finished; private boolean finished;
public UserEmailTableModel(final User user) { public UserEmailTableModel(final User user) {
@ -56,12 +56,18 @@ public class UserEmailTableModel implements TableModel {
@Override @Override
public boolean nextRow() { public boolean nextRow() {
if (index < emailAddresses.size()) { if (emailAddresses == null || emailAddresses.isEmpty()) {
index++;
return true;
} else {
return false; return false;
} }
// if (index < emailAddresses.size()) {
// index++;
// return true;
// } else {
// return false;
// }
index++;
return index < emailAddresses.size();
} }
@Override @Override

View File

@ -33,6 +33,7 @@ import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root; import javax.persistence.criteria.Root;
import javax.transaction.Transactional;
/** /**
* A base class providing common method needed by every repository. * A base class providing common method needed by every repository.
@ -274,6 +275,7 @@ public abstract class AbstractEntityRepository<K, E> {
* *
* @param entity The entity to save. * @param entity The entity to save.
*/ */
@Transactional(Transactional.TxType.REQUIRED)
public void save(final E entity) { public void save(final E entity) {
if (isNew(entity)) { if (isNew(entity)) {
initNewEntity(entity); initNewEntity(entity);

View File

@ -225,11 +225,11 @@ public class User extends Party implements Serializable {
this.emailAddresses = emailAddresses; this.emailAddresses = emailAddresses;
} }
protected void addEmailAddress(final EmailAddress emailAddress) { public void addEmailAddress(final EmailAddress emailAddress) {
emailAddresses.add(emailAddress); emailAddresses.add(emailAddress);
} }
protected void removeEmailAddress(final EmailAddress emailAddress) { public void removeEmailAddress(final EmailAddress emailAddress) {
emailAddresses.remove(emailAddress); emailAddresses.remove(emailAddress);
} }

View File

@ -0,0 +1,100 @@
bebop.demo.demobebop_has_been_merged_with_bebopdemo=Demo-bebop has been merged with bebop-demo.
bebop.demo.go_there=Go there
bebop.demo.this_is_the_main_content_area=this is the main content area.
bebop.demo.four_score_and_seven_years_ago_blah_blah=four score and seven years ago... blah blah...
bebop.demo.tab_a=Tab A
bebop.demo.tab_b=Tab B
bebop.demo.this_outer_panel_runs_across=This outer panel runs across
bebop.demo.this_is_in_the_outer_panel_again=This is in the outer panel again
bebop.demo.this_inner_panel_runs_downwards=This inner panel runs downwards.
bebop.demo.its_axis_defaults_to_vertical=Its axis defaults to VERTICAL,
bebop.demo.centering_to_false=centering to false,
bebop.demo.border_to_0_false=border to 0 (false),
bebop.demo.and_its_width_is_unconstrained=and its width is unconstrained.
bebop.demo.hello_world_=Hello, World !
bebop.demo.link_text=Link Text
bebop.demo.you_are_connecting_from=You are connecting from
bebop.demo.dont_care=don't care
bebop.demo.your_request_header_specifies=Your request header specifies
bebop.demo.this_should_be_full_width_aligned_right=This should be full width, aligned right
bebop.demo.this_should_be_full_width_and_centered=This should be full width and centered
bebop.demo.this_should_not_be_full_width=This should not be full width
bebop.demo.yet_another_single_column=yet another single column
bebop.demo.third_1_column_cell=Third 1 column cell
bebop.demo.lone_cell_makes_table_look_bad=lone cell makes table look bad
bebop.demo.centered_across_the_full_width=Centered across the full width
bebop.demo.only_one_column=only one column
bebop.demo.rightaligned_single_column=right-aligned single column
bebop.demo.full_width_and_aligned_right=full width and aligned right
bebop.demo.lonely_cell_on_last_row=lonely cell on last row
bebop.demo.this_is_the_blurb=this is the Blurb
bebop.demo.a_static_label=A static label
bebop.demo.this_should_be_full_width_too=This should be full width too
bebop.demo.header=Header
bebop.demo.left_component=Left Component
bebop.demo.right_component=Right Component
bebop.demo.ignored=Ignored
bebop.demo.this_pane_talks_about_monocotyledons=This pane talks about monocotyledons
bebop.demo.this_pane_talks_about_dicotyledons=This pane talks about dicotyledons
bebop.demo.street=Street
bebop.demo.country=Country
bebop.demo.subscribe_to_our_mailing_list=Subscribe to our mailing list
bebop.demo.name=Name:
bebop.demo.age=Age:
bebop.demo.email_required=Email (required):
bebop.demo.why_would_you_ever_want_to_subscribe_to_spam_=Why would you ever want to subscribe to spam ?
bebop.demo.customize_your_sandwich=Customize Your Sandwich
bebop.demo.protein=Protein:
bebop.demo.vitamins=Vitamins:
bebop.demo.sauce=Sauce:
bebop.demo.payment_method=Payment Method:
bebop.demo.now_with_100_more_tofu_=Now with 100% more tofu !
bebop.demo.delivery=Delivery
bebop.demo.shipment_method=Shipment Method:
bebop.demo.purchase=Purchase
bebop.demo.animal_kingdom_little_lamb=Animal Kingdom: Little Lamb
bebop.demo.workflow.process_name=Process Name
bebop.demo.workflow.short_description=Short Description
bebop.demo.workflow.name=Name
bebop.demo.workflow.task=Task
bebop.demo.workflow.description=Description
bebop.demo.workflow.depends_on=Depends on
bebop.demo.workflow.h4emselect_process_to_view_detailsemh4=<h4><em>Select Process to View Details</em></h4>
bebop.demo.workflow.task_details=Task details
bebop.demo.workflow.default_assignee_group=Default assignee group
bebop.demo.workflow.dependencies=Dependencies
bebop.demo.workflow.add_dependency=Add dependency
bebop.demo.workflow.none=None
bebop.demo.workflow.h4workflow_templatesh4=<h4>Workflow Templates</h4>
bebop.demo.workflow.add_template=add template
bebop.page=Page:
bebop.previous=Previous
bebop.next=Next
bebop.please_select_choice_from_the_list_on_the_left=Please select choice from the list on the left
bebop.send_email_to_everybody=Send email to everybody
bebop.basic_item_metadata=Basic Item Metadata
bebop.title=Title:
bebop.click_here=click here
bebop.demo.foo_is_null=foo is null.
bebop.demo.this_link_showshides_the_blurb=This link shows/hides the Blurb
bebop.demo.no_action=no action
bebop.event.default_text=Default text
bebop.event.call_no=Call no.
bebop.first_name=First Name:
bebop.last_name=Last Name:
bebop.hello_world=Hello World
bebop.edit_the_foo_property=Edit the Foo property
bebop.table.=&nbsp;
bebop.the_table_is_empty=The table is empty
bebop.util.some_text=Some Text
bebop.subject=Subject
bebop.body=Body
bebop.are_you_sure=Are you sure?
bebop.the_model_is_empty=The Model is Empty
bebop.save=Save
bebop.cancel=Cancel
bebop.cancel.msg=Submission Cancelled
bebop.parameter.unexpected_value_type=Unexpected value type: {0}
bebop.date.year.hint=Year
bebop.date.year.label=Year
bebop.hint.no_entry_yet=No information available yet.

View File

@ -0,0 +1,100 @@
bebop.demo.demobebop_has_been_merged_with_bebopdemo=Demo-bebop has been merged with bebop-demo.
bebop.demo.go_there=Go there
bebop.demo.this_is_the_main_content_area=this is the main content area.
bebop.demo.four_score_and_seven_years_ago_blah_blah=four score and seven years ago... blah blah...
bebop.demo.tab_a=Tab A
bebop.demo.tab_b=Tab B
bebop.demo.this_outer_panel_runs_across=This outer panel runs across
bebop.demo.this_is_in_the_outer_panel_again=This is in the outer panel again
bebop.demo.this_inner_panel_runs_downwards=This inner panel runs downwards.
bebop.demo.its_axis_defaults_to_vertical=Its axis defaults to VERTICAL,
bebop.demo.centering_to_false=centering to false,
bebop.demo.border_to_0_false=border to 0 (false),
bebop.demo.and_its_width_is_unconstrained=and its width is unconstrained.
bebop.demo.hello_world_=Hello, World !
bebop.demo.link_text=Link Text
bebop.demo.you_are_connecting_from=You are connecting from
bebop.demo.dont_care=don't care
bebop.demo.your_request_header_specifies=Your request header specifies
bebop.demo.this_should_be_full_width_aligned_right=This should be full width, aligned right
bebop.demo.this_should_be_full_width_and_centered=This should be full width and centered
bebop.demo.this_should_not_be_full_width=This should not be full width
bebop.demo.yet_another_single_column=yet another single column
bebop.demo.third_1_column_cell=Third 1 column cell
bebop.demo.lone_cell_makes_table_look_bad=lone cell makes table look bad
bebop.demo.centered_across_the_full_width=Centered across the full width
bebop.demo.only_one_column=only one column
bebop.demo.rightaligned_single_column=right-aligned single column
bebop.demo.full_width_and_aligned_right=full width and aligned right
bebop.demo.lonely_cell_on_last_row=lonely cell on last row
bebop.demo.this_is_the_blurb=this is the Blurb
bebop.demo.a_static_label=A static label
bebop.demo.this_should_be_full_width_too=This should be full width too
bebop.demo.header=Header
bebop.demo.left_component=Left Component
bebop.demo.right_component=Right Component
bebop.demo.ignored=Ignored
bebop.demo.this_pane_talks_about_monocotyledons=This pane talks about monocotyledons
bebop.demo.this_pane_talks_about_dicotyledons=This pane talks about dicotyledons
bebop.demo.street=Street
bebop.demo.country=Country
bebop.demo.subscribe_to_our_mailing_list=Subscribe to our mailing list
bebop.demo.name=Name:
bebop.demo.age=Age:
bebop.demo.email_required=Email (required):
bebop.demo.why_would_you_ever_want_to_subscribe_to_spam_=Why would you ever want to subscribe to spam ?
bebop.demo.customize_your_sandwich=Customize Your Sandwich
bebop.demo.protein=Protein:
bebop.demo.vitamins=Vitamins:
bebop.demo.sauce=Sauce:
bebop.demo.payment_method=Payment Method:
bebop.demo.now_with_100_more_tofu_=Now with 100% more tofu !
bebop.demo.delivery=Delivery
bebop.demo.shipment_method=Shipment Method:
bebop.demo.purchase=Purchase
bebop.demo.animal_kingdom_little_lamb=Animal Kingdom: Little Lamb
bebop.demo.workflow.process_name=Process Name
bebop.demo.workflow.short_description=Short Description
bebop.demo.workflow.name=Name
bebop.demo.workflow.task=Task
bebop.demo.workflow.description=Description
bebop.demo.workflow.depends_on=Depends on
bebop.demo.workflow.h4emselect_process_to_view_detailsemh4=<h4><em>Select Process to View Details</em></h4>
bebop.demo.workflow.task_details=Task details
bebop.demo.workflow.default_assignee_group=Default assignee group
bebop.demo.workflow.dependencies=Dependencies
bebop.demo.workflow.add_dependency=Add dependency
bebop.demo.workflow.none=None
bebop.demo.workflow.h4workflow_templatesh4=<h4>Workflow Templates</h4>
bebop.demo.workflow.add_template=add template
bebop.page=Seite:
bebop.previous=Zur\u00fcck
bebop.next=Weiter
bebop.please_select_choice_from_the_list_on_the_left=Bitte eine Auswahl aus der Liste links treffen
bebop.send_email_to_everybody=Sende E-Mail an alle
bebop.basic_item_metadata=Basis Metadaten
bebop.title=Titel:
bebop.click_here=Hier klicken
bebop.demo.foo_is_null=foo is null.
bebop.demo.this_link_showshides_the_blurb=This link shows/hides the Blurb
bebop.demo.no_action=no action
bebop.event.default_text=Default Text
bebop.event.call_no=Call no.
bebop.first_name=Vorname:
bebop.last_name=Nachname:
bebop.hello_world=Hallo Welt
bebop.edit_the_foo_property=Edit the Foo property
bebop.table.=&nbsp;
bebop.the_table_is_empty=The table is empty
bebop.util.some_text=Beliebiger Text
bebop.subject=Betreff
bebop.body=Body
bebop.are_you_sure=Sind Sie sicher?
bebop.the_model_is_empty=The Model is Empty
bebop.save=Speichern
bebop.cancel=Abbrechen
bebop.cancel.msg=Bearbeitung abgebrochen
bebop.parameter.unexpected_value_type=Unerwarteter Typ des Wertes: {0}
bebop.date.year.hint=Jahr
bebop.date.year.label=Jahr
bebop.hint.no_entry_yet=Gegenw\u00e4rtig noch keine Information verf\u00fcgbar.

View File

@ -0,0 +1,100 @@
bebop.demo.demobebop_has_been_merged_with_bebopdemo=TRANSLATE THIS: Demo-bebop has been merged with bebop-demo. (bebop.demo.demobebop_has_been_merged_with_bebopdemo)
bebop.demo.go_there=TRANSLATE THIS: Go there (bebop.demo.go_there)
bebop.demo.this_is_the_main_content_area=TRANSLATE THIS: this is the main content area. (bebop.demo.this_is_the_main_content_area)
bebop.demo.four_score_and_seven_years_ago_blah_blah=TRANSLATE THIS: four score and seven years ago... blah blah... (bebop.demo.four_score_and_seven_years_ago_blah_blah)
bebop.demo.tab_a=TRANSLATE THIS: Tab A (bebop.demo.tab_a)
bebop.demo.tab_b=TRANSLATE THIS: Tab B (bebop.demo.tab_b)
bebop.demo.this_outer_panel_runs_across=TRANSLATE THIS: This outer panel runs across (bebop.demo.this_outer_panel_runs_across)
bebop.demo.this_is_in_the_outer_panel_again=TRANSLATE THIS: This is in the outer panel again (bebop.demo.this_is_in_the_outer_panel_again)
bebop.demo.this_inner_panel_runs_downwards=TRANSLATE THIS: This inner panel runs downwards. (bebop.demo.this_inner_panel_runs_downwards)
bebop.demo.its_axis_defaults_to_vertical=TRANSLATE THIS: Its axis defaults to VERTICAL, (bebop.demo.its_axis_defaults_to_vertical)
bebop.demo.centering_to_false=TRANSLATE THIS: centering to false, (bebop.demo.centering_to_false)
bebop.demo.border_to_0_false=TRANSLATE THIS: border to 0 (false), (bebop.demo.border_to_0_false)
bebop.demo.and_its_width_is_unconstrained=TRANSLATE THIS: and its width is unconstrained. (bebop.demo.and_its_width_is_unconstrained)
bebop.demo.hello_world_=TRANSLATE THIS: Hello, World ! (bebop.demo.hello_world_)
bebop.demo.link_text=TRANSLATE THIS: Link Text (bebop.demo.link_text)
bebop.demo.you_are_connecting_from=TRANSLATE THIS: You are connecting from (bebop.demo.you_are_connecting_from)
bebop.demo.dont_care=TRANSLATE THIS: don't care (bebop.demo.dont_care)
bebop.demo.your_request_header_specifies=TRANSLATE THIS: Your request header specifies (bebop.demo.your_request_header_specifies)
bebop.demo.this_should_be_full_width_aligned_right=TRANSLATE THIS: This should be full width, aligned right (bebop.demo.this_should_be_full_width_aligned_right)
bebop.demo.this_should_be_full_width_and_centered=TRANSLATE THIS: This should be full width and centered (bebop.demo.this_should_be_full_width_and_centered)
bebop.demo.this_should_not_be_full_width=TRANSLATE THIS: This should not be full width (bebop.demo.this_should_not_be_full_width)
bebop.demo.yet_another_single_column=TRANSLATE THIS: yet another single column (bebop.demo.yet_another_single_column)
bebop.demo.third_1_column_cell=TRANSLATE THIS: Third 1 column cell (bebop.demo.third_1_column_cell)
bebop.demo.lone_cell_makes_table_look_bad=TRANSLATE THIS: lone cell makes table look bad (bebop.demo.lone_cell_makes_table_look_bad)
bebop.demo.centered_across_the_full_width=TRANSLATE THIS: Centered across the full width (bebop.demo.centered_across_the_full_width)
bebop.demo.only_one_column=TRANSLATE THIS: only one column (bebop.demo.only_one_column)
bebop.demo.rightaligned_single_column=TRANSLATE THIS: right-aligned single column (bebop.demo.rightaligned_single_column)
bebop.demo.full_width_and_aligned_right=TRANSLATE THIS: full width and aligned right (bebop.demo.full_width_and_aligned_right)
bebop.demo.lonely_cell_on_last_row=TRANSLATE THIS: lonely cell on last row (bebop.demo.lonely_cell_on_last_row)
bebop.demo.this_is_the_blurb=TRANSLATE THIS: this is the Blurb (bebop.demo.this_is_the_blurb)
bebop.demo.a_static_label=TRANSLATE THIS: A static label (bebop.demo.a_static_label)
bebop.demo.this_should_be_full_width_too=TRANSLATE THIS: This should be full width too (bebop.demo.this_should_be_full_width_too)
bebop.demo.header=TRANSLATE THIS: Header (bebop.demo.header)
bebop.demo.left_component=TRANSLATE THIS: Left Component (bebop.demo.left_component)
bebop.demo.right_component=TRANSLATE THIS: Right Component (bebop.demo.right_component)
bebop.demo.ignored=TRANSLATE THIS: Ignored (bebop.demo.ignored)
bebop.demo.this_pane_talks_about_monocotyledons=TRANSLATE THIS: This pane talks about monocotyledons (bebop.demo.this_pane_talks_about_monocotyledons)
bebop.demo.this_pane_talks_about_dicotyledons=TRANSLATE THIS: This pane talks about dicotyledons (bebop.demo.this_pane_talks_about_dicotyledons)
bebop.demo.street=TRANSLATE THIS: Street (bebop.demo.street)
bebop.demo.country=TRANSLATE THIS: Country (bebop.demo.country)
bebop.demo.subscribe_to_our_mailing_list=TRANSLATE THIS: Subscribe to our mailing list (bebop.demo.subscribe_to_our_mailing_list)
bebop.demo.name=TRANSLATE THIS: Name: (bebop.demo.name)
bebop.demo.age=TRANSLATE THIS: Age: (bebop.demo.age)
bebop.demo.email_required=TRANSLATE THIS: Email (required): (bebop.demo.email_required)
bebop.demo.why_would_you_ever_want_to_subscribe_to_spam_=TRANSLATE THIS: Why would you ever want to subscribe to spam ? (bebop.demo.why_would_you_ever_want_to_subscribe_to_spam_)
bebop.demo.customize_your_sandwich=TRANSLATE THIS: Customize Your Sandwich (bebop.demo.customize_your_sandwich)
bebop.demo.protein=TRANSLATE THIS: Protein: (bebop.demo.protein)
bebop.demo.vitamins=TRANSLATE THIS: Vitamins: (bebop.demo.vitamins)
bebop.demo.sauce=TRANSLATE THIS: Sauce: (bebop.demo.sauce)
bebop.demo.payment_method=TRANSLATE THIS: Payment Method: (bebop.demo.payment_method)
bebop.demo.now_with_100_more_tofu_=TRANSLATE THIS: Now with 100% more tofu ! (bebop.demo.now_with_100_more_tofu_)
bebop.demo.delivery=TRANSLATE THIS: Delivery (bebop.demo.delivery)
bebop.demo.shipment_method=TRANSLATE THIS: Shipment Method: (bebop.demo.shipment_method)
bebop.demo.purchase=TRANSLATE THIS: Purchase (bebop.demo.purchase)
bebop.demo.animal_kingdom_little_lamb=TRANSLATE THIS: Animal Kingdom: Little Lamb (bebop.demo.animal_kingdom_little_lamb)
bebop.demo.workflow.process_name=TRANSLATE THIS: Process Name (bebop.demo.workflow.process_name)
bebop.demo.workflow.short_description=TRANSLATE THIS: Short Description (bebop.demo.workflow.short_description)
bebop.demo.workflow.name=TRANSLATE THIS: Name (bebop.demo.workflow.name)
bebop.demo.workflow.task=TRANSLATE THIS: Task (bebop.demo.workflow.task)
bebop.demo.workflow.description=TRANSLATE THIS: Description (bebop.demo.workflow.description)
bebop.demo.workflow.depends_on=TRANSLATE THIS: Depends on (bebop.demo.workflow.depends_on)
bebop.demo.workflow.h4emselect_process_to_view_detailsemh4=TRANSLATE THIS: <h4><em>Select Process to View Details</em></h4> (bebop.demo.workflow.h4emselect_process_to_view_detailsemh4)
bebop.demo.workflow.task_details=TRANSLATE THIS: Task details (bebop.demo.workflow.task_details)
bebop.demo.workflow.default_assignee_group=TRANSLATE THIS: Default assignee group (bebop.demo.workflow.default_assignee_group)
bebop.demo.workflow.dependencies=TRANSLATE THIS: Dependencies (bebop.demo.workflow.dependencies)
bebop.demo.workflow.add_dependency=TRANSLATE THIS: Add dependency (bebop.demo.workflow.add_dependency)
bebop.demo.workflow.none=TRANSLATE THIS: None (bebop.demo.workflow.none)
bebop.demo.workflow.h4workflow_templatesh4=TRANSLATE THIS: <h4>Workflow Templates</h4> (bebop.demo.workflow.h4workflow_templatesh4)
bebop.demo.workflow.add_template=TRANSLATE THIS: add template (bebop.demo.workflow.add_template)
bebop.page=TRANSLATE THIS: Page: (bebop.page)
bebop.previous=TRANSLATE THIS: Previous (bebop.previous)
bebop.next=TRANSLATE THIS: Next (bebop.next)
bebop.please_select_choice_from_the_list_on_the_left=TRANSLATE THIS: Please select choice from the list on the left (bebop.please_select_choice_from_the_list_on_the_left)
bebop.send_email_to_everybody=TRANSLATE THIS: Send email to everybody (bebop.send_email_to_everybody)
bebop.basic_item_metadata=TRANSLATE THIS: Basic Item Metadata (bebop.basic_item_metadata)
bebop.title=TRANSLATE THIS: Title: (bebop.title)
bebop.click_here=TRANSLATE THIS: click here (bebop.click_here)
bebop.demo.foo_is_null=TRANSLATE THIS: foo is null. (bebop.demo.foo_is_null)
bebop.demo.this_link_showshides_the_blurb=TRANSLATE THIS: This link shows/hides the Blurb (bebop.demo.this_link_showshides_the_blurb)
bebop.demo.no_action=TRANSLATE THIS: no action (bebop.demo.no_action)
bebop.event.default_text=TRANSLATE THIS: Default text (bebop.event.default_text)
bebop.event.call_no=TRANSLATE THIS: Call no. (bebop.event.call_no)
bebop.first_name=TRANSLATE THIS: First Name: (bebop.first_name)
bebop.last_name=TRANSLATE THIS: Last Name: (bebop.last_name)
bebop.hello_world=TRANSLATE THIS: Hello World (bebop.hello_world)
bebop.edit_the_foo_property=TRANSLATE THIS: Edit the Foo property (bebop.edit_the_foo_property)
bebop.table.=TRANSLATE THIS: &nbsp; (bebop.table.)
bebop.the_table_is_empty=TRANSLATE THIS: The table is empty (bebop.the_table_is_empty)
bebop.util.some_text=TRANSLATE THIS: Some Text (bebop.util.some_text)
bebop.subject=TRANSLATE THIS: Subject (bebop.subject)
bebop.body=TRANSLATE THIS: Body (bebop.body)
bebop.are_you_sure=TRANSLATE THIS: Are you sure? (bebop.are_you_sure)
bebop.the_model_is_empty=TRANSLATE THIS: The Model is Empty (bebop.the_model_is_empty)
bebop.save=TRANSLATE THIS: Previous (bebop.save)
bebop.cancel=TRANSLATE THIS: Previous (bebop.cancel)
bebop.cancel.msg=TRANSLATE THIS: Previous (bebop.cancel.submission.msg)
bebop.parameter.unexpected_value_type=Unexpected value type: {0}
bebop.date.year.hint=
bebop.date.year.label=
bebop.hint.no_entry_yet=No information available yet.

View File

@ -196,3 +196,9 @@ ui.admin.user.email_addresses.delete=Delete
ui.admin.user.primary_email.action=Action ui.admin.user.primary_email.action=Action
ui.admin.user.email_addresses.none=No additional email addresses ui.admin.user.email_addresses.none=No additional email addresses
ui.admin.user.email_addresses.add=Add email address ui.admin.user.email_addresses.add=Add email address
ui.admin.user.email_form.address=Email address
ui.admin.user.email_form.verified=Verified
ui.admin.user.email_form.bouncing=Bouncing
ui.admin.user.email_form.address.not_empty=Email address can't be empty.
ui.admin.user.email_addresses.delete.confirm=Are sure to delete this email address?
ui.admin.user_details.generate_password.confirm=Are you sure to reset this users password?

View File

@ -196,3 +196,9 @@ ui.admin.user.email_addresses.delete=L\u00f6schen
ui.admin.user.primary_email.action=Aktion ui.admin.user.primary_email.action=Aktion
ui.admin.user.email_addresses.none=Keine weiteren E-Mail-Adressen ui.admin.user.email_addresses.none=Keine weiteren E-Mail-Adressen
ui.admin.user.email_addresses.add=E-Mail-Adresse hinzuf\u00fcgen ui.admin.user.email_addresses.add=E-Mail-Adresse hinzuf\u00fcgen
ui.admin.user.email_form.address=E-Mail-Adresse
ui.admin.user.email_form.verified=Verifiziert
ui.admin.user.email_form.bouncing=Wird zur\u00fcckgewiesen
ui.admin.user.email_form.address.not_empty=Die E-Mail-Adresse darf nicht leer sein.
ui.admin.user.email_addresses.delete.confirm=Sind Sie sicher, dass Sie diese E-Mail-Adresse l\u00f6schen wollen?
ui.admin.user_details.generate_password.confirm=Sind Sie sicher, dass Sie das Passwort dieses Benutzers zur\u00fccksetzen wollen?

View File

@ -169,3 +169,9 @@ ui.admin.user.email_addresses.delete=Delete
ui.admin.user.primary_email.action=Action ui.admin.user.primary_email.action=Action
ui.admin.user.email_addresses.none=No additional email addresses ui.admin.user.email_addresses.none=No additional email addresses
ui.admin.user.email_addresses.add=Add email address ui.admin.user.email_addresses.add=Add email address
ui.admin.user.email_form.address=Email address
ui.admin.user.email_form.verified=Verified
ui.admin.user.email_form.bouncing=Bouncing
ui.admin.user.email_form.address.not_empty=Email address can't be empty.
ui.admin.user.email_addresses.delete.confirm=Are sure to delete this email address?
ui.admin.user_details.generate_password.confirm=Are you sure to reset this users password?

View File

@ -160,3 +160,9 @@ ui.admin.user.email_addresses.delete=Delete
ui.admin.user.primary_email.action=Action ui.admin.user.primary_email.action=Action
ui.admin.user.email_addresses.none=No additional email addresses ui.admin.user.email_addresses.none=No additional email addresses
ui.admin.user.email_addresses.add=Add email address ui.admin.user.email_addresses.add=Add email address
ui.admin.user.email_form.address=Email address
ui.admin.user.email_form.verified=Verified
ui.admin.user.email_form.bouncing=Bouncing
ui.admin.user.email_form.address.not_empty=Email address can't be empty.
ui.admin.user.email_addresses.delete.confirm=Are sure to delete this email address?
ui.admin.user_details.generate_password.confirm=Are you sure to reset this users password?