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

View File

@ -72,15 +72,26 @@ public final class MailConfig {
if (javaMailPropertiesFile == null
|| javaMailPropertiesFile.isEmpty()) {
properties.put("mail.transport.protocol", "smtp");
properties.put("mail.smtp.host", "localhost");
if (System.getProperty("ccm.mail.config") == null) {
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 {
try {
properties.load(new URL(javaMailPropertiesFile).openStream());
} catch (IOException ex) {
throw new UncheckedWrapperException(String.format(
"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.ControlLink;
import com.arsdigita.bebop.Form;
import com.arsdigita.bebop.FormProcessException;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.Page;
import com.arsdigita.bebop.PageState;
@ -32,26 +31,32 @@ import com.arsdigita.bebop.PropertySheet;
import com.arsdigita.bebop.SaveCancelSection;
import com.arsdigita.bebop.Table;
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.TableActionListener;
import com.arsdigita.bebop.form.CheckboxGroup;
import com.arsdigita.bebop.form.Option;
import com.arsdigita.bebop.form.Submit;
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.table.TableCellRenderer;
import com.arsdigita.bebop.table.TableColumn;
import com.arsdigita.bebop.table.TableColumnModel;
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.core.EmailAddress;
import org.libreccm.security.User;
import org.libreccm.security.UserManager;
import org.libreccm.security.UserRepository;
import java.util.logging.Level;
import javax.mail.MessagingException;
import static com.arsdigita.ui.admin.AdminUiConstants.*;
/**
@ -60,7 +65,9 @@ import static com.arsdigita.ui.admin.AdminUiConstants.*;
*/
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 ParameterSingleSelectionModel<String> selectedUserId;
private final ParameterSingleSelectionModel<String> selectedEmailAddress;
@ -98,7 +105,7 @@ public class UserAdmin extends BoxPanel {
filterForm.add(clearLink);
usersTablePanel.add(filterForm);
userIdParameter = new LongParameter("selected_user_id");
userIdParameter = new StringParameter("selected_user_id");
selectedUserId = new ParameterSingleSelectionModel<>(userIdParameter);
//selectedUserId = new ParameterSingleSelectionModel<>(USER_ID_PARAM);
@ -159,8 +166,25 @@ public class UserAdmin extends BoxPanel {
final ActionLink generatePasswordLink = new ActionLink(
new GlobalizedMessage("ui.admin.user_details.generate_password",
ADMIN_BUNDLE));
generatePasswordLink.setConfirmation(new GlobalizedMessage(
"ui.admin.user_details.generate_password.confirm",
ADMIN_BUNDLE));
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);
userDetails.add(actionLinks);
@ -266,7 +290,7 @@ public class UserAdmin extends BoxPanel {
final Object key,
final int row,
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 int row,
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
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
@ -307,7 +365,7 @@ public class UserAdmin extends BoxPanel {
final ActionLink addEmailLink = new ActionLink(new GlobalizedMessage(
"ui.admin.user.email_addresses.add", ADMIN_BUNDLE));
addEmailLink.addActionListener(e -> {
//ToDo
showEmailForm(e.getPageState());
});
userDetails.add(addEmailLink);
@ -318,6 +376,10 @@ public class UserAdmin extends BoxPanel {
final TextField emailFormAddress = new TextField("email_form_address");
emailFormAddress.setLabel(new GlobalizedMessage(
"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(
"email_form_verified");
emailFormVerified.addOption(
@ -325,13 +387,15 @@ public class UserAdmin extends BoxPanel {
new Label(new GlobalizedMessage(
"ui.admin.user.email_form.verified",
ADMIN_BUNDLE))));
emailForm.add(emailFormVerified);
final CheckboxGroup emailFormBouncing = new CheckboxGroup(
"email_form_verified");
"email_form_bouncing");
emailFormBouncing.addOption(
new Option("true",
new Label(new GlobalizedMessage(
"ui.admin.user.email_form.bouncing",
ADMIN_BUNDLE))));
emailForm.add(emailFormBouncing);
emailForm.add(new SaveCancelSection());
@ -370,21 +434,65 @@ public class UserAdmin extends BoxPanel {
});
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());
});
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(userDetails);

View File

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

View File

@ -33,6 +33,7 @@ import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;
/**
* 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.
*/
@Transactional(Transactional.TxType.REQUIRED)
public void save(final E entity) {
if (isNew(entity)) {
initNewEntity(entity);

View File

@ -225,11 +225,11 @@ public class User extends Party implements Serializable {
this.emailAddresses = emailAddresses;
}
protected void addEmailAddress(final EmailAddress emailAddress) {
public void addEmailAddress(final EmailAddress emailAddress) {
emailAddresses.add(emailAddress);
}
protected void removeEmailAddress(final EmailAddress emailAddress) {
public void removeEmailAddress(final EmailAddress 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.email_addresses.none=No additional email addresses
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.email_addresses.none=Keine weiteren E-Mail-Adressen
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.email_addresses.none=No additional email addresses
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.email_addresses.none=No additional email addresses
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?