diff --git a/demo-tt/pom.xml b/demo-tt/pom.xml index 0bf36ed770..f0537f8c59 100644 --- a/demo-tt/pom.xml +++ b/demo-tt/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 demo-tt war @@ -123,7 +123,7 @@ 1.1.11 - + @@ -136,7 +136,7 @@ - + portofino-development diff --git a/demo-tt/src/main/webapp/jsp/projects/components/components-search.jsp b/demo-tt/src/main/webapp/jsp/projects/components/components-search.jsp index 2eb3922e49..bd9b66acf4 100644 --- a/demo-tt/src/main/webapp/jsp/projects/components/components-search.jsp +++ b/demo-tt/src/main/webapp/jsp/projects/components/components-search.jsp @@ -21,7 +21,7 @@ - + diff --git a/demo-tt/src/main/webapp/jsp/projects/versions/versions-search.jsp b/demo-tt/src/main/webapp/jsp/projects/versions/versions-search.jsp index 1ff31f78a4..41946cbc6a 100644 --- a/demo-tt/src/main/webapp/jsp/projects/versions/versions-search.jsp +++ b/demo-tt/src/main/webapp/jsp/projects/versions/versions-search.jsp @@ -21,7 +21,7 @@ - + diff --git a/elements/pom.xml b/elements/pom.xml index 693c35aee9..9a4ffcc2d5 100755 --- a/elements/pom.xml +++ b/elements/pom.xml @@ -2,142 +2,154 @@ - 4.0.0 - - com.manydesigns - portofino - 4.2.4-SNAPSHOT - - elements - jar - http://www.manydesigns.com/ - - - javax.servlet - javax.servlet-api - provided - - - javax.servlet.jsp - javax.servlet.jsp-api - provided - - - - commons-lang - commons-lang - ${commons.lang.version} - compile - - - commons-io - commons-io - ${commons.io.version} - compile - - - commons-fileupload - commons-fileupload - ${commons.fileupload.version} - compile - - - commons-configuration - commons-configuration - ${commons.configuration.version} - compile - - - commons-logging - commons-logging - - - commons-beanutils - commons-beanutils-core - - - - - commons-collections - commons-collections - ${commons.collections.version} - compile - - - com.google.guava - guava - ${guava.version} - compile - - - - ognl - ognl - ${ognl.version} - compile - - - javassist - javassist - - - - - - org.javassist - javassist - ${javassist.version} - compile - - - joda-time - joda-time - ${joda-time.version} - compile - - - org.slf4j - slf4j-api - ${slf4j.version} - compile - - - com.intellij - annotations - 7.0.3 - - - org.json - json - ${json.version} - - - - net.sourceforge.stripes - stripes - ${stripes.version} - compile - - - commons-logging - commons-logging - - - log4j - log4j - - - - - - org.apache.xmlgraphics - fop - provided - - - net.sourceforge.jexcelapi - jxl - provided - - + 4.0.0 + + com.manydesigns + portofino + 4.2.4 + + elements + jar + http://www.manydesigns.com/ + + + javax.servlet + javax.servlet-api + provided + + + javax.servlet.jsp + javax.servlet.jsp-api + provided + + + + commons-lang + commons-lang + ${commons.lang.version} + compile + + + commons-io + commons-io + ${commons.io.version} + compile + + + commons-fileupload + commons-fileupload + ${commons.fileupload.version} + compile + + + commons-configuration + commons-configuration + ${commons.configuration.version} + compile + + + commons-logging + commons-logging + + + commons-beanutils + commons-beanutils-core + + + + + commons-collections + commons-collections + ${commons.collections.version} + compile + + + com.google.guava + guava + ${guava.version} + compile + + + + ognl + ognl + ${ognl.version} + compile + + + javassist + javassist + + + + + + org.javassist + javassist + ${javassist.version} + compile + + + joda-time + joda-time + ${joda-time.version} + compile + + + org.slf4j + slf4j-api + ${slf4j.version} + compile + + + com.intellij + annotations + 7.0.3 + + + org.json + json + ${json.version} + + + + net.sourceforge.stripes + stripes + ${stripes.version} + compile + + + commons-logging + commons-logging + + + log4j + log4j + + + + + + org.apache.xmlgraphics + fop + provided + + + net.sourceforge.jexcelapi + jxl + provided + + + com.manydesigns + portofino-cryptography + 4.2.4 + compile + + + com.fasterxml.jackson.core + jackson-databind + 2.5.4 + provided + + diff --git a/elements/src/main/java/com/manydesigns/elements/DefaultFieldEncrypter.java b/elements/src/main/java/com/manydesigns/elements/DefaultFieldEncrypter.java new file mode 100644 index 0000000000..0d9ad66bff --- /dev/null +++ b/elements/src/main/java/com/manydesigns/elements/DefaultFieldEncrypter.java @@ -0,0 +1,36 @@ +package com.manydesigns.elements; + +import com.manydesigns.crypto.CryptoService; +import com.manydesigns.elements.FieldEncrypter; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DefaultFieldEncrypter implements FieldEncrypter { + + private static final Logger logger = LoggerFactory.getLogger(DefaultFieldEncrypter.class); + + public String encrypt(String value) { + if(StringUtils.trimToNull(value) == null){ + return value; + } + try { + CryptoService.getInstance().encrypt(value); + } catch (Exception e) { + logger.error("DefaultFieldEncrypter.encrypt error:"+e.getMessage(),e); + } + return value; + } + + public String decrypt(String value) { + if(StringUtils.trimToNull(value) == null){ + return value; + } + try { + CryptoService.getInstance().decrypt(value); + } catch (Exception e) { + logger.error("DefaultFieldEncrypter.decrypt error:"+e.getMessage(),e); + } + return value; + } +} diff --git a/elements/src/main/java/com/manydesigns/elements/ElementsProperties.java b/elements/src/main/java/com/manydesigns/elements/ElementsProperties.java index ec9058b3c0..c974953651 100644 --- a/elements/src/main/java/com/manydesigns/elements/ElementsProperties.java +++ b/elements/src/main/java/com/manydesigns/elements/ElementsProperties.java @@ -86,7 +86,7 @@ public static void addConfiguration(String resource) { try { configuration.addConfiguration( new PropertiesConfiguration(resource)); - } catch (Throwable e) { + } catch (Exception e) { logger.warn(String.format( "Error loading properties from: %s", resource), e); } diff --git a/elements/src/main/java/com/manydesigns/elements/FieldEncrypter.java b/elements/src/main/java/com/manydesigns/elements/FieldEncrypter.java new file mode 100644 index 0000000000..615da7c510 --- /dev/null +++ b/elements/src/main/java/com/manydesigns/elements/FieldEncrypter.java @@ -0,0 +1,8 @@ +package com.manydesigns.elements; + +public interface FieldEncrypter { + + public String encrypt(String value); + + public String decrypt(String value); +} diff --git a/elements/src/main/java/com/manydesigns/elements/TestEncrypter.java b/elements/src/main/java/com/manydesigns/elements/TestEncrypter.java new file mode 100644 index 0000000000..e2ae80eb50 --- /dev/null +++ b/elements/src/main/java/com/manydesigns/elements/TestEncrypter.java @@ -0,0 +1,12 @@ +package com.manydesigns.elements; + +public class TestEncrypter implements FieldEncrypter { + + public String encrypt(String value) { + return value!=null?"Encrypted": null; + } + + public String decrypt(String value) { + return value!=null?"Decrypted": null; + } +} diff --git a/elements/src/main/java/com/manydesigns/elements/annotations/Encrypted.java b/elements/src/main/java/com/manydesigns/elements/annotations/Encrypted.java new file mode 100644 index 0000000000..7cb73f8f07 --- /dev/null +++ b/elements/src/main/java/com/manydesigns/elements/annotations/Encrypted.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2005-2017 ManyDesigns srl. All rights reserved. + * http://www.manydesigns.com/ + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package com.manydesigns.elements.annotations; + +import com.manydesigns.elements.FieldEncrypter; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/* +* @author Emanuele Poggi - emanuele.poggi@manydesigns.com +*/ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.METHOD}) +public @interface Encrypted { + public static final String copyright = "Copyright (C) 2005-2018 ManyDesigns srl"; + + String value(); + +} diff --git a/elements/src/main/java/com/manydesigns/elements/annotations/impl/EncryptedImpl.java b/elements/src/main/java/com/manydesigns/elements/annotations/impl/EncryptedImpl.java new file mode 100644 index 0000000000..1e4553c6ae --- /dev/null +++ b/elements/src/main/java/com/manydesigns/elements/annotations/impl/EncryptedImpl.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2005-2017 ManyDesigns srl. All rights reserved. + * http://www.manydesigns.com/ + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package com.manydesigns.elements.annotations.impl; + +import com.manydesigns.elements.FieldEncrypter; +import com.manydesigns.elements.annotations.Encrypted; + +import java.lang.annotation.Annotation; + +/* + * @author Emanuele Poggi - emanuele.poggi@manydesigns.com + */ +@SuppressWarnings({"ClassExplicitlyAnnotation"}) +public class EncryptedImpl implements Encrypted { + public static final String copyright = + "Copyright (C) 2005-2017 ManyDesigns srl"; + + private final String value; + + public EncryptedImpl(String value) { + this.value = value; + } + + public String value() { + return value; + } + + public Class annotationType() { + return Encrypted.class; + } +} diff --git a/elements/src/main/java/com/manydesigns/elements/blobs/Blob.java b/elements/src/main/java/com/manydesigns/elements/blobs/Blob.java index 07138b6728..2348373d74 100644 --- a/elements/src/main/java/com/manydesigns/elements/blobs/Blob.java +++ b/elements/src/main/java/com/manydesigns/elements/blobs/Blob.java @@ -20,13 +20,18 @@ package com.manydesigns.elements.blobs; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.io.IOUtils; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.InputStream; +import java.util.Map; import java.util.Properties; /** @@ -39,11 +44,17 @@ public class Blob { public static final String copyright = "Copyright (C) 2005-2017 ManyDesigns srl"; + public static final Logger logger = LoggerFactory.getLogger(Blob.class); + public final static String FILENAME_PROPERTY = "filename"; public final static String CONTENT_TYPE_PROPERTY = "content.type"; public final static String SIZE_PROPERTY = "size"; public final static String CREATE_TIMESTAMP_PROPERTY = "create.timestamp"; public final static String CHARACTER_ENCODING_PROPERTY = "character.encoding"; + public final static String REPOSITORY_PROPERTY = "repository"; + public final static String REPOSITORY_ID_PROPERTY = "repository.id"; + public final static String ENCRYPTION_PROPERTY = "encryption.type"; + public final static String CUSTOM_DATA_PROPERTY = "custom.data"; protected final DateTimeFormatter formatter = ISODateTimeFormat.dateTime(); @@ -55,9 +66,14 @@ public class Blob { protected String characterEncoding; protected InputStream inputStream; protected boolean propertiesLoaded; + protected String encryptionType; + protected String repository; + protected String repositoryId; + protected Map customData; public Blob(String code) { this.code = code; + //this.repository="cache"; } protected void safeSetProperty(Properties metaProperties, String key, String value) { @@ -79,6 +95,10 @@ public Properties getMetaProperties() throws IOException { safeSetProperty(metaProperties, SIZE_PROPERTY, Long.toString(size)); safeSetProperty(metaProperties, CREATE_TIMESTAMP_PROPERTY, formatter.print(createTimestamp)); safeSetProperty(metaProperties, CHARACTER_ENCODING_PROPERTY, characterEncoding); + safeSetProperty(metaProperties, REPOSITORY_PROPERTY, repository); + safeSetProperty(metaProperties, REPOSITORY_ID_PROPERTY, repositoryId); + safeSetProperty(metaProperties, ENCRYPTION_PROPERTY, encryptionType); + safeSetProperty(metaProperties, CUSTOM_DATA_PROPERTY, getSerializedCustomData()); return metaProperties; } @@ -89,6 +109,10 @@ public void setMetaProperties(Properties metaProperties) throws IOException { size = Long.parseLong(metaProperties.getProperty(SIZE_PROPERTY)); createTimestamp = formatter.parseDateTime(metaProperties.getProperty(CREATE_TIMESTAMP_PROPERTY)); characterEncoding = metaProperties.getProperty(CHARACTER_ENCODING_PROPERTY); + repository = metaProperties.getProperty(REPOSITORY_PROPERTY); + repositoryId = metaProperties.getProperty(REPOSITORY_ID_PROPERTY); + encryptionType=metaProperties.getProperty(ENCRYPTION_PROPERTY); + setCustomData(metaProperties.getProperty(CUSTOM_DATA_PROPERTY)); propertiesLoaded = true; } @@ -145,7 +169,7 @@ public InputStream getInputStream() { } public void setInputStream(InputStream inputStream) { - this.inputStream = inputStream; + this.inputStream = inputStream; } public boolean isPropertiesLoaded() { @@ -160,6 +184,64 @@ public void dispose() { IOUtils.closeQuietly(inputStream); } + public String getEncryptionType() { + return encryptionType; + } + + public String getRepository() { + return repository; + } + + public void setEncryptionType(String encryptionType) { + this.encryptionType = encryptionType; + } + + public void setRepository(String repository) { + this.repository = repository; + } + + public Boolean isEncrypted(){ + return this.encryptionType!=null; + } + + public String getRepositoryId() { + return repositoryId; + } + + public void setRepositoryId(String repositoryId) { + this.repositoryId = repositoryId; + } + + public Map getCustomData() { + return customData; + } + + public void setCustomData(Map customData) { + this.customData = customData; + } + + public String getSerializedCustomData() { + ObjectMapper mapper = new ObjectMapper(); + try { + return mapper.writeValueAsString(customData); + } catch (JsonProcessingException e) { + logger.error(e.getMessage(),e); + } + return null; + } + + public void setCustomData(String customData) { + if (customData != null && !customData.equals("")) { + try { + logger.debug("Reading customData from: "+customData); + ObjectMapper mapper = new ObjectMapper(); + this.customData = mapper.readValue(customData, Map.class); + } catch (IOException e) { + logger.error(e.getMessage(),e); + } + } + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/elements/src/main/java/com/manydesigns/elements/blobs/BlobUtils.java b/elements/src/main/java/com/manydesigns/elements/blobs/BlobUtils.java index 0962d4f4a0..24916a2ecc 100644 --- a/elements/src/main/java/com/manydesigns/elements/blobs/BlobUtils.java +++ b/elements/src/main/java/com/manydesigns/elements/blobs/BlobUtils.java @@ -1,12 +1,17 @@ package com.manydesigns.elements.blobs; +import com.manydesigns.crypto.CryptoService; import com.manydesigns.elements.FormElement; import com.manydesigns.elements.fields.AbstractBlobField; import com.manydesigns.elements.forms.FieldSet; import com.manydesigns.elements.forms.Form; import com.manydesigns.elements.forms.TableForm; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; +import java.io.InputStream; +import java.security.GeneralSecurityException; /** * @author Angelo Lupo - angelo.lupo@manydesigns.com @@ -16,6 +21,13 @@ */ public abstract class BlobUtils { + //************************************************************************** + // Logging + //************************************************************************** + + public static final Logger logger = + LoggerFactory.getLogger(BlobUtils.class); + public static void loadBlobs(Form form, BlobManager blobManager, boolean loadContents) { for(FieldSet fieldSet : form) { loadBlobs(fieldSet, blobManager, loadContents); @@ -65,4 +77,28 @@ public static void saveBlobs(FieldSet fieldSet, BlobManager blobManager) throws } } + public static InputStream encrypt( InputStream decryptedInputStream, String type ){ + try { + logger.debug("Decrypting encryptedInputStream"); + return CryptoService.getInstance().encrypt(decryptedInputStream); + } catch (GeneralSecurityException | IOException e) { + logger.error(e.getMessage(),e); + } + return decryptedInputStream; + } + + public static InputStream decrypt( InputStream encryptedInputStream , String type ){ + try { + logger.debug("Decrypting encryptedInputStream"); + return CryptoService.getInstance().decrypt(encryptedInputStream); + } catch (GeneralSecurityException | IOException e) { + logger.error(e.getMessage(),e); + } + return encryptedInputStream; + } + + public static Long calculatePaddingSize(Blob blob) { + logger.debug("Calculating padding size"); + return CryptoService.getInstance().getFileSize(blob.getSize()); + } } diff --git a/elements/src/main/java/com/manydesigns/elements/blobs/HierarchicalBlobManager.java b/elements/src/main/java/com/manydesigns/elements/blobs/HierarchicalBlobManager.java index 5107e02e80..197510b31d 100644 --- a/elements/src/main/java/com/manydesigns/elements/blobs/HierarchicalBlobManager.java +++ b/elements/src/main/java/com/manydesigns/elements/blobs/HierarchicalBlobManager.java @@ -1,8 +1,9 @@ package com.manydesigns.elements.blobs; import com.manydesigns.elements.util.RandomUtil; +import org.apache.commons.io.IOUtils; -import java.io.File; +import java.io.*; /** * @author Angelo Lupo - angelo.lupo@manydesigns.com @@ -31,4 +32,76 @@ protected File getDataFile(String code) { protected File getBlobSubdir(String code) { return new File(new File(new File(blobsDir, code.substring(0, 2)), code.substring(2, 4)), code.substring(4, 6)); } + + @Override + public InputStream openStream(Blob blob) throws IOException { + ensureValidCode(blob.getCode()); + + if( blob.getRepository() != null ) { //TODO vedere se usare così + Repository repository = RepositoryRegistry.getInstance().getRepository(blob.getRepository()); + repository.load(blob); + }else{ + if(blob.isEncrypted()) + blob.setInputStream(BlobUtils.decrypt(new FileInputStream(getDataFile(blob.getCode())),blob.getEncryptionType())); + else + blob.setInputStream(new FileInputStream(getDataFile(blob.getCode()))); + } + return blob.getInputStream(); + } + + @Override + public void save(Blob blob) throws IOException { + if( blob.getRepository() != null ){ //TODO vedere se usare così + ensureValidCode(blob.getCode()); + + Repository repository=RepositoryRegistry.getInstance().getRepository(blob.getRepository()); + repository.save(blob); + + File metaFile = getMetaFile(blob.getCode()); + if(!metaFile.getParentFile().isDirectory()) { + metaFile.getParentFile().mkdirs(); + } + FileOutputStream out = new FileOutputStream(metaFile); + try { + blob.getMetaProperties().store(out, "Remote Blob code #" + blob.getCode()); //TODO aggiungere altre info in commento + } finally { + IOUtils.closeQuietly(out); + } + blob.dispose(); + }else{ + super.save(blob); + } + } + + @Override + public boolean delete(Blob blob) { + if( !blob.isPropertiesLoaded() ){ + try{ loadMetadata(blob); } + catch (IOException e){ + logger.warn("Cound load metadata ", e); + } + } + if( blob.getRepository() != null ){ + String code = blob.getCode(); + ensureValidCode(code); + File metaFile = getMetaFile(code); + boolean success = true; + try { + Repository repository=RepositoryRegistry.getInstance().getRepository(blob.getRepository()); + success = repository.delete(blob) && success; + } catch (Exception e) { + logger.warn("Cound not delete file from repository ", e); + success = false; + } + try { + success = metaFile.delete() && success; + } catch (Exception e) { + logger.warn("Cound not delete meta file", e); + success = false; + } + return success; + }else { + return super.delete(blob); + } + } } diff --git a/elements/src/main/java/com/manydesigns/elements/blobs/Repository.java b/elements/src/main/java/com/manydesigns/elements/blobs/Repository.java new file mode 100644 index 0000000000..af9a265335 --- /dev/null +++ b/elements/src/main/java/com/manydesigns/elements/blobs/Repository.java @@ -0,0 +1,14 @@ +package com.manydesigns.elements.blobs; + +import java.io.IOException; +import java.io.InputStream; + +public interface Repository { + public static final String copyright = "Copyright (C) 2005-2018 ManyDesigns srl"; + + public String save(Blob blob) throws IOException; + public InputStream load(Blob blob) throws IOException; + public Boolean delete(Blob blob) throws IOException; + + public String getId(); +} diff --git a/elements/src/main/java/com/manydesigns/elements/blobs/RepositoryRegistry.java b/elements/src/main/java/com/manydesigns/elements/blobs/RepositoryRegistry.java new file mode 100644 index 0000000000..1756905efd --- /dev/null +++ b/elements/src/main/java/com/manydesigns/elements/blobs/RepositoryRegistry.java @@ -0,0 +1,49 @@ +package com.manydesigns.elements.blobs; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.HashMap; +import java.util.Map; + +public class RepositoryRegistry { + + public static final String copyright = "Copyright (C) 2005-2018 ManyDesigns srl"; + public static final Logger logger = LoggerFactory.getLogger(RepositoryRegistry.class); + + private static RepositoryRegistry instance = null; // lazy loading + private Map registry = null; + + private RepositoryRegistry() { + synchronized(RepositoryRegistry.class) { + registry = new HashMap(); + } + } + + public static RepositoryRegistry getInstance() { + if(instance == null) { + synchronized(RepositoryRegistry.class) { + if(instance == null) { + instance = new RepositoryRegistry(); + } + } + } + return instance; + } + + public Repository getRepository(String key){ + return registry.get(key); + } + + public void put(Repository repository){ + logger.info("Putting "+repository.getId()+" into RepositoryRegistry"); + registry.put(repository.getId(),repository); + } + +} + + + + + + + diff --git a/elements/src/main/java/com/manydesigns/elements/blobs/SimpleBlobManager.java b/elements/src/main/java/com/manydesigns/elements/blobs/SimpleBlobManager.java index c686b89b4f..72f9219fe9 100644 --- a/elements/src/main/java/com/manydesigns/elements/blobs/SimpleBlobManager.java +++ b/elements/src/main/java/com/manydesigns/elements/blobs/SimpleBlobManager.java @@ -122,8 +122,16 @@ public void save(Blob blob) throws IOException { dataFile.getParentFile().mkdirs(); } FileOutputStream out = new FileOutputStream(dataFile); + InputStream encryptInputStream; try { - blob.setSize(IOUtils.copyLarge(blob.getInputStream(), out)); + InputStream inputStream = blob.getInputStream(); + if(blob.isEncrypted()){ + encryptInputStream = BlobUtils.encrypt(inputStream,blob.getEncryptionType()); + IOUtils.copyLarge(encryptInputStream, out); + //blob.setSize(BlobUtils.calculatePaddingSize(blob)); + }else{ + blob.setSize(IOUtils.copyLarge(inputStream, out)); + } } finally { IOUtils.closeQuietly(out); } diff --git a/elements/src/main/java/com/manydesigns/elements/fields/AbstractBlobField.java b/elements/src/main/java/com/manydesigns/elements/fields/AbstractBlobField.java index 2a8b4b1b6b..ec5790ade4 100644 --- a/elements/src/main/java/com/manydesigns/elements/fields/AbstractBlobField.java +++ b/elements/src/main/java/com/manydesigns/elements/fields/AbstractBlobField.java @@ -23,6 +23,7 @@ import com.manydesigns.elements.ElementsThreadLocals; import com.manydesigns.elements.KeyValueAccessor; import com.manydesigns.elements.Mode; +import com.manydesigns.elements.annotations.Encrypted; import com.manydesigns.elements.annotations.MaxLength; import com.manydesigns.elements.blobs.Blob; import com.manydesigns.elements.blobs.BlobManager; @@ -66,6 +67,7 @@ public abstract class AbstractBlobField extends AbstractField implements M protected Blob blob; protected String blobError; + protected String encryptionType; //************************************************************************** // Costruttori @@ -88,6 +90,11 @@ public AbstractBlobField(@NotNull PropertyAccessor accessor, } else { size = 25; } + + + if (accessor.isAnnotationPresent(Encrypted.class)) { + encryptionType = accessor.getAnnotation(Encrypted.class).value(); + } } //************************************************************************** @@ -303,6 +310,8 @@ public void dispose() { blob.setContentType(fileBean.getContentType()); blob.setCreateTimestamp(new DateTime()); blob.setPropertiesLoaded(true); + blob.setEncryptionType(encryptionType); + blob.setSize(fileBean.getSize()); } public abstract String generateNewCode(); diff --git a/elements/src/main/java/com/manydesigns/elements/fields/AbstractDateField.java b/elements/src/main/java/com/manydesigns/elements/fields/AbstractDateField.java index 87324d0649..dc31dd25c0 100644 --- a/elements/src/main/java/com/manydesigns/elements/fields/AbstractDateField.java +++ b/elements/src/main/java/com/manydesigns/elements/fields/AbstractDateField.java @@ -199,7 +199,7 @@ public void setStringValue(String stringValue) { try { DateTime dateTime = Util.parseDateTime(dateTimeFormatter, stringValue, containsTime); dateValue = toDate(dateTime); - } catch (Throwable e) { + } catch (Exception e) { dateFormatError = true; logger.debug("Cannot parse date: {}", stringValue); } diff --git a/elements/src/main/java/com/manydesigns/elements/fields/EncryptedField.java b/elements/src/main/java/com/manydesigns/elements/fields/EncryptedField.java new file mode 100644 index 0000000000..a50984d3be --- /dev/null +++ b/elements/src/main/java/com/manydesigns/elements/fields/EncryptedField.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2005-2017 ManyDesigns srl. All rights reserved. + * http://www.manydesigns.com/ + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package com.manydesigns.elements.fields; + +import com.manydesigns.elements.FieldEncrypter; +import com.manydesigns.elements.Mode; +import com.manydesigns.elements.reflection.PropertyAccessor; +import com.manydesigns.elements.xml.XhtmlBuffer; + +/* +* @author Paolo Predonzani - paolo.predonzani@manydesigns.com +* @author Angelo Lupo - angelo.lupo@manydesigns.com +* @author Giampiero Granatella - giampiero.granatella@manydesigns.com +* @author Alessio Stalla - alessio.stalla@manydesigns.com +*/ +public class EncryptedField extends TextField { + public static final String copyright = + "Copyright (C) 2005-2017 ManyDesigns srl"; + + private FieldEncrypter encrypter; + + //************************************************************************** + // Constructors + //************************************************************************** + + public EncryptedField(PropertyAccessor accessor, Mode mode, String prefix , String classPath) { + super(accessor, mode, prefix); + try { + Class clazz = Class.forName(classPath); + encrypter = (FieldEncrypter)clazz.newInstance(); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { + logger.error(e.getMessage(),e); + } + } + + @Override + public void readFromObject(Object obj) { + super.readFromObject(obj); + if (obj == null) { + stringValue = null; + } else { + stringValue = encrypter.decrypt( (String)accessor.get(obj) ); + } + } + + @Override + public void writeToObject(Object obj) { + writeToObject(obj, encrypter.encrypt(stringValue)); + } +} diff --git a/elements/src/main/java/com/manydesigns/elements/fields/FileBlobField.java b/elements/src/main/java/com/manydesigns/elements/fields/FileBlobField.java index ffc577928e..79c8480d32 100644 --- a/elements/src/main/java/com/manydesigns/elements/fields/FileBlobField.java +++ b/elements/src/main/java/com/manydesigns/elements/fields/FileBlobField.java @@ -51,12 +51,21 @@ public String call() { }; protected Callable blobCodeGenerator = DEFAULT_CODE_GENERATOR; + protected String encryptionType=null; + public FileBlobField(@NotNull PropertyAccessor accessor, @NotNull Mode mode, @Nullable String prefix) { super(accessor, mode, prefix); } + public FileBlobField(@NotNull PropertyAccessor accessor, + @NotNull Mode mode, + @Nullable String prefix,@Nullable String encryptionType) { + super(accessor, mode, prefix); + this.encryptionType=encryptionType; + } + @Override public boolean isSaveBlobOnObject() { return false; @@ -72,6 +81,7 @@ public void readFromObject(Object obj) { forgetBlob(); } else { blob = new Blob(code); + blob.setEncryptionType(encryptionType); } } } @@ -99,4 +109,12 @@ public Callable getBlobCodeGenerator() { public void setBlobCodeGenerator(Callable blobCodeGenerator) { this.blobCodeGenerator = blobCodeGenerator; } + + public String getEncryptionType() { + return encryptionType; + } + + public void setEncryptionType(String encryptionType) { + this.encryptionType = encryptionType; + } } diff --git a/elements/src/main/java/com/manydesigns/elements/fields/NumericField.java b/elements/src/main/java/com/manydesigns/elements/fields/NumericField.java index 7df97c6c34..f3f8a8e0dc 100644 --- a/elements/src/main/java/com/manydesigns/elements/fields/NumericField.java +++ b/elements/src/main/java/com/manydesigns/elements/fields/NumericField.java @@ -97,7 +97,7 @@ public NumericField(PropertyAccessor accessor, Mode mode, String prefix) { if (accessor.isAnnotationPresent(MinDecimalValue.class)) { double minDecimalValue = accessor.getAnnotation(MinDecimalValue.class).value(); - minValue = new BigDecimal(minDecimalValue); + minValue = BigDecimal.valueOf(minDecimalValue); } else if (accessor.isAnnotationPresent(MinIntValue.class)) { int minIntValue = accessor.getAnnotation(MinIntValue.class).value(); @@ -108,7 +108,7 @@ public NumericField(PropertyAccessor accessor, Mode mode, String prefix) { if (accessor.isAnnotationPresent(MaxDecimalValue.class)) { double maxDecimalValue = accessor.getAnnotation(MaxDecimalValue.class).value(); - maxValue = new BigDecimal(maxDecimalValue); + maxValue = BigDecimal.valueOf(maxDecimalValue); } else if (accessor.isAnnotationPresent(MaxIntValue.class)) { int maxIntValue = accessor.getAnnotation(MaxIntValue.class).value(); @@ -243,7 +243,7 @@ public void setStringValue(String stringValue) { return; } decimalValue = tmpValue.setScale(scale, BigDecimal.ROUND_HALF_EVEN); - } catch (Throwable e) { + }catch (Exception e) { logger.debug("Decimal parse error", e); } } diff --git a/elements/src/main/java/com/manydesigns/elements/fields/helpers/EncryptedFieldHelper.java b/elements/src/main/java/com/manydesigns/elements/fields/helpers/EncryptedFieldHelper.java new file mode 100644 index 0000000000..d4fbc5f411 --- /dev/null +++ b/elements/src/main/java/com/manydesigns/elements/fields/helpers/EncryptedFieldHelper.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2005-2017 ManyDesigns srl. All rights reserved. + * http://www.manydesigns.com/ + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package com.manydesigns.elements.fields.helpers; + +import com.manydesigns.elements.Mode; +import com.manydesigns.elements.annotations.Encrypted; +import com.manydesigns.elements.fields.Field; +import com.manydesigns.elements.fields.EncryptedField; +import com.manydesigns.elements.fields.search.EncryptedTextSearchField; +import com.manydesigns.elements.fields.search.SearchField; +import com.manydesigns.elements.fields.search.TextMatchMode; +import com.manydesigns.elements.fields.search.TextSearchField; +import com.manydesigns.elements.reflection.ClassAccessor; +import com.manydesigns.elements.reflection.PropertyAccessor; + +/* + * @author Emanuele Poggi - emanuele.poggi@manydesigns.com + */ +public class EncryptedFieldHelper implements FieldHelper { + public static final String copyright = + "Copyright (C) 2005-2017 ManyDesigns srl"; + + public Field tryToInstantiateField(ClassAccessor classAccessor, + PropertyAccessor propertyAccessor, + Mode mode, + String prefix) { + + Encrypted encrypted = propertyAccessor.getAnnotation(Encrypted.class); + if (encrypted != null && + String.class.isAssignableFrom(propertyAccessor.getType())) { + EncryptedField field = new EncryptedField(propertyAccessor, mode, prefix, encrypted.value()); + return field; + } + + return null; + } + + public SearchField tryToInstantiateSearchField(ClassAccessor classAccessor, + PropertyAccessor propertyAccessor, + String prefix) { + Encrypted encrypted = propertyAccessor.getAnnotation(Encrypted.class); + if (encrypted != null && String.class.isAssignableFrom(propertyAccessor.getType())) { + EncryptedTextSearchField textSearchField = + new EncryptedTextSearchField(propertyAccessor, prefix,encrypted.value()); + textSearchField.setShowMatchMode(false); + textSearchField.setMatchMode(TextMatchMode.EQUALS); + return textSearchField; + } + return null; + } +} diff --git a/elements/src/main/java/com/manydesigns/elements/fields/helpers/FileBlobFieldHelper.java b/elements/src/main/java/com/manydesigns/elements/fields/helpers/FileBlobFieldHelper.java index 02526378f0..2e2e0591d4 100644 --- a/elements/src/main/java/com/manydesigns/elements/fields/helpers/FileBlobFieldHelper.java +++ b/elements/src/main/java/com/manydesigns/elements/fields/helpers/FileBlobFieldHelper.java @@ -20,7 +20,9 @@ package com.manydesigns.elements.fields.helpers; +import com.manydesigns.crypto.CryptoService; import com.manydesigns.elements.Mode; +import com.manydesigns.elements.annotations.Encrypted; import com.manydesigns.elements.annotations.FileBlob; import com.manydesigns.elements.fields.Field; import com.manydesigns.elements.fields.FileBlobField; @@ -44,6 +46,8 @@ public Field tryToInstantiateField(ClassAccessor classAccessor, String prefix) { if (String.class.isAssignableFrom(propertyAccessor.getType()) && propertyAccessor.isAnnotationPresent(FileBlob.class)) { + if(propertyAccessor.isAnnotationPresent(Encrypted.class)) + return new FileBlobField(propertyAccessor, mode, prefix, CryptoService.getInstance().getTypeAlgo()); return new FileBlobField(propertyAccessor, mode, prefix); } return null; diff --git a/elements/src/main/java/com/manydesigns/elements/fields/search/Criteria.java b/elements/src/main/java/com/manydesigns/elements/fields/search/Criteria.java index b877f8dda3..f6053c79cc 100644 --- a/elements/src/main/java/com/manydesigns/elements/fields/search/Criteria.java +++ b/elements/src/main/java/com/manydesigns/elements/fields/search/Criteria.java @@ -22,6 +22,8 @@ import com.manydesigns.elements.reflection.PropertyAccessor; +import java.io.Serializable; + /* * @author Paolo Predonzani - paolo.predonzani@manydesigns.com * @author Angelo Lupo - angelo.lupo@manydesigns.com @@ -59,7 +61,7 @@ Criteria ilike(PropertyAccessor accessor, String value, OrderBy getOrderBy(); - static class OrderBy { + static class OrderBy implements Serializable { protected final PropertyAccessor propertyAccessor; protected final String direction; diff --git a/elements/src/main/java/com/manydesigns/elements/fields/search/EncryptedTextSearchField.java b/elements/src/main/java/com/manydesigns/elements/fields/search/EncryptedTextSearchField.java new file mode 100644 index 0000000000..e7d7c8c7fb --- /dev/null +++ b/elements/src/main/java/com/manydesigns/elements/fields/search/EncryptedTextSearchField.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2005-2017 ManyDesigns srl. All rights reserved. + * http://www.manydesigns.com/ + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package com.manydesigns.elements.fields.search; + +import com.manydesigns.elements.FieldEncrypter; +import com.manydesigns.elements.annotations.MaxLength; +import com.manydesigns.elements.reflection.PropertyAccessor; +import com.manydesigns.elements.xml.XhtmlBuffer; +import org.apache.commons.lang.StringUtils; +import org.jetbrains.annotations.NotNull; + +import javax.servlet.http.HttpServletRequest; + +/* +* @author Paolo Predonzani - paolo.predonzani@manydesigns.com +* @author Angelo Lupo - angelo.lupo@manydesigns.com +* @author Giampiero Granatella - giampiero.granatella@manydesigns.com +* @author Alessio Stalla - alessio.stalla@manydesigns.com +*/ +public class EncryptedTextSearchField extends TextSearchField { + public static final String copyright = + "Copyright (C) 2005-2017 ManyDesigns srl"; + + private FieldEncrypter encrypter; + + //************************************************************************** + // Costruttori + //************************************************************************** + + public EncryptedTextSearchField(PropertyAccessor accessor) { + this(accessor, null,null); + }//TODO default encrypter + + public EncryptedTextSearchField(PropertyAccessor accessor, String prefix, String classPath) { + super(accessor, prefix); + + try { + Class clazz = Class.forName(classPath); + encrypter = (FieldEncrypter)clazz.newInstance(); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { + logger.error(e.getMessage(),e); + } + } + + //************************************************************************** + // Element implementation + //************************************************************************** + + @Override + public void readFromRequest(HttpServletRequest req) { + value = encrypter.encrypt(StringUtils.trimToNull(req.getParameter(inputName))); + } + +} diff --git a/elements/src/main/java/com/manydesigns/elements/fields/search/RangeSearchField.java b/elements/src/main/java/com/manydesigns/elements/fields/search/RangeSearchField.java index 197005974d..bc2069df11 100644 --- a/elements/src/main/java/com/manydesigns/elements/fields/search/RangeSearchField.java +++ b/elements/src/main/java/com/manydesigns/elements/fields/search/RangeSearchField.java @@ -135,7 +135,7 @@ public void readFromRequest(HttpServletRequest req) { protected Object readValue(String parameter, Class type) { try { return OgnlUtils.convertValue(parameter, type); - } catch (Throwable e) { + } catch (Exception e) { return null; } } diff --git a/elements/src/main/java/com/manydesigns/elements/i18n/SimpleTextProvider.java b/elements/src/main/java/com/manydesigns/elements/i18n/SimpleTextProvider.java index b0a2318a56..d901a147ed 100644 --- a/elements/src/main/java/com/manydesigns/elements/i18n/SimpleTextProvider.java +++ b/elements/src/main/java/com/manydesigns/elements/i18n/SimpleTextProvider.java @@ -76,7 +76,8 @@ private SimpleTextProvider(Locale locale, String messageResource) { else { tmpBundle = ResourceBundle.getBundle(messageResource, locale); } - } catch (Throwable e) { + } catch (Exception e) { + logger.warn("Couldn't load bundle: "+e.getMessage()); tmpBundle = null; } resourceBundle = tmpBundle; @@ -107,7 +108,7 @@ public String getLocalizedString(String key) { } else { return resourceBundle.getString(key); } - } catch (Throwable e) { + } catch (Exception e) { logger.debug("Key not found: " + key, e); return null; } diff --git a/elements/src/main/java/com/manydesigns/elements/util/ElementsFileUtils.java b/elements/src/main/java/com/manydesigns/elements/util/ElementsFileUtils.java index 2088721589..c5b1e34e9f 100644 --- a/elements/src/main/java/com/manydesigns/elements/util/ElementsFileUtils.java +++ b/elements/src/main/java/com/manydesigns/elements/util/ElementsFileUtils.java @@ -133,6 +133,7 @@ public static boolean chmod(File file, String perms) { int result = process.waitFor(); return result == 0; } catch (Exception e) { + logger.warn("Couldn't chmod "+file.getAbsolutePath()+" "+e.getMessage()); return false; } } diff --git a/elements/src/main/java/com/manydesigns/elements/xls/FormXlsExporter.java b/elements/src/main/java/com/manydesigns/elements/xls/FormXlsExporter.java index 4ab7ab522c..d4c5eb8acb 100644 --- a/elements/src/main/java/com/manydesigns/elements/xls/FormXlsExporter.java +++ b/elements/src/main/java/com/manydesigns/elements/xls/FormXlsExporter.java @@ -67,11 +67,12 @@ public void export(OutputStream outputStream) addHeaderToSheet(sheet); + XlsUtil xlsUtil = new XlsUtil(); int i = 1; for (FieldSet fieldset : form) { int j = 0; for (Field field : fieldset.fields()) { - XlsUtil.addFieldToCell(sheet, i, j, field); + xlsUtil.addFieldToCell(sheet, i, j, field); j++; } i++; diff --git a/elements/src/main/java/com/manydesigns/elements/xls/TableFormXlsExporter.java b/elements/src/main/java/com/manydesigns/elements/xls/TableFormXlsExporter.java index 7f0ebdb183..4c28a1ecbb 100644 --- a/elements/src/main/java/com/manydesigns/elements/xls/TableFormXlsExporter.java +++ b/elements/src/main/java/com/manydesigns/elements/xls/TableFormXlsExporter.java @@ -70,8 +70,9 @@ public void export(OutputStream outputStream) throws IOException, WriteException addHeaderToSheet(sheet); int i = 1; + XlsUtil xlsUtil = new XlsUtil(); for (TableForm.Row row : form.getRows()) { - exportRows(sheet, i, row); + exportRows(sheet, i, row,xlsUtil); i++; } @@ -92,10 +93,11 @@ private void addHeaderToSheet(WritableSheet sheet) throws WriteException { } } - private void exportRows(WritableSheet sheet, int i,TableForm.Row row) throws WriteException { + private void exportRows(WritableSheet sheet, int i,TableForm.Row row,XlsUtil xlsUtil) throws WriteException { int j = 0; + for (Field field : row) { - XlsUtil.addFieldToCell(sheet, i, j, field); + xlsUtil.addFieldToCell(sheet, i, j, field); j++; } } diff --git a/elements/src/main/java/com/manydesigns/elements/xls/XlsUtil.java b/elements/src/main/java/com/manydesigns/elements/xls/XlsUtil.java index 4b7ba396a1..38d9835857 100644 --- a/elements/src/main/java/com/manydesigns/elements/xls/XlsUtil.java +++ b/elements/src/main/java/com/manydesigns/elements/xls/XlsUtil.java @@ -1,31 +1,31 @@ /* -* Copyright (C) 2005-2017 ManyDesigns srl. All rights reserved. -* http://www.manydesigns.com/ -* -* Unless you have purchased a commercial license agreement from ManyDesigns srl, -* the following license terms apply: -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 3 as published by -* the Free Software Foundation. -* -* There are special exceptions to the terms and conditions of the GPL -* as it is applied to this software. View the full text of the -* exception in file OPEN-SOURCE-LICENSE.txt in the directory of this -* software distribution. -* -* This program is distributed WITHOUT ANY WARRANTY; and without the -* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -* See the GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, see http://www.gnu.org/licenses/gpl.txt -* or write to: -* Free Software Foundation, Inc., -* 59 Temple Place - Suite 330, -* Boston, MA 02111-1307 USA -* -*/ + * Copyright (C) 2005-2017 ManyDesigns srl. All rights reserved. + * http://www.manydesigns.com/ + * + * Unless you have purchased a commercial license agreement from ManyDesigns srl, + * the following license terms apply: + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the + * exception in file OPEN-SOURCE-LICENSE.txt in the directory of this + * software distribution. + * + * This program is distributed WITHOUT ANY WARRANTY; and without the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see http://www.gnu.org/licenses/gpl.txt + * or write to: + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, + * Boston, MA 02111-1307 USA + * + */ package com.manydesigns.elements.xls; @@ -39,6 +39,7 @@ import java.math.BigDecimal; import java.util.Date; +import java.util.HashMap; /** * @author Paolo Predonzani - paolo.predonzani@manydesigns.com @@ -48,61 +49,70 @@ * @author Emanuele Poggi - emanuele.poggi@manydesigns.com */ public class XlsUtil { - public static final String copyright = - "Copyright (C) 2005-2017 ManyDesigns srl"; + public static final String copyright = + "Copyright (C) 2005-2017 ManyDesigns srl"; + + //Map for formatters, only 350 availables in jxl + private HashMap formatMap = new HashMap(); - public static void addFieldToCell(WritableSheet sheet, int i, int j, Field field) throws WriteException { - if (field instanceof NumericField) { - NumericField numField = (NumericField) field; - if (numField.getValue() != null) { - jxl.write.Number number; - BigDecimal decimalValue = numField.getValue(); - if (numField.getDecimalFormat() == null) { - number = new Number(j, i, - decimalValue == null - ? null : decimalValue.doubleValue()); - } else { - NumberFormat numberFormat = new NumberFormat( - numField.getDecimalFormat().toPattern()); - WritableCellFormat writeCellNumberFormat = - new WritableCellFormat(numberFormat); - number = new Number(j, i, - decimalValue == null - ? null : decimalValue.doubleValue(), - writeCellNumberFormat); - } - sheet.addCell(number); - } - } else if (field instanceof PasswordField) { - Label label = new Label(j, i, - PasswordField.PASSWORD_PLACEHOLDER); - sheet.addCell(label); - } else if (field instanceof DateField) { - DateField dateField = (DateField) field; - DateTime dateCell; - Date date = dateField.getValue(); - if (date != null) { - DateFormat dateFormat = new DateFormat( - dateField.getDatePattern()); - WritableCellFormat wDateFormat = - new WritableCellFormat(dateFormat); - dateCell = new DateTime(j, i, - dateField.getValue() == null - ? null : dateField.getValue(), - wDateFormat); - sheet.addCell(dateCell); - } + public void addFieldToCell(WritableSheet sheet, int i, int j, Field field) throws WriteException { + if (field instanceof NumericField) { + NumericField numField = (NumericField) field; + if (numField.getValue() != null) { + jxl.write.Number number; + BigDecimal decimalValue = numField.getValue(); + if (numField.getDecimalFormat() == null) { + number = new Number(j, i, decimalValue == null ? null : decimalValue.doubleValue()); } else { - Label label = new Label(j, i, field.getStringValue()); - sheet.addCell(label); + number = new Number(j, i, decimalValue == null ? null : decimalValue.doubleValue(), + getNumberFormat(numField.getDecimalFormat().toPattern())); } + sheet.addCell(number); + } + } else if (field instanceof PasswordField) { + Label label = new Label(j, i, PasswordField.PASSWORD_PLACEHOLDER); + sheet.addCell(label); + } else if (field instanceof DateField) { + DateField dateField = (DateField) field; + DateTime dateCell; + Date date = dateField.getValue(); + if (date != null) { + dateCell = new DateTime(j, i, date, getDateFormat(dateField.getDatePattern())); + sheet.addCell(dateCell); + } + } else { + Label label = new Label(j, i, field.getStringValue()); + sheet.addCell(label); } + } - public static void autoSizeColumns(WritableSheet sheet, int columns){ - for(int c=0;ccom.manydesigns portofino pom - 4.2.4-SNAPSHOT + 4.2.4 manydesigns-portofino Portofino is a web application framework written in Java and @@ -77,12 +77,12 @@ 1.10 1.3 1.4 - 1.3.2 + 1.3.3 2.0.1 2.5 2.10.2.2.21 2.1 - 2.4.7 + 2.4.15 18.0 4.3.11.Final 3.18.1-GA @@ -97,7 +97,7 @@ 1.9.2 1.2 2.6.12 - 3.5.3 + 3.6.1 1.1.7 3.2 2.2.1 @@ -114,6 +114,7 @@ elements portofino-base + portofino-cryptography portofino-stripes portofino-jersey portofino-resteasy diff --git a/portofino-admin/pom.xml b/portofino-admin/pom.xml index 71d6c50576..d7b21bbc10 100644 --- a/portofino-admin/pom.xml +++ b/portofino-admin/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-admin jar diff --git a/portofino-admin/src/main/java/com/manydesigns/portofino/actions/admin/appwizard/ApplicationWizard.java b/portofino-admin/src/main/java/com/manydesigns/portofino/actions/admin/appwizard/ApplicationWizard.java index 781f2b1314..4320c868c1 100644 --- a/portofino-admin/src/main/java/com/manydesigns/portofino/actions/admin/appwizard/ApplicationWizard.java +++ b/portofino-admin/src/main/java/com/manydesigns/portofino/actions/admin/appwizard/ApplicationWizard.java @@ -361,11 +361,11 @@ protected void configureEditSchemas() throws Exception { selectableSchemas = new ArrayList(schemaNamesFromDb.size()); for(String[] schemaName : schemaNamesFromDb) { - SelectableSchema schema = new SelectableSchema(schemaName[0], schemaName[1], schemaNamesFromDb.size() == 1); + SelectableSchema schema = new SelectableSchema(schemaName[0], schemaName[1],schemaName[1], schemaNamesFromDb.size() == 1); selectableSchemas.add(schema); } schemasForm = new TableFormBuilder(SelectableSchema.class) - .configFields("selected", "schemaName") + .configFields("selected", "schema","schemaName") .configMode(Mode.EDIT) .configNRows(selectableSchemas.size()) .configPrefix("schemas_") @@ -429,12 +429,13 @@ protected Database configureModelSchemas(boolean alwaysUseExistingModel) { List tempSchemas = new ArrayList(); Database database = connectionProvider.getDatabase(); for(SelectableSchema schema : selectableSchemas) { - Schema modelSchema = DatabaseLogic.findSchemaByName(database, schema.schemaName); + Schema modelSchema = DatabaseLogic.findSchemaByName(database, schema.schema); if(schema.selected) { if(modelSchema == null) { modelSchema = new Schema(); modelSchema.setCatalog(schema.catalogName); modelSchema.setSchemaName(schema.schemaName); + modelSchema.setSchema(schema.schema); modelSchema.setDatabase(database); database.getSchemas().add(modelSchema); tempSchemas.add(modelSchema); @@ -758,7 +759,7 @@ protected List determineRoots(Multimap children, List roots = new ArrayList
(); for(SelectableSchema selectableSchema : selectableSchemas) { if(selectableSchema.selected) { - Schema schema = DatabaseLogic.findSchemaByName(database, selectableSchema.schemaName); + Schema schema = DatabaseLogic.findSchemaByName(database, selectableSchema.schema); roots.addAll(schema.getTables()); } } diff --git a/portofino-admin/src/main/java/com/manydesigns/portofino/actions/admin/database/ConnectionProvidersAction.java b/portofino-admin/src/main/java/com/manydesigns/portofino/actions/admin/database/ConnectionProvidersAction.java index e5dd0324c3..1facae6e41 100644 --- a/portofino-admin/src/main/java/com/manydesigns/portofino/actions/admin/database/ConnectionProvidersAction.java +++ b/portofino-admin/src/main/java/com/manydesigns/portofino/actions/admin/database/ConnectionProvidersAction.java @@ -241,17 +241,17 @@ protected void configureEditSchemas() { for(String[] schemaName : schemaNamesFromDb) { boolean selected = false; for(Schema schema : selectedSchemas) { - if(schemaName[1].equalsIgnoreCase(schema.getSchemaName())) { + if(schemaName[1].equalsIgnoreCase(schema.getSchema())) { selected = true; break; } } - SelectableSchema schema = new SelectableSchema(schemaName[0], schemaName[1], selected); + SelectableSchema schema = new SelectableSchema(schemaName[0], schemaName[1],schemaName[1], selected); selectableSchemas.add(schema); } schemasForm = new TableFormBuilder(SelectableSchema.class) .configFields( - "selected", "schemaName" + "selected", "schema","schemaName" ) .configMode(Mode.EDIT) .configNRows(selectableSchemas.size()) @@ -322,19 +322,20 @@ public Resolution update() { List selectedSchemas = database.getSchemas(); List selectedSchemaNames = new ArrayList(selectedSchemas.size()); for(Schema schema : selectedSchemas) { - selectedSchemaNames.add(schema.getSchemaName().toLowerCase()); + selectedSchemaNames.add(schema.getSchema().toLowerCase()); } for(SelectableSchema schema : selectableSchemas) { - if(schema.selected && !selectedSchemaNames.contains(schema.schemaName.toLowerCase())) { + if(schema.selected && !selectedSchemaNames.contains(schema.schema.toLowerCase())) { Schema modelSchema = new Schema(); modelSchema.setCatalog(schema.catalogName); modelSchema.setSchemaName(schema.schemaName); + modelSchema.setSchema(schema.schema); modelSchema.setDatabase(database); database.getSchemas().add(modelSchema); - } else if(!schema.selected && selectedSchemaNames.contains(schema.schemaName.toLowerCase())) { + } else if(!schema.selected && selectedSchemaNames.contains(schema.schema.toLowerCase())) { Schema toBeRemoved = null; for(Schema aSchema : database.getSchemas()) { - if(aSchema.getSchemaName().equalsIgnoreCase(schema.schemaName)) { + if(aSchema.getSchema().equalsIgnoreCase(schema.schema)) { toBeRemoved = aSchema; break; } diff --git a/portofino-admin/src/main/java/com/manydesigns/portofino/actions/admin/database/TablesAction.java b/portofino-admin/src/main/java/com/manydesigns/portofino/actions/admin/database/TablesAction.java index 41508e337c..8c67c0bbaa 100644 --- a/portofino-admin/src/main/java/com/manydesigns/portofino/actions/admin/database/TablesAction.java +++ b/portofino-admin/src/main/java/com/manydesigns/portofino/actions/admin/database/TablesAction.java @@ -73,11 +73,11 @@ import java.util.*; /* -* @author Paolo Predonzani - paolo.predonzani@manydesigns.com -* @author Angelo Lupo - angelo.lupo@manydesigns.com -* @author Giampiero Granatella - giampiero.granatella@manydesigns.com -* @author Alessio Stalla - alessio.stalla@manydesigns.com -*/ + * @author Paolo Predonzani - paolo.predonzani@manydesigns.com + * @author Angelo Lupo - angelo.lupo@manydesigns.com + * @author Giampiero Granatella - giampiero.granatella@manydesigns.com + * @author Alessio Stalla - alessio.stalla@manydesigns.com + */ @RequiresAuthentication @RequiresAdministrator @UrlBinding(TablesAction.BASE_ACTION_PATH + "/{databaseName}/{schemaName}/{tableName}/{columnName}") @@ -647,6 +647,7 @@ protected ColumnForm setupColumnForm() { stringFormatSP.appendRow(PartitaIva.class.getName(), "Partita IVA", true); stringFormatSP.appendRow(CodiceFiscale.class.getName(), "Codice Fiscale", true); stringFormatSP.appendRow(Phone.class.getName(), "Phone", true); + stringFormatSP.appendRow(Encrypted.class.getName(), "Encrypted", true); DefaultSelectionProvider typeOfContentSP = new DefaultSelectionProvider("typeOfContent"); typeOfContentSP.appendRow(Multiline.class.getName(), "Multiline", true); @@ -655,7 +656,7 @@ protected ColumnForm setupColumnForm() { columnForm = new FormBuilder(ColumnForm.class) .configFieldSetNames("Properties", "Annotations") .configFields(new String[] { "columnName", "propertyName", "javaType", "type", - "length", "scale", "reallyNullable", "reallyAutoincrement", "inPk" }, + "length", "scale", "reallyNullable", "reallyAutoincrement", "inPk" }, getApplicableAnnotations(column.getActualJavaType())) .configSelectionProvider(typesSP, "columnName", "type", "javaType") .configSelectionProvider(stringFormatSP, "stringFormat") diff --git a/portofino-admin/src/main/java/com/manydesigns/portofino/actions/admin/database/forms/SelectableSchema.java b/portofino-admin/src/main/java/com/manydesigns/portofino/actions/admin/database/forms/SelectableSchema.java index d8738db7b1..b16505c261 100644 --- a/portofino-admin/src/main/java/com/manydesigns/portofino/actions/admin/database/forms/SelectableSchema.java +++ b/portofino-admin/src/main/java/com/manydesigns/portofino/actions/admin/database/forms/SelectableSchema.java @@ -36,13 +36,16 @@ public class SelectableSchema { @Updatable(false) public final String catalogName; @Updatable(false) - public final String schemaName; + public final String schema; + @Updatable(true) + public String schemaName; @Label("") public boolean selected; - public SelectableSchema(String catalogName, String schemaName, boolean selected) { + public SelectableSchema(String catalogName, String schemaName, String schema,boolean selected) { this.catalogName = catalogName; this.schemaName = schemaName; + this.schema = schema; this.selected = selected; } } diff --git a/portofino-admin/src/main/java/com/manydesigns/portofino/actions/admin/tables/forms/ColumnForm.java b/portofino-admin/src/main/java/com/manydesigns/portofino/actions/admin/tables/forms/ColumnForm.java index cba5d14b30..787498037a 100644 --- a/portofino-admin/src/main/java/com/manydesigns/portofino/actions/admin/tables/forms/ColumnForm.java +++ b/portofino-admin/src/main/java/com/manydesigns/portofino/actions/admin/tables/forms/ColumnForm.java @@ -73,7 +73,7 @@ public class ColumnForm extends Column { HighlightLinks.class.getName(), RegExp.class.getName(), DatabaseBlob.class.getName(), FileBlob.class.getName(), MinDecimalValue.class.getName(), MinIntValue.class.getName(), MaxDecimalValue.class.getName(), - MaxIntValue.class.getName(), DecimalFormat.class.getName(), DateFormat.class.getName() + MaxIntValue.class.getName(), DecimalFormat.class.getName(), DateFormat.class.getName(),Encrypted.class.getName() }; public ColumnForm(Column copyFrom, PropertyAccessor columnAccessor, Type type) { @@ -122,6 +122,9 @@ public ColumnForm(Column copyFrom, PropertyAccessor columnAccessor, Type type) { if(columnAccessor.isAnnotationPresent(Phone.class)) { stringFormat = Phone.class.getName(); } + if(columnAccessor.isAnnotationPresent(Encrypted.class)) { + stringFormat = Encrypted.class.getName(); + } HighlightLinks hlAnn = columnAccessor.getAnnotation(HighlightLinks.class); if(hlAnn != null) { @@ -216,8 +219,8 @@ public void copyTo(Column column) { column.getAnnotations().add(ann); } if(!StringUtils.isEmpty(databaseBlobContentTypeProperty) || - !StringUtils.isEmpty(databaseBlobFileNameProperty) || - !StringUtils.isEmpty(databaseBlobTimestampProperty)) { + !StringUtils.isEmpty(databaseBlobFileNameProperty) || + !StringUtils.isEmpty(databaseBlobTimestampProperty)) { Annotation ann = new Annotation(column, DatabaseBlob.class.getName()); ann.getValues().add(databaseBlobContentTypeProperty); ann.getValues().add(databaseBlobFileNameProperty); @@ -300,8 +303,8 @@ public Integer getScale() { @Override @RegExp( - value = "(_|$|[a-z]|[A-Z]|[\u0080-\ufffe])(_|$|[a-z]|[A-Z]|[\u0080-\ufffe]|[0-9])*", - errorMessage = "invalid.property.name") + value = "(_|$|[a-z]|[A-Z]|[\u0080-\ufffe])(_|$|[a-z]|[A-Z]|[\u0080-\ufffe]|[0-9])*", + errorMessage = "invalid.property.name") public String getPropertyName() { return super.getPropertyName(); } diff --git a/portofino-admin/src/main/resources/META-INF/resources/m/admin/connectionProviders/read.jsp b/portofino-admin/src/main/resources/META-INF/resources/m/admin/connectionProviders/read.jsp index 5470977d1a..fe555b9fda 100644 --- a/portofino-admin/src/main/resources/META-INF/resources/m/admin/connectionProviders/read.jsp +++ b/portofino-admin/src/main/resources/META-INF/resources/m/admin/connectionProviders/read.jsp @@ -19,7 +19,7 @@

- , + () , diff --git a/portofino-admin/src/main/resources/META-INF/resources/m/admin/groovy.jsp b/portofino-admin/src/main/resources/META-INF/resources/m/admin/groovy.jsp index 0060f84a05..60c16163f9 100644 --- a/portofino-admin/src/main/resources/META-INF/resources/m/admin/groovy.jsp +++ b/portofino-admin/src/main/resources/META-INF/resources/m/admin/groovy.jsp @@ -19,9 +19,7 @@

-

-

diff --git a/portofino-atmosphere/pom.xml b/portofino-atmosphere/pom.xml index 11d8c45f8c..2eecca01b6 100644 --- a/portofino-atmosphere/pom.xml +++ b/portofino-atmosphere/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-atmosphere jar diff --git a/portofino-base/pom.xml b/portofino-base/pom.xml index 7f636babfa..e7cb3aaa0e 100644 --- a/portofino-base/pom.xml +++ b/portofino-base/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-base jar diff --git a/portofino-base/src/main/java/com/manydesigns/portofino/servlets/PortofinoListener.java b/portofino-base/src/main/java/com/manydesigns/portofino/servlets/PortofinoListener.java index 6802c1cafb..45cf8ad389 100644 --- a/portofino-base/src/main/java/com/manydesigns/portofino/servlets/PortofinoListener.java +++ b/portofino-base/src/main/java/com/manydesigns/portofino/servlets/PortofinoListener.java @@ -20,6 +20,7 @@ package com.manydesigns.portofino.servlets; +import com.manydesigns.crypto.KeyManager; import com.manydesigns.elements.ElementsProperties; import com.manydesigns.elements.ElementsThreadLocals; import com.manydesigns.elements.blobs.BlobManager; @@ -191,6 +192,14 @@ public boolean accept(File dir, String name) { logger.info("Blobs found directly under the blobs directory; using old style (pre-4.1.1) flat file blob manager"); defaultBlobManager = new SimpleBlobManager(appBlobsDir, metaFilenamePattern, dataFilenamePattern); } + + try { + logger.info("Initializing KeyManager "); + KeyManager.init(configuration); + } catch (Exception e) { + logger.error("Could not initialize KeyManager", e); + } + servletContext.setAttribute(BaseModule.TEMPORARY_BLOB_MANAGER, tempBlobManager); servletContext.setAttribute(BaseModule.DEFAULT_BLOB_MANAGER, defaultBlobManager); diff --git a/portofino-base/src/main/resources/portofino-messages_de.properties b/portofino-base/src/main/resources/portofino-messages_de.properties index 4703eb90d3..f77cfed925 100755 --- a/portofino-base/src/main/resources/portofino-messages_de.properties +++ b/portofino-base/src/main/resources/portofino-messages_de.properties @@ -2,7 +2,7 @@ log.out=Log Out ok = Ok login=Anmelden update=Speichern -object.updated.successfully = Objekt erfolgreich gespeichert. +object.updated.successfully = Objekt erfolgreich gespeichert update.failed = Speichern fehlgeschlagen cancel=Abbrechen create.new=Neu @@ -22,23 +22,23 @@ forgot.your.password=Passwort vergessen? sign.up = Registrieren please.type.the.text.shown.in.the.image = Bitte den Text aus dem Bild abtippen wrong.text = Der Text ist falsch -this.page.is.not.correctly.configured = Diese Seite ist falsch konfiguriert. +this.page.is.not.correctly.configured = Diese Seite ist falsch konfiguriert modules = Modules servlet.context = Servlet context #User management user._.logged.in.successfully = Benutzer {0} erfolgreich eingeloggt login.failed.for.user._ = Anmeldung f\u00FCr Benutzer {0} fehlgeschlagen -user._.is.not.active = Benutzer {0} ist inaktiv. Bitte verst\u00E4ndigen Sie den Administrator. -user.disconnected = Benutzer abgemeldet. -password.successfully.reset = Passwort wurde erfolgreich zur\u00FCckgesetzt. +user._.is.not.active = Benutzer {0} ist inaktiv. Bitte verst\u00E4ndigen Sie den Administrator +user.disconnected = Benutzer abgemeldet +password.successfully.reset = Passwort wurde erfolgreich zur\u00FCckgesetzt password.reset.failed = Passwortzur\u00FCcksetzen fehlgeschlagen the.password.reset.link.is.no.longer.active = Der Link zum Passwortzur\u00FCcksetzen ist nicht mehr g\u00FCltig. Bitte das \ Passwortzur\u00FCcksetzen erneut anfordern. check.your.mailbox.and.follow.the.instructions = Pr\u00FCfen Sie Ihre Mail und folgen Sie den Anweisungen user.created = Benutzer angelegt. signup.failed = Registrierung fehlgeschlagen. -a.user.with.the.same.username.already.exists = Ein Benutzer mit demselben Namen existiert bereits. +a.user.with.the.same.username.already.exists = Ein Benutzer mit demselben Namen existiert bereits please.correct.the.errors.before.proceeding = Bitte korrigieren Sie die Fehler bevor Sie weitermachen the.sign.up.confirmation.link.is.no.longer.active = Der Registrierungslink ist nicht mehr g\u00FCltig. Bitte registrieren Sie \ sich erneut. diff --git a/portofino-base/src/main/resources/portofino-messages_es.properties b/portofino-base/src/main/resources/portofino-messages_es.properties index d7fa497a8f..b3cec56dc6 100644 --- a/portofino-base/src/main/resources/portofino-messages_es.properties +++ b/portofino-base/src/main/resources/portofino-messages_es.properties @@ -36,7 +36,7 @@ check.your.mailbox.and.follow.the.instructions=Revisa tu correo electr\u00F3nico user.created=Usuario creado signup.failed=El alta ha fallado a.user.with.the.same.username.already.exists=Existe un usuario con el mismo nombre o correo electr\u00F3nico. -please.correct.the.errors.before.proceeding=Corrige los errores antes de continuar. +please.correct.the.errors.before.proceeding=Corrige los errores antes de continuar the.sign.up.confirmation.link.is.no.longer.active=El enlace de confirmaci\u00F3n de alta ya no es v\u00E1lido. confirm.signup=Confirma tu alta password.changed.successfully=Contrase\u00F1a modificada correctamente diff --git a/portofino-base/src/main/resources/portofino-messages_it.properties b/portofino-base/src/main/resources/portofino-messages_it.properties index dafbd9ad58..4843ab78ed 100644 --- a/portofino-base/src/main/resources/portofino-messages_it.properties +++ b/portofino-base/src/main/resources/portofino-messages_it.properties @@ -21,26 +21,26 @@ forgot.your.password=Hai dimenticato la password? sign.up = Iscriviti please.type.the.text.shown.in.the.image = Digita il testo mostrato nell'immagine wrong.text = Testo errato -this.page.is.not.correctly.configured = Questa pagina non \u00E8 configurata correttamente. +this.page.is.not.correctly.configured = Questa pagina non \u00E8 configurata correttamente modules = Moduli servlet.context = Servlet context #User management user._.logged.in.successfully=L''utente {0} ha effettuato il login con successo login.failed.for.user._ = Login fallito per l''utente {0} -user._.is.not.active = L''utente {0} non \u00E8 attivo. Contattare l''amministratore. -user.disconnected = Utente disconnesso. -password.successfully.reset = Password resettata correttamente. +user._.is.not.active = L''utente {0} non \u00E8 attivo. Contattare l''amministratore +user.disconnected = Utente disconnesso +password.successfully.reset = Password resettata correttamente password.reset.failed = Reset della password fallito the.password.reset.link.is.no.longer.active = Il link per il reset della password che hai seguito non \u00E8 pi\u00F9 valido. Per \ - favore, fai una nuova richiesta di reset della password. -check.your.mailbox.and.follow.the.instructions = Controlla la tua casella email e segui le istruzioni. -user.created = Utente creato. -signup.failed = Iscrizione fallita. -a.user.with.the.same.username.already.exists = Esiste gi\u00E0 un utente con lo stesso nome o la stessa email. -please.correct.the.errors.before.proceeding = Correggere gli errori per proseguire. + favore, fai una nuova richiesta di reset della password +check.your.mailbox.and.follow.the.instructions = Controlla la tua casella email e segui le istruzioni +user.created = Utente creato +signup.failed = Iscrizione fallita +a.user.with.the.same.username.already.exists = Esiste gi\u00E0 un utente con lo stesso nome o la stessa email +please.correct.the.errors.before.proceeding = Correggere gli errori per proseguire the.sign.up.confirmation.link.is.no.longer.active = Il link di iscrizione che hai seguito non \u00E8 pi\u00F9 valido. Per favore, fai una nuova \ - richiesta di iscrizione. + richiesta di iscrizione confirm.signup = Conferma iscrizione password.changed.successfully = Password modificata correttamente password.change.failed = Modifica della password fallita @@ -53,7 +53,7 @@ null.password = La password \u00E8 vuota password.too.short = La password \u00E8 troppo corta (dev''essere lunga almeno {0} caratteri) password.only.letters = La password contiene soltanto lettere password.spam.filter = Se non ricevi alcuna mail da noi nei prossimi minuti, controlla la tua cartella dello spam. Le nostre email sono inviate dal seguente indirizzo: {0} -password.resend = Inserisci il tuo indirizzo email qui sotto e ti invieremo le istruzioni per resettare la password. +password.resend = Inserisci il tuo indirizzo email qui sotto e ti invieremo le istruzioni per resettare la password #Default number format elements.fields.format.decimal=#.# diff --git a/portofino-calendar/pom.xml b/portofino-calendar/pom.xml index e34058c4c5..770a0a3513 100644 --- a/portofino-calendar/pom.xml +++ b/portofino-calendar/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-calendar jar diff --git a/portofino-chart/pom.xml b/portofino-chart/pom.xml index 3d36bfde9b..8b2ed1d237 100644 --- a/portofino-chart/pom.xml +++ b/portofino-chart/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-chart jar diff --git a/portofino-chart/src/main/java/com/manydesigns/portofino/pageactions/chart/jfreechart/JFreeChartAction.java b/portofino-chart/src/main/java/com/manydesigns/portofino/pageactions/chart/jfreechart/JFreeChartAction.java index 97ca8d4b45..797d2e4283 100644 --- a/portofino-chart/src/main/java/com/manydesigns/portofino/pageactions/chart/jfreechart/JFreeChartAction.java +++ b/portofino-chart/src/main/java/com/manydesigns/portofino/pageactions/chart/jfreechart/JFreeChartAction.java @@ -144,7 +144,7 @@ public Resolution execute() { jfreeChartInstance = new JFreeChartInstance(chart, file, chartId, "Chart: " + chartConfiguration.getName(), width, height, url); - } catch (Throwable e) { + } catch (Exception e) { logger.error("Chart exception", e); return forwardToPageActionError(e); } diff --git a/portofino-crud/pom.xml b/portofino-crud/pom.xml index 6ba135fe8f..38ef2de43a 100644 --- a/portofino-crud/pom.xml +++ b/portofino-crud/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-crud jar diff --git a/portofino-crud/src/main/java/com/manydesigns/portofino/pageactions/crud/AbstractCrudAction.java b/portofino-crud/src/main/java/com/manydesigns/portofino/pageactions/crud/AbstractCrudAction.java index 9184f36444..816e841265 100644 --- a/portofino-crud/src/main/java/com/manydesigns/portofino/pageactions/crud/AbstractCrudAction.java +++ b/portofino-crud/src/main/java/com/manydesigns/portofino/pageactions/crud/AbstractCrudAction.java @@ -301,8 +301,8 @@ protected void loadObject(String... identifier) { //************************************************************************** @Buttons({ - @Button(list = "crud-search-form", key = "search", order = 1, type = Button.TYPE_PRIMARY, icon = Button.ICON_SEARCH), - @Button(list = "crud-search-form-default-button", key = "search" ) + @Button(list = "crud-search-form", key = "search", order = 1, type = Button.TYPE_PRIMARY, icon = Button.ICON_SEARCH), + @Button(list = "crud-search-form-default-button", key = "search" ) }) public Resolution search() { //Not really used. Search is AJAX these days. @@ -325,8 +325,8 @@ protected Resolution doSearch() { return getEmbeddedSearchView(); } else { returnUrl = new UrlBuilder( - context.getLocale(), Util.getAbsoluteUrl(context.getActionPath()), false) - .toString(); + context.getLocale(), Util.getAbsoluteUrl(context.getActionPath()), false) + .toString(); returnUrl = appendSearchStringParamIfNecessary(returnUrl); return getSearchView(); } @@ -599,9 +599,9 @@ protected void preEdit() { } @Buttons({ - @Button(list = "crud-read", key = "edit", order = 1 , icon = Button.ICON_EDIT + Button.ICON_WHITE, - group = "crud", type = Button.TYPE_SUCCESS), - @Button(list = "crud-read-default-button", key = "search") + @Button(list = "crud-read", key = "edit", order = 1 , icon = Button.ICON_EDIT + Button.ICON_WHITE, + group = "crud", type = Button.TYPE_SUCCESS), + @Button(list = "crud-read-default-button", key = "search") }) @RequiresPermissions(permissions = PERMISSION_EDIT) @Guard(test = "isEditEnabled()", type = GuardType.VISIBLE) @@ -687,8 +687,8 @@ public boolean isBulkOperationsEnabled() { } @Buttons({ - @Button(list = "crud-search", key = "edit", order = 2, icon = Button.ICON_EDIT), - @Button(list = "crud-bulk", key = "edit", order = 2, icon = Button.ICON_EDIT) + @Button(list = "crud-search", key = "edit", order = 2, icon = Button.ICON_EDIT), + @Button(list = "crud-bulk", key = "edit", order = 2, icon = Button.ICON_EDIT) }) @Guard(test = "isBulkOperationsEnabled() && isEditEnabled()", type = GuardType.VISIBLE) @RequiresPermissions(permissions = PERMISSION_EDIT) @@ -778,8 +778,8 @@ public Resolution delete() { } @Buttons({ - @Button(list = "crud-search", key = "delete", order = 3, icon = Button.ICON_TRASH), - @Button(list = "crud-bulk", key = "delete", order = 3, icon = Button.ICON_TRASH) + @Button(list = "crud-search", key = "delete", order = 3, icon = Button.ICON_TRASH), + @Button(list = "crud-bulk", key = "delete", order = 3, icon = Button.ICON_TRASH) }) @Guard(test = "isBulkOperationsEnabled() && isDeleteEnabled()", type = GuardType.VISIBLE) @RequiresPermissions(permissions = PERMISSION_DELETE) @@ -822,7 +822,7 @@ public Resolution bulkDelete() { public boolean isCreateEnabled() { return true; } - + /** * Hook method called just after a new object has been created. * @param object the new object. @@ -855,7 +855,7 @@ protected void commitTransaction() {} public boolean isEditEnabled() { return true; } - + /** * Hook method called just before an object is used to populate the edit form. * @param object the object. @@ -882,7 +882,7 @@ protected void editPostProcess(T object) {} public boolean isDeleteEnabled() { return true; } - + /** * Hook method called before an object is deleted. * @param object the object. @@ -1281,7 +1281,7 @@ protected void configureDetailLink(TableFormBuilder tableFormBuilder) { boolean isShowingKey = false; for (PropertyAccessor property : classAccessor.getKeyProperties()) { if(tableFormBuilder.getPropertyAccessors().contains(property) && - tableFormBuilder.isPropertyVisible(property)) { + tableFormBuilder.isPropertyVisible(property)) { isShowingKey = true; break; } @@ -1298,9 +1298,9 @@ protected void configureDetailLink(TableFormBuilder tableFormBuilder) { logger.debug("TableForm: configuring detail link for the first visible property"); for (PropertyAccessor property : classAccessor.getProperties()) { if(tableFormBuilder.getPropertyAccessors().contains(property) && - tableFormBuilder.isPropertyVisible(property)) { + tableFormBuilder.isPropertyVisible(property)) { tableFormBuilder.configHrefTextFormat( - property.getName(), hrefFormat); + property.getName(), hrefFormat); break; } } @@ -1527,10 +1527,10 @@ public Resolution returnToSearch() throws Exception { @Override @Buttons({ - @Button(list = "crud-edit", key = "cancel", order = 99), - @Button(list = "crud-create", key = "cancel", order = 99), - @Button(list = "crud-bulk-edit", key = "cancel", order = 99), - @Button(list = "configuration", key = "cancel", order = 99) + @Button(list = "crud-edit", key = "cancel", order = 99), + @Button(list = "crud-create", key = "cancel", order = 99), + @Button(list = "crud-bulk-edit", key = "cancel", order = 99), + @Button(list = "configuration", key = "cancel", order = 99) }) public Resolution cancel() { if(isPopup()) { @@ -1577,8 +1577,8 @@ protected void refreshTableBlobDownloadHref() { Blob blob = ((AbstractBlobField) field).getValue(); if(blob != null) { UrlBuilder urlBuilder = new UrlBuilder(Locale.getDefault(), baseUrl, false) - .addParameter("downloadBlob", "") - .addParameter("propertyName", field.getPropertyAccessor().getName()); + .addParameter("downloadBlob", "") + .addParameter("propertyName", field.getPropertyAccessor().getName()); field.setHref(urlBuilder.toString()); } } @@ -1636,10 +1636,15 @@ public Resolution downloadBlob(@PathParam("propertyName") String propertyName) t } else { inputStream = blob.getInputStream(); } - return new StreamingResolution(contentType, inputStream) + StreamingResolution streamingResolution = new StreamingResolution(contentType, inputStream) .setFilename(fileName) - .setLength(contentLength) .setLastModified(lastModified); + + if( contentLength>0 ){ + streamingResolution.setLength(contentLength); + } + + return streamingResolution; } @PUT @@ -1806,7 +1811,7 @@ protected void prepareConfigurationForms() { if(propertyEdits != null) { TableFormBuilder tableFormBuilder = new TableFormBuilder(CrudPropertyEdit.class) - .configNRows(propertyEdits.length); + .configNRows(propertyEdits.length); propertiesTableForm = tableFormBuilder.build(); propertiesTableForm.setCondensed(true); } @@ -1955,7 +1960,7 @@ public Resolution updateConfiguration() { } if(selectionProviderSupport != null && - !selectionProviderSupport.getAvailableSelectionProviderNames().isEmpty()) { + !selectionProviderSupport.getAvailableSelectionProviderNames().isEmpty()) { updateSelectionProviders(); } @@ -2060,7 +2065,7 @@ public Resolution jsonOptions( ) { return jsonOptions(selectionProviderName, selectionProviderIndex, prefix, includeSelectPrompt); } - + /** * Returns values to update multiple related select fields or a single autocomplete * text field, in JSON form. Note that, for autocomplete fields, it expects the autocomplete value @@ -2110,7 +2115,7 @@ public Resolution jsonOptions( field.setUpdatable(true); } form.readFromRequest(context.getRequest()); - + //The form only contains fields from the selection provider, so the index matches that of the field if(selectionProviderIndex < 0 || selectionProviderIndex >= fieldSet.size()) { return new ErrorResolution(400, "Invalid index"); @@ -2270,7 +2275,7 @@ protected String getEncodedSearchStringParam() { encodedSearchString += encoded; } else { logger.warn("Could not encode search string \"" + StringEscapeUtils.escapeJava(searchString) + - "\" with encoding " + encoding); + "\" with encoding " + encoding); return null; } } catch (UnsupportedEncodingException e) { diff --git a/portofino-crud/src/main/resources/META-INF/resources/m/crud/search.jsp b/portofino-crud/src/main/resources/META-INF/resources/m/crud/search.jsp index 19ce41917c..8815aa099e 100644 --- a/portofino-crud/src/main/resources/META-INF/resources/m/crud/search.jsp +++ b/portofino-crud/src/main/resources/META-INF/resources/m/crud/search.jsp @@ -9,6 +9,7 @@ /> + ${actionBean.totalSearchRecords} "/>
+
\ No newline at end of file diff --git a/portofino-crud/src/main/resources/portofino-messages.properties b/portofino-crud/src/main/resources/portofino-messages.properties index 0629e01354..2b1a8e2c98 100644 --- a/portofino-crud/src/main/resources/portofino-messages.properties +++ b/portofino-crud/src/main/resources/portofino-messages.properties @@ -27,3 +27,4 @@ none.available = None available. return.to.search = Back to search show.search = Show search hide.search = Hide search +search.results=results diff --git a/portofino-crud/src/main/resources/portofino-messages_it.properties b/portofino-crud/src/main/resources/portofino-messages_it.properties index ea68161e3c..a8e863d59a 100644 --- a/portofino-crud/src/main/resources/portofino-messages_it.properties +++ b/portofino-crud/src/main/resources/portofino-messages_it.properties @@ -27,3 +27,5 @@ none.available = Nessuno disponibile. return.to.search = Torna alla ricerca show.search = Ricerca hide.search = Nascondi + +search.results=risultati diff --git a/portofino-cryptography/pom.xml b/portofino-cryptography/pom.xml new file mode 100644 index 0000000000..1ebdc58121 --- /dev/null +++ b/portofino-cryptography/pom.xml @@ -0,0 +1,58 @@ + + + + portofino + com.manydesigns + 4.2.4 + + 4.0.0 + portofino-cryptography + jar + http://www.manydesigns.com/ + + + javax.servlet + javax.servlet-api + provided + + + + org.slf4j + slf4j-nop + 1.7.5 + provided + + + commons-codec + commons-codec + 20041127.091804 + compile + + + commons-configuration + commons-configuration + ${commons.configuration.version} + compile + + + commons-logging + commons-logging + + + commons-beanutils + commons-beanutils-core + + + + + + + + src/main/resources + false + + + + \ No newline at end of file diff --git a/portofino-cryptography/src/main/java/com/manydesigns/crypto/CryptoService.java b/portofino-cryptography/src/main/java/com/manydesigns/crypto/CryptoService.java new file mode 100644 index 0000000000..f4853d1ae0 --- /dev/null +++ b/portofino-cryptography/src/main/java/com/manydesigns/crypto/CryptoService.java @@ -0,0 +1,93 @@ +package com.manydesigns.crypto; + +import org.apache.commons.codec.binary.Base64; + +import javax.crypto.*; +import java.io.IOException; +import java.io.InputStream; +import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +public class CryptoService { + + //Affect resulting file size + private String typeAlgo = "DES/ECB/PKCS5Padding"; + private static CryptoService single; + + public String getTypeAlgo(){ + return typeAlgo; + } + + public static CryptoService getInstance() { + if (single == null) + single = new CryptoService(); + return single; + } + + private SecretKey getkey() throws GeneralSecurityException, IOException { + return KeyManager.getInstance().getSimmK(); + } + + public String encrypt(String decrypted) + throws GeneralSecurityException, IOException { + return new String(Base64.encodeBase64(encrypt(decrypted.getBytes()))); + } + + public String decrypt(String encrypted) + throws GeneralSecurityException, IOException { + return new String(decrypt(Base64.decodeBase64(encrypted.getBytes()))); + } + + public byte[] encrypt(byte[] decrypted) + throws GeneralSecurityException, IOException { + return encrypt(decrypted, typeAlgo, getkey()); + } + + public byte[] decrypt(byte[] encrypted) + throws GeneralSecurityException, IOException { + return decrypt(encrypted, typeAlgo, getkey()); + } + + public InputStream encrypt(InputStream decrypted) + throws GeneralSecurityException, IOException { + return encrypt(decrypted, typeAlgo, getkey()); + } + + public InputStream decrypt(InputStream encrypted) + throws GeneralSecurityException, IOException { + return decrypt(encrypted, typeAlgo, getkey()); + } + + public static byte[] encrypt(byte[] decrypted, String algorithm, SecretKey key) + throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException { + Cipher cipher = Cipher.getInstance(algorithm); + cipher.init(Cipher.ENCRYPT_MODE, key); + return cipher.doFinal(decrypted); + } + + public static byte[] decrypt(byte[] encrypted, String algorithm, SecretKey key) + throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException { + Cipher cipher = Cipher.getInstance(algorithm); + cipher.init(Cipher.DECRYPT_MODE, key); + return cipher.doFinal(encrypted); + } + + public static InputStream decrypt(InputStream encryptedInputStream, String algorithm, SecretKey key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException { + Cipher cipher = Cipher.getInstance(algorithm); + cipher.init(Cipher.DECRYPT_MODE, key); + return new CipherInputStream(encryptedInputStream, cipher); + } + + public static InputStream encrypt(InputStream decryptedInputStream, String algorithm, SecretKey key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException { + Cipher cipher = Cipher.getInstance(algorithm); + cipher.init(Cipher.ENCRYPT_MODE, key); + return new CipherInputStream(decryptedInputStream, cipher); + } + + public Long getFileSize( Long originalSize ){ + //if( typeAlgo ... + Double value = Math.ceil(originalSize.doubleValue()/16d)*16; + return value.longValue(); + } +} diff --git a/portofino-cryptography/src/main/java/com/manydesigns/crypto/KeyManager.java b/portofino-cryptography/src/main/java/com/manydesigns/crypto/KeyManager.java new file mode 100644 index 0000000000..2276ecb086 --- /dev/null +++ b/portofino-cryptography/src/main/java/com/manydesigns/crypto/KeyManager.java @@ -0,0 +1,214 @@ +package com.manydesigns.crypto; + +import org.apache.commons.configuration.Configuration; +import javax.crypto.*; +import javax.crypto.spec.DESKeySpec; +import javax.crypto.spec.SecretKeySpec; +import javax.servlet.ServletContext; +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.*; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import org.apache.commons.codec.binary.Base64; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class KeyManager { + + public static final Logger logger = LoggerFactory.getLogger(KeyManager.class); + + private static final String PROPERTY_ALG="com.manydesigns.crypto.algrorithm"; + private static final String PROPERTY_PRIVATE_KEY="com.manydesigns.crypto.private.key"; + private static final String PROPERTY_PUBLIC_KEY="com.manydesigns.crypto.public.key"; + private static final String PROPERTY_PRIVATE_KEY_DELETE="com.manydesigns.crypto.delete.key"; + private static final String PROPERTY_PASSPHRASE="com.manydesigns.crypto.passphrase"; + + private static final String ASYMMETRIC_ALG="AES"; + private static final String SYMMETRIC_ALG="DES"; + + private static final int PASS_MIN_LEN = 8; + + private SecretKey simmK; + private PublicKey pbK; + private PrivateKey prK; + private String algo; + private static KeyManager single; + + private KeyManager(Configuration configuration ) throws GeneralSecurityException, IOException { + algo = configuration.getString(PROPERTY_ALG); + + if( algo==null ) + return; + + Boolean autoDelete = configuration.getBoolean(PROPERTY_PRIVATE_KEY_DELETE,false); + String publicKeyPath = configuration.getString(PROPERTY_PUBLIC_KEY); + String privateKeyPath = configuration.getString(PROPERTY_PRIVATE_KEY); + String passphrasePath = configuration.getString(PROPERTY_PASSPHRASE); + + if( algo.equals(ASYMMETRIC_ALG)){ + this.prK = getPrivateKey(privateKeyPath); + this.pbK = getPublicKey(publicKeyPath); + this.simmK = null; + }else{ + String strK = getPassPhrase(passphrasePath); + DESKeySpec desKeySpec = new DESKeySpec(strK.getBytes()); + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(SYMMETRIC_ALG); + this.simmK = keyFactory.generateSecret(desKeySpec); + } + + if( autoDelete && passphrasePath!=null ){ + try { + if( algo.equals(ASYMMETRIC_ALG)) { + logger.info("DELETING " + privateKeyPath); + try(PrintWriter pw = new PrintWriter(privateKeyPath);) { + pw.print(""); + } + } + else{ + logger.info("DELETING " + passphrasePath); + try(PrintWriter pw = new PrintWriter(passphrasePath);) { + pw.print(""); + } + } + } catch (IOException e) { + logger.error(e.getMessage(),e); + } + } + } + + public static KeyManager init(Configuration configuration) throws IOException, GeneralSecurityException { + if (isActive()) + throw new GeneralSecurityException("Key manager already initialized"); + single = new KeyManager(configuration); + return getInstance(); + } + + public static KeyManager getInstance() throws IOException, GeneralSecurityException { + if(single == null) + throw new GeneralSecurityException("Key manager not initialized"); + return single; + } + + public static boolean isActive(){ + if(single == null) + return false; + return true; + } + + public SecretKey getSimmK() { + return this.simmK; + } + + public PublicKey getPbKey(){ + return this.pbK; + } + + public PrivateKey getPrKey(){ + return this.prK; + } + + public String getAlgo(){ return this.algo; } + + private static String getKey(String filename) throws IOException { + // Read key from file + String strKeyPEM = ""; + BufferedReader br = null; + try { + br = new BufferedReader(new FileReader(filename)); + String line; + while ((line = br.readLine()) != null) { + strKeyPEM += line + "\n"; + } + }catch (IOException e) { + e.printStackTrace(); + }finally{ + br.close(); + } + + return strKeyPEM; + } + + private static PrivateKey getPrivateKey(String filename) throws IOException, GeneralSecurityException { + String privateKeyPEM = getKey(filename); + return getPrivateKeyFromString(privateKeyPEM); + } + + private static PrivateKey getPrivateKeyFromString(String key) throws IOException, GeneralSecurityException { + String privateKeyPEM = key; + privateKeyPEM = privateKeyPEM.replace("-----BEGIN PRIVATE KEY-----\n", ""); + privateKeyPEM = privateKeyPEM.replace("-----END PRIVATE KEY-----", ""); + byte[] encoded = Base64.decodeBase64(privateKeyPEM.getBytes()); + KeyFactory kf = KeyFactory.getInstance("RSA"); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded); + PrivateKey privKey = kf.generatePrivate(keySpec); + return privKey; + } + + private static PublicKey getPublicKey(String filename) throws IOException, GeneralSecurityException { + String publicKeyPEM = getKey(filename); + return getPublicKeyFromString(publicKeyPEM); + } + + private static PublicKey getPublicKeyFromString(String key) throws IOException, GeneralSecurityException { + String publicKeyPEM = key; + publicKeyPEM = publicKeyPEM.replace("-----BEGIN PUBLIC KEY-----\n", ""); + publicKeyPEM = publicKeyPEM.replace("-----END PUBLIC KEY-----", ""); + byte[] encoded = Base64.decodeBase64(publicKeyPEM.getBytes()); + KeyFactory kf = KeyFactory.getInstance("RSA"); + PublicKey pubKey = kf.generatePublic(new X509EncodedKeySpec(encoded)); + return pubKey; + } + + private String getPassPhrase(String passphrasePath){ + logger.info("Retrieving passphrase"); + StringBuilder passPhrase = new StringBuilder(); + + if(passphrasePath!=null) { + BufferedReader br = null; + try { + br = new BufferedReader(new FileReader(passphrasePath)); + String line; + while ((line = br.readLine()) != null) { + passPhrase.append(line); + } + } catch (IOException e) { + logger.error("getPassPhrase: " + e.getMessage(), e); + logger.debug("prompt passphrase"); + return getInputPassphrase(); + } + }else{ + logger.debug("passphrasePath null, prompt passphrase"); + return getInputPassphrase(); + } + + return passPhrase.toString(); + } + + private String getInputPassphrase() { + String pass = null; + Console console = System.console(); + if (console != null) { + logger.debug("Reading from System.console"); + console.printf("_______________________________________________________\n\n ENTER PASSPHRASE: \n"); + pass = new String(console.readPassword()); + console.printf("_______________________________________________________\n"); + } else { + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + System.out.print("_______________________________________________________\n\n ENTER PASSPHRASE: \n"); + try { + logger.debug("Reading from System.in"); + pass = br.readLine(); + System.out.print("_______________________________________________________\n"); + } catch (IOException e) { + logger.error(e.getMessage(), e); + } + } + if( pass!=null && pass.length() com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-database jar diff --git a/portofino-database/src/main/java/com/manydesigns/portofino/persistence/Persistence.java b/portofino-database/src/main/java/com/manydesigns/portofino/persistence/Persistence.java index 554162e0f2..1d9696c859 100644 --- a/portofino-database/src/main/java/com/manydesigns/portofino/persistence/Persistence.java +++ b/portofino-database/src/main/java/com/manydesigns/portofino/persistence/Persistence.java @@ -205,7 +205,7 @@ protected void runLiquibase(Database database) { JdbcConnection jdbcConnection = new JdbcConnection(connection); liquibase.database.Database lqDatabase = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(jdbcConnection); - lqDatabase.setDefaultSchemaName(schemaName); + lqDatabase.setDefaultSchemaName(schema.getSchema()); String relativeChangelogPath = ElementsFileUtils.getRelativePath(appDir, changelogFile, System.getProperty("file.separator")); if(new File(relativeChangelogPath).isAbsolute()) { diff --git a/portofino-database/src/main/java/com/manydesigns/portofino/sync/DatabaseSyncer.java b/portofino-database/src/main/java/com/manydesigns/portofino/sync/DatabaseSyncer.java index e09ef12316..4fb65a885d 100644 --- a/portofino-database/src/main/java/com/manydesigns/portofino/sync/DatabaseSyncer.java +++ b/portofino-database/src/main/java/com/manydesigns/portofino/sync/DatabaseSyncer.java @@ -101,14 +101,14 @@ public Database syncDatabase(Model sourceModel) throws Exception { for (Schema schema : schemas) { String schemaName = schema.getSchemaName(); - logger.info("Processing schema: {}", schemaName); - Schema sourceSchema = - DatabaseLogic.findSchemaByNameIgnoreCase( - sourceDatabase, schemaName); + String schemaRealName = schema.getSchema(); + logger.info("Processing schema: {}", schemaRealName); + Schema sourceSchema = DatabaseLogic.findSchemaByNameIgnoreCase(sourceDatabase, schemaName); if (sourceSchema == null) { logger.debug("Source schema not found. Creating an empty one."); sourceSchema = new Schema(); sourceSchema.setSchemaName(schemaName); + sourceSchema.setSchema(schemaRealName); } logger.debug("Creating Liquibase database snapshot"); @@ -136,13 +136,13 @@ public Database syncDatabase(Model sourceModel) throws Exception { } public Schema syncSchema(DatabaseSnapshot databaseSnapshot, Schema sourceSchema, Schema targetSchema) { - logger.info("Synchronizing schema: {}", sourceSchema.getSchemaName()); + logger.info("Synchronizing schema: {}", sourceSchema.getSchema()); + targetSchema.setSchemaName(sourceSchema.getSchemaName()); + targetSchema.setSchema(sourceSchema.getSchema()); syncTables(databaseSnapshot, sourceSchema, targetSchema); - syncPrimaryKeys(databaseSnapshot, sourceSchema, targetSchema); - syncForeignKeys(databaseSnapshot, sourceSchema, targetSchema); return targetSchema; diff --git a/portofino-db2/pom.xml b/portofino-db2/pom.xml index 7b91ae5e93..89044f1bfc 100644 --- a/portofino-db2/pom.xml +++ b/portofino-db2/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-db2 jar diff --git a/portofino-derby/pom.xml b/portofino-derby/pom.xml index 8a69e91d7d..b8178c0b1f 100644 --- a/portofino-derby/pom.xml +++ b/portofino-derby/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-derby jar diff --git a/portofino-gallery/pom.xml b/portofino-gallery/pom.xml index c61882d8ae..9116c12ea1 100644 --- a/portofino-gallery/pom.xml +++ b/portofino-gallery/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-gallery jar diff --git a/portofino-googlecloudsql/pom.xml b/portofino-googlecloudsql/pom.xml index bec4e5bf3b..0271fe4521 100644 --- a/portofino-googlecloudsql/pom.xml +++ b/portofino-googlecloudsql/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-googlecloudsql jar diff --git a/portofino-h2/pom.xml b/portofino-h2/pom.xml index c236431d52..881e21916e 100644 --- a/portofino-h2/pom.xml +++ b/portofino-h2/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-h2 jar diff --git a/portofino-jersey/pom.xml b/portofino-jersey/pom.xml index 9e81415c88..c8d082244c 100644 --- a/portofino-jersey/pom.xml +++ b/portofino-jersey/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-jersey jar diff --git a/portofino-mail/pom.xml b/portofino-mail/pom.xml index d20bc7d22f..4940d462c7 100644 --- a/portofino-mail/pom.xml +++ b/portofino-mail/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-mail jar diff --git a/portofino-map/pom.xml b/portofino-map/pom.xml index 70c171eab0..7bb8f32f95 100644 --- a/portofino-map/pom.xml +++ b/portofino-map/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-map jar diff --git a/portofino-model/pom.xml b/portofino-model/pom.xml index 12ad4b7127..59b1bff294 100644 --- a/portofino-model/pom.xml +++ b/portofino-model/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-model jar diff --git a/portofino-model/src/main/java/com/manydesigns/portofino/model/database/Schema.java b/portofino-model/src/main/java/com/manydesigns/portofino/model/database/Schema.java index 3110f6694d..90f94b7702 100644 --- a/portofino-model/src/main/java/com/manydesigns/portofino/model/database/Schema.java +++ b/portofino-model/src/main/java/com/manydesigns/portofino/model/database/Schema.java @@ -39,7 +39,7 @@ * @author Alessio Stalla - alessio.stalla@manydesigns.com */ @XmlAccessorType(XmlAccessType.NONE) -@XmlType(propOrder = {"catalog", "schemaName","immediateTables"}) +@XmlType(propOrder = {"catalog", "schemaName","schema","immediateTables"}) public class Schema implements ModelObject { public static final String copyright = "Copyright (C) 2005-2017 ManyDesigns srl"; @@ -53,6 +53,7 @@ public class Schema implements ModelObject { protected final List
tables = new ArrayList
(); protected String schemaName; + protected String schema; protected String catalog; //************************************************************************** @@ -86,9 +87,9 @@ public void afterUnmarshal(Unmarshaller u, Object parent) { public String getQualifiedName() { if(getDatabaseName() == null) { - return schemaName; + return schema!=null?schema:schemaName; } - return MessageFormat.format("{0}.{1}", getDatabaseName(), schemaName); + return MessageFormat.format("{0}.{1}", getDatabaseName(), schema!=null?schema:schemaName); } public void reset() {} @@ -96,6 +97,8 @@ public void reset() {} public void init(Model model) { assert database != null; assert schemaName != null; + if( schema == null ) + schema = schemaName; } public void link(Model model) {} @@ -131,6 +134,15 @@ public void setSchemaName(String schemaName) { this.schemaName = schemaName; } + @XmlAttribute(required = false) + public String getSchema() { + return schema; + } + + public void setSchema(String schema) { + this.schema = schema; + } + @XmlAttribute(required = false) public String getCatalog() { return catalog; diff --git a/portofino-model/src/main/java/com/manydesigns/portofino/model/database/Table.java b/portofino-model/src/main/java/com/manydesigns/portofino/model/database/Table.java index 8b43206f81..ed8890bd6d 100644 --- a/portofino-model/src/main/java/com/manydesigns/portofino/model/database/Table.java +++ b/portofino-model/src/main/java/com/manydesigns/portofino/model/database/Table.java @@ -188,7 +188,7 @@ public String getDatabaseName() { @Required public String getSchemaName() { - return schema.getSchemaName(); + return schema.getSchema(); } @Required diff --git a/portofino-mssql/pom.xml b/portofino-mssql/pom.xml index df0323cf69..21dee1c107 100644 --- a/portofino-mssql/pom.xml +++ b/portofino-mssql/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-mssqljar diff --git a/portofino-mysql/pom.xml b/portofino-mysql/pom.xml index b93c94c842..1e7084c47c 100644 --- a/portofino-mysql/pom.xml +++ b/portofino-mysql/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-mysqljar diff --git a/portofino-openid/pom.xml b/portofino-openid/pom.xml index eae6438dee..0e21acd33b 100644 --- a/portofino-openid/pom.xml +++ b/portofino-openid/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-openidjar diff --git a/portofino-oracle/pom.xml b/portofino-oracle/pom.xml index ebcf20c2cc..43b1933326 100644 --- a/portofino-oracle/pom.xml +++ b/portofino-oracle/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-oraclejar diff --git a/portofino-pageactions/pom.xml b/portofino-pageactions/pom.xml index 1a3aed8f36..174b3edde3 100644 --- a/portofino-pageactions/pom.xml +++ b/portofino-pageactions/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-pageactionsjar diff --git a/portofino-pageactions/src/main/java/com/manydesigns/portofino/pages/Page.java b/portofino-pageactions/src/main/java/com/manydesigns/portofino/pages/Page.java index 6b0982095b..4241a9ac2c 100644 --- a/portofino-pageactions/src/main/java/com/manydesigns/portofino/pages/Page.java +++ b/portofino-pageactions/src/main/java/com/manydesigns/portofino/pages/Page.java @@ -20,6 +20,7 @@ package com.manydesigns.portofino.pages; +import com.manydesigns.elements.ElementsThreadLocals; import com.manydesigns.elements.annotations.FieldSize; import com.manydesigns.elements.annotations.Required; import org.slf4j.Logger; @@ -28,14 +29,14 @@ import javax.xml.bind.annotation.*; /* -* @author Paolo Predonzani - paolo.predonzani@manydesigns.com -* @author Angelo Lupo - angelo.lupo@manydesigns.com -* @author Giampiero Granatella - giampiero.granatella@manydesigns.com -* @author Alessio Stalla - alessio.stalla@manydesigns.com -*/ + * @author Paolo Predonzani - paolo.predonzani@manydesigns.com + * @author Angelo Lupo - angelo.lupo@manydesigns.com + * @author Giampiero Granatella - giampiero.granatella@manydesigns.com + * @author Alessio Stalla - alessio.stalla@manydesigns.com + */ @XmlRootElement @XmlAccessorType(value = XmlAccessType.NONE) -@XmlType(propOrder = {"title","description", "navigationRoot","id","layout","detailLayout","permissions"}) +@XmlType(propOrder = {"title","titleKey","description", "navigationRoot","id","layout","detailLayout","permissions"}) public class Page { public static final String copyright = "Copyright (C) 2005-2017 ManyDesigns srl"; @@ -46,6 +47,7 @@ public class Page { protected String id; protected String title; + protected String titleKey; protected String description; protected Layout layout; protected Layout detailLayout; @@ -122,7 +124,17 @@ public void setId(String id) { @Required @FieldSize(50) public String getTitle() { - return title; + return titleKey==null?title: ElementsThreadLocals.getText(titleKey); + } + + @XmlAttribute(required = false) + @FieldSize(50) + public String getTitleKey() { + return titleKey; + } + + public void setTitleKey(String titleKey) { + this.titleKey = titleKey; } public void setTitle(String title) { diff --git a/portofino-pageactions/src/main/resources/portofino-messages_ar.properties b/portofino-pageactions/src/main/resources/portofino-messages_ar.properties new file mode 100644 index 0000000000..ef436fa1cf --- /dev/null +++ b/portofino-pageactions/src/main/resources/portofino-messages_ar.properties @@ -0,0 +1,334 @@ +#CRUD +save = \u062d\u0641\u0638 +object.not.found._= \u0627\u0644\u0645\u0648\u0636\u0648\u0639 \u063a\u064a\u0631 \u0645\u0648\u062c\u0648\u062f +incorrect.field.type = \u0646\u0648\u0639 \u0627\u0644\u062d\u0642\u0644 \u063a\u064a\u0631 \u0635\u062d\u064a\u062d +save.failed.because.constraint.violated = \u0641\u0634\u0644 \u0627\u0644\u062d\u0641\u0638 \u0628\u0633\u0628\u0628 \u0627\u0646\u062a\u0647\u0627\u0643 \u0627\u062d\u062f \u0627\u0644\u0642\u064a\u0648\u062f +object._.saved= \u062a\u0645 \u062d\u0641\u0638 \u0627\u0644\u0645\u0648\u0636\u0648\u0639 +create.another.object= \u0627\u0646\u0634\u0627\u0621 \u0645\u0648\u0636\u0648\u0639 \u0627\u062e\u0631 +update.of._.objects.successful = \u062a\u0645 \u062a\u062d\u062f\u064a\u062b \u0627\u0644\u0645\u0648\u0636\u0648\u0639 \u0628\u0646\u062c\u0627\u062d +no.object.was.selected = \u0644\u0645 \u064a\u062a\u0645 \u062a\u062d\u062f\u064a\u062f \u0645\u0648\u0636\u0648\u0639 +object.deleted.successfully= \u062a\u0645 \u062d\u0630\u0641 \u0627\u0644\u0645\u0648\u0636\u0648\u0639 \u0628\u0646\u062c\u0627\u062d +_.objects.deleted.successfully = \u062a\u0645 \u062d\u0630\u0641 \u0627\u0644\u0645\u0648\u0627\u0636\u064a\u0639 \u0628\u0646\u062c\u0627\u062d +fields.marked.with.a.star.are.required= \u0627\u0644\u062d\u0642\u0648\u0644 \u0627\u0644\u062a\u064a \u062a\u062d\u0645\u0644 \u0639\u0644\u0627\u0645\u0629 "*" \u0645\u0637\u0644\u0648\u0628\u0629 +search= \u0627\u0644\u0628\u062d\u062b +reset.search= \u0627\u0639\u0627\u062f\u0629 \u062a\u0639\u064a\u064a\u0646 \u0627\u0644\u0628\u062d\u062b +page._.of._ = \u0635\u0641\u062d\u0647 {0} \u0645\u0646 {1} +_.of._ = {0} \u0645\u0646 {1} +crud-create = \u0627\u0646\u0634\u0627\u0621 +crud-delete = \u062d\u0630\u0641 +crud-edit = \u062a\u0639\u062f\u064a\u0644 +name = \u0627\u0644\u0627\u0633\u0645 +name_en = \u0646\u064a\u0645 (\u0625\u0646\u062c\u0644\u064a\u0634) +in.the.first.column.select.the.fields.you.want.to.edit = \u0641\u064a \u0627\u0644\u0639\u0645\u0648\u062f \u0627\u0644\u0627\u0648\u0644 , \u062d\u062f\u062f \u0627\u0644\u062d\u0642\u0648\u0644 \u0627\u0644\u062a\u064a \u062a\u0631\u064a\u062f \u062a\u0639\u062f\u064a\u0644\u0647\u0627 \u062b\u0645 \u0627\u0645\u0644\u0623\u0647\u0627 +properties = \u0627\u0644\u062e\u0635\u0627\u0626\u0635 +you.must.write.a.query.first = \u064a\u062c\u0628 \u0643\u062a\u0627\u0628\u0629 \u0627\u0644\u0627\u0633\u062a\u0639\u0644\u0627\u0645 \u0627\u0648\u0644\u0627 +selection.providers = \u0627\u062e\u062a\u064a\u0627\u0631 \u0627\u0644\u0645\u0642\u062f\u0645\u064a\u0646 +none.available = \u063a\u064a\u0631 \u0645\u062a\u0648\u0641\u0631 +return.to.search = \u0627\u0644\u0631\u062c\u0648\u0639 \u0627\u0644\u0649 \u0627\u0644\u0628\u062d\u062b +show.search = \u0639\u0631\u0636 \u0627\u0644\u0628\u062d\u062b +hide.search = \u0627\u062e\u0641\u0627\u0621 \u0627\u0644\u0628\u062d\u062b +elements.null= \u0627\u0644\u0639\u0646\u0635\u0631 \u0641\u0627\u0631\u063a +elements.Yes= \u0646\u0639\u0645 +elements.No= \u0644\u0627 +elements.Any= \u0627\u0644\u0643\u0644 +elements.Undefined= \u063a\u064a\u0631 \u0645\u0639\u0631\u0641 +elements.field.upload.keep=\u062d\u0641\u0638 +elements.field.upload.update= \u062a\u062d\u062f\u064a\u062b +elements.field.upload.delete= \u062d\u0630\u0641 +elements.field.password.confirm= \u062a\u0627\u0643\u064a\u062f +elements.field.select.select= {0} \u0627\u062e\u062a\u064a\u0627\u0631 +elements.field.select.none= \u0644\u0627 \u064a\u0648\u062c\u062f +elements.search.range.from= \u0645\u0646 +elements.search.range.to= \u0627\u0644\u0649 +elements.search.select.none= \u0644\u0645 \u062a\u062a\u0645 \u062a\u0635\u0646\u064a\u0641\u0647 +elements.search.select.notset.radio=(\u063a\u064a\u0631 \u0645\u062d\u062f\u062f) +elements.search.select.notset=-- \u063a\u064a\u0631 \u0645\u062d\u062f\u062f -- +elements.search.text.match.mode.contains=\u064a\u062d\u062a\u0648\u064a \u0639\u0644\u0649 +elements.search.text.match.mode.equals= \u064a\u0633\u0627\u0648\u064a +elements.search.text.match.mode.starts.with= \u0627\u0644\u0628\u062f\u0621 \u0645\u0639 +elements.search.text.match.mode.ends.with= \u0627\u0644\u0646\u0647\u0627\u064a\u0629 \u0645\u0639 +elements.error.field.required= \u0627\u0644\u062d\u0642\u0648\u0644 \u0645\u0637\u0644\u0648\u0628\u0647 +elements.error.field.length.exceeded= \u062d\u062f \u0627\u0644\u0623\u0642\u0635\u0649 \u0627\u0644\u0645\u0633\u0645\u0648\u062d \u0628\u0647 \u0647\u0648 {0} \u062d\u0631\u0641\u0627 +elements.error.field.integer.format= \u0639\u062f\u062f \u063a\u064a\u0631 \u0635\u062d\u064a\u062d +elements.error.field.decimal.format= \u0639\u062f\u062f \u0639\u0634\u0631\u064a \u063a\u064a\u0631 \u0635\u0627\u0644\u062d +elements.error.field.date.format= \u062a\u0627\u0631\u064a\u062e \u063a\u064a\u0631 \u0635\u062d\u064a\u062d +elements.error.field.greater.or.equal=\u064a\u062c\u0628 \u0627\u0646 \u064a\u0643\u0648\u0646 >= {0} +elements.error.field.less.or.equal=\u064a\u062c\u0628 \u0627\u0646 \u064a\u0643\u0648\u0646 <= {0} +elements.error.field.passwords.dont.match= \u0643\u0644\u0645\u0629 \u0627\u0644\u0633\u0631 \u063a\u064a\u0631 \u0645\u0637\u0627\u0628\u0642\u0629 +elements.error.field.email.format= \u0627\u0644\u0627\u064a\u0645\u064a\u0644 \u063a\u064a\u0631 \u0635\u062d\u064a\u062d +elements.error.field.phone.format= \u0631\u0642\u0645 \u0627\u0644\u0647\u0627\u062a\u0641 \u063a\u064a\u0631 \u0635\u062d\u064a\u062d +elements.error.field.codice.fiscale.format=\u0627\u0644\u0634\u0641\u0631\u0647 \u063a\u064a\u0631 \u0635\u0627\u0644\u062d\u0647 +elements.error.field.cap.format= \u062a\u0646\u0633\u064a\u0642 \u0643\u0627\u0628 \u063a\u064a\u0631 \u0635\u0627\u0644\u062d +elements.error.field.partita.iva.format=Invalid partita IVA +elements.error.field.regexp.format=\u0642\u064a\u0645\u0647 \u063a\u064a\u0631 \u0635\u0627\u0644\u062d\u0647 - \u0644\u0627 \u062a\u062a\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u062a\u0639\u0628\u064a\u0631 \u0627\u0644\u0639\u0627\u062f\u064a {0} +elements.error.field.fileblob.cannotLoad = \u0644\u0627 \u064a\u0645\u0643\u0646 \u062a\u062d\u0645\u064a\u0644 \u0627\u0644\u0646\u0642\u0637\u0629 +elements.error.field.fileblob.uploadFailed = \u0641\u0634\u0644 \u0627\u0644\u0631\u0641\u0639 +elements.error.field.databaseblob.couldntSaveBlob = \u062a\u0639\u0630\u0631 \u062d\u0641\u0638 \u0627\u0644\u0646\u0642\u0637\u0629 +elements.error.field.invalid=\u0642\u064a\u0645\u0647 \u062e\u0627\u0637\u0626\u0629: {0} + +move = \u0646\u0642\u0644 +copy = \u0646\u0633\u062e +copy.to = \u0646\u0633\u062e \u0627\u0644\u0649... +are.you.sure.you.want.to.delete.this.page = \u0647\u0644 \u0627\u0646\u062a \u0645\u062a\u0627\u0643\u062f \u0645\u0646 \u062d\u0630\u0641 \u0627\u0644\u0635\u0641\u062d\u0647 \u061f +deleting.it.will.also.delete.its.children = \u0627\u0644\u062d\u0630\u0641 \u0633\u064a\u0624\u062f\u064a \u0627\u0644\u0649 \u062d\u0630\u0641 \u0627\u0644\u062c\u0645\u064a\u0639 +really.delete = \u0647\u0644 \u062d\u0642\u0627 \u062a\u0631\u064a\u062f \u0627\u0644\u062d\u0630\u0641 \u061f +where.to.move = \u0627\u0644\u0646\u0642\u0644 \u0627\u0644\u0649 \u0627\u064a\u0646 \u061f +move.to = \u0627\u0644\u0646\u0642\u0644 \u0627\u0644\u0649 ... +root.permissions = \u0627\u0630\u0648\u0646\u0627\u062a \u0627\u0644\u062c\u0630\u0631 +top.level.pages = \u0627\u0644\u0635\u0641\u062d\u0627\u062a \u0630\u0627\u062a \u0627\u0644\u0645\u0633\u062a\u0648\u0649 \u0627\u0644\u0627\u0639\u0644\u0649 +add.new.page = \u0627\u0636\u0627\u0641\u0629 \u0635\u0641\u062d\u0647 +preview = \u0645\u0639\u0627\u064a\u0646\u0629 +test.a.user = \u0641\u062d\u0635 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645 +select.a.user.and.view.its.permissions = \u062a\u062d\u062f\u064a\u062f \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645 \u0648\u0639\u0631\u0636 \u0627\u0630\u0648\u0646\u0627\u062a\u0647 \u062d\u0648\u0644 \u0647\u0630\u0647 \u0627\u0644\u0635\u0641\u062d\u0647 +group = \u0627\u0644\u0645\u062c\u0645\u0648\u0639\u0647 +access.level = \u0645\u0633\u062a\u0648\u0649 \u0627\u0644\u0648\u0635\u0648\u0644 +#Permissions +inherited._=\u0648\u0627\u0631\u062b ({0}) +view= \u0639\u0631\u0636 +develop= \u062a\u0637\u0648\u064a\u0631 +deny= \u0631\u0641\u0636 +none= \u0644\u0627\u064a\u0648\u062c\u062f +permissions = \u0627\u0644\u0627\u0630\u0648\u0646\u0627\u062a +page.permissions.for._ = {\u0630\u0648\u0646\u0627\u062a \u0627\u0644\u0635\u0641\u062e\u0629 \u0627\u0644: {0 +page.permissions.saved.successfully = \u062a\u0645 \u062d\u0641\u0638 \u0627\u0630\u0648\u0646\u0627\u062a \u0627\u0644\u0635\u0641\u062d\u0629 \u0628\u0646\u062c\u0627\u062d +root.permissions.saved.successfully = \u062a\u0645 \u062d\u0641\u0638 \u0627\u0630\u0648\u0646\u0627\u062a \u0627\u0644\u062c\u0630\u0631 \u0628\u0646\u062c\u0627\u062d + +#Page crud +error.creating.page._ = \u062d\u062f\u062b \u062e\u0637\u0623 \u0623\u062b\u0646\u0627\u0621 \u0625\u0646\u0634\u0627\u0621 \u0627\u0644\u0635\u0641\u062d\u0629: {0} (\u0631\u0627\u062c\u0639 \u0627\u0644\u0633\u062c\u0644\u0627\u062a \u0644\u0644\u062d\u0635\u0648\u0644 \u0639\u0644\u0649 \u0645\u0632\u064a\u062f \u0645\u0646 \u0627\u0644\u062a\u0641\u0627\u0635\u064a\u0644) +error.creating.page.the.directory.already.exists = \u062d\u062f\u062b \u062e\u0637\u0623 \u0623\u062b\u0646\u0627\u0621 \u0625\u0646\u0634\u0627\u0621 \u0627\u0644\u0635\u0641\u062d\u0629\u060c \u0641\u0647\u0630\u0627 \u0627\u0644\u062f\u0644\u064a\u0644 \u0645\u0648\u062c\u0648\u062f \u0628\u0627\u0644\u0641\u0639\u0644 +error.creating.page.the.directory.could.not.be.created = \u062d\u062f\u062b \u062e\u0637\u0623 \u0623\u062b\u0646\u0627\u0621 \u0625\u0646\u0634\u0627\u0621 \u0627\u0644\u0635\u0641\u062d\u0629\u060c \u0648\u0644\u0627 \u064a\u0645\u0643\u0646 \u0625\u0646\u0634\u0627\u0621 \u0627\u0644\u062f\u0644\u064a\u0644 +page.created.successfully.you.should.now.configure.it = \u062a\u0645 \u0625\u0646\u0634\u0627\u0621 \u0627\u0644\u0635\u0641\u062d\u0629 \u0628\u0646\u062c\u0627\u062d. \u064a\u062c\u0628 \u0627\u0644\u0622\u0646 \u062a\u0643\u0648\u064a\u0646\u0647. +invalid.fragment.only.letters.numbers.etc.are.allowed = \u062c\u0632\u0621 \u063a\u064a\u0631 \u0635\u0627\u0644\u062d. \u064a\u0633\u0645\u062d \u0648_ \u0627\u0644\u0623\u062d\u0631\u0641 - \u062d\u0631\u0648\u0641 \u0648\u0623\u0631\u0642\u0627\u0645. +you.cant.delete.the.root.page = \u0644\u0627 \u064a\u0645\u0643\u0646\u0643 \u062d\u0630\u0641 \u0627\u0644\u0635\u0641\u062d\u0629 \u0627\u0644\u062c\u0630\u0631! +you.cant.delete.the.landing.page = \u0644\u0627 \u064a\u0645\u0643\u0646\u0643 \u062d\u0630\u0641 \u0627\u0644\u0635\u0641\u062d\u0629 \u0627\u0644\u0645\u0642\u0635\u0648\u062f\u0629! +you.must.select.a.destination = \u064a\u062c\u0628 \u062a\u062d\u062f\u064a\u062f \u0627\u0644\u0648\u062c\u0647\u0629 +you.cant.copy.or.move.the.root.page =\u0644\u0627 \u064a\u0645\u0643\u0646\u0643 \u0646\u0633\u062e \u0623\u0648 \u0646\u0642\u0644 \u0627\u0644\u0635\u0641\u062d\u0629 \u0627\u0644\u062c\u0630\u0631! +you.dont.have.edit.access.level.on.the.destination.page = \u0644\u064a\u0633 \u0644\u062f\u064a\u0643 \u0627\u0644\u062a\u062e\u0648\u064a\u0644 \u0644\u0644\u0648\u0635\u0648\u0644 \u0644\u0644\u0635\u0641\u062d\u0629 \u0627\u0644\u0646\u0642\u0635\u0648\u062f\u0629 \u0648\u0627\u0644\u062a\u0639\u062f\u064a\u0644 \u0639\u0644\u064a\u0647\u0627 +invalid.destination._ = \u0627\u0644\u0648\u062c\u0647\u0629 \u063a\u064a\u0631 \u0635\u0627\u0644\u062d\u0629: {0} +destination.is.an.existing.file/directory._ = {\u0627\u0644\u0648\u062c\u0647\u0629 \u0647\u064a \u0645\u0644\u0641 / \u062f\u0644\u064a\u0644 \u0645\u0648\u062c\u0648\u062f: {0 +you.cant.move.the.landing.page = \u0644\u0627 \u064a\u0645\u0643\u0646\u0643 \u0646\u0642\u0644 \u0627\u0644\u0635\u0641\u062d\u0629 \u0627\u0644\u0645\u0642\u0635\u0648\u062f\u0629! +the.page._.is.not.embedded.and.not.included.in.navigation = \u0627\u0644\u0635\u0641\u062d\u0629 {0} \u063a\u064a\u0631 \u0645\u0636\u0645\u0646\u0629 \u0648\u0644\u0627 \u064a\u062a\u0645 \u062a\u0636\u0645\u064a\u0646\u0647\u0627 \u0641\u064a \u0627\u0644\u062a\u0646\u0642\u0644 - \u0644\u0646 \u064a\u0643\u0648\u0646 \u0627\u0644\u0648\u0635\u0648\u0644 \u0625\u0644\u064a\u0647\u0627 \u0625\u0644\u0627 \u0639\u0646 \u0637\u0631\u064a\u0642 \u0639\u0646\u0648\u0627\u0646 \u0648\u0631\u0644 \u0623\u0648 \u0627\u0644\u0631\u0628\u0637 \u0627\u0644\u0635\u0631\u064a\u062d. +error.updating.page._ = \u062d\u062f\u062b \u062e\u0637\u0623 \u0623\u062b\u0646\u0627\u0621 \u062a\u062d\u062f\u064a\u062b \u0627\u0644\u0635\u0641\u062d\u0629: {0} (\u0631\u0627\u062c\u0639 \u0627\u0644\u0633\u062c\u0644\u0627\u062a \u0644\u0644\u062d\u0635\u0648\u0644 \u0639\u0644\u0649 \u0645\u0632\u064a\u062f \u0645\u0646 \u0627\u0644\u062a\u0641\u0627\u0635\u064a\u0644) +page.children.for._ = Page children for: {0} +detail = \u0627\u0644\u062a\u0641\u0627\u0635\u064a\u0644 +drag.the.rows.of.the.tables.to.reorder.the.children = \u0627\u0633\u062d\u0628 \u0627\u0644\u0635\u0641\u0648\u0641 \u0644\u0627\u0639\u0627\u062f\u0629 \u0627\u0644\u062a\u0631\u062a\u064a\u0628 - \u0644\u0627\u064a\u0645\u0643\u0646 \u0627\u0639\u062f\u0629 \u062a\u0631\u062a\u064a\u0628 \u0627\u0644\u0635\u0641\u0648\u0641 \u0627\u0644\u063a\u064a\u0631 \u0646\u0634\u0637\u0647 + +#Wizard +next = \u0627\u0644\u062a\u0627\u0644\u064a +previous = \u0627\u0644\u0633\u0627\u0628\u0642 +finish = \u0627\u0646\u0647\u0627\u0621 +register = register + +show.advanced.options = \u0639\u0631\u0636 \u0627\u0644\u062e\u064a\u0627\u0631\u0627\u062a \u0627\u0644\u0645\u062a\u0642\u062f\u0645\u0629 +additional.drivers.can.be.downloaded = \u0628\u0631\u0627\u0645\u062c \u062a\u0634\u063a\u064a\u0644 \u0625\u0636\u0627\u0641\u064a\u0629 \u064a\u0645\u0643\u0646 \u062a\u062d\u0645\u064a\u0644\u0647\u0627 \u0648\u0625\u0636\u0627\u0641\u062a\u0647\u0627 \u0625\u0644\u0649 \u0627\u0644\u0645\u0643\u062a\u0628\u0627\u062a \u0627\u0644\u0645\u0634\u062a\u0631\u0643\u0629 \u0645\u0646 \u062e\u0627\u062f\u0645 \u0627\u0644\u062a\u0637\u0628\u064a\u0642 \u0627\u0644\u062e\u0627\u0635 \u0628\u0643. +there.is.already.a.database.named._ = {\u0647\u0646\u0627\u0643 \u0628\u0627\u0644\u0641\u0639\u0644 \u0642\u0627\u0639\u062f\u0629 \u0628\u064a\u0627\u0646\u0627\u062a \u062a\u0633\u0645\u0649 {0 +couldnt.read.schema.names.from.db._ = \u0644\u0627 \u064a\u0645\u0643\u0646 \u0642\u0631\u0627\u0621\u0629 \u0627\u0633\u0645\u0627\u0621 \u0627\u0644\u0645\u062e\u0637\u0637 \u0645\u0646 \u0642\u0627\u0639\u062f\u0629 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a +select.at.least.a.schema = \u062d\u062f\u062f \u0645\u062e\u0637\u0637\u0627 \u0639\u0644\u0649 \u0627\u0644\u0623\u0642\u0644 +error.in.database.synchronization._ = {\u062e\u0637\u0623 \u0641\u064a \u0645\u0632\u0627\u0645\u0646\u0629 \u0642\u0627\u0639\u062f\u0629 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a: {0 +could.not.save.model._ = {\u062a\u0639\u0630\u0631 \u062d\u0641\u0638 \u0627\u0644\u0646\u0645\u0648\u0630\u062c: {0 +could.not.create.pages._ = {\u062a\u0639\u0630\u0631 \u0625\u0646\u0634\u0627\u0621 \u0627\u0644\u0635\u0641\u062d\u0627\u062a: {0 +couldnt.create.directory = {\u062a\u0639\u0630\u0631 \u0625\u0646\u0634\u0627\u0621 \u0627\u0644\u062f\u0644\u064a\u0644 {0 +directory.exists.page.not.created._ = ({\u0627\u0644\u062f\u0644\u064a\u0644 \u0645\u0648\u062c\u0648\u062f\u060c \u0644\u0645 \u064a\u062a\u0645 \u0625\u0646\u0634\u0627\u0621 \u0627\u0644\u0635\u0641\u062d\u0629 ({0 +couldnt.set.up.user.management._ = {\u062a\u0639\u0630\u0631 \u0625\u0639\u062f\u0627\u062f \u0625\u062f\u0627\u0631\u0629 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645\u064a\u0646: {0 +no.page.will.be.generated =\u0644\u0646 \u064a\u062a\u0645 \u0625\u0646\u0634\u0627\u0621 \u0623\u064a\u0629 \u0635\u0641\u062d\u0629 +schema._.was.already.configured = \u062a\u0645 \u0628\u0627\u0644\u0641\u0639\u0644 \u062a\u0647\u064a\u0626\u0629 \u0627\u0644\u0645\u062e\u0637\u0637 {0}: \u0644\u0646 \u064a\u062a\u0645 \u062a\u062d\u062f\u064a\u062b \u0627\u0644\u0635\u0641\u062d\u0627\u062a \u0627\u0644\u062d\u0627\u0644\u064a\u0629 + +use.an.existing.database.connection = \u0627\u0633\u062a\u062e\u062f\u0627\u0645 \u0627\u062a\u0635\u0627\u0644 \u0642\u0627\u0639\u062f\u0629 \u0628\u064a\u0627\u0646\u0627\u062a \u0645\u0648\u062c\u0648\u062f +or.create.a.new.one.choose.its.type = \u0623\u0648 \u0625\u0646\u0634\u0627\u0621 \u0648\u0627\u062d\u062f \u062c\u062f\u064a\u062f (\u0627\u062e\u062a\u0631 \u0646\u0648\u0639\u0647): +create.a.new.connection.choose.type = \u0625\u0646\u0634\u0627\u0621 \u0627\u062a\u0635\u0627\u0644 \u062c\u062f\u064a\u062f (\u0627\u062e\u062a\u0631 \u0627\u0644\u0646\u0648\u0639): +found.schemas = \u0627\u0644\u0623\u0646\u0638\u0645\u0629 \u0627\u0644\u062a\u064a \u062a\u0645 \u0627\u0644\u0639\u062b\u0648\u0631 \u0639\u0644\u064a\u0647\u0627: +select.root.tables = \u062d\u062f\u062f \u062c\u062f\u0627\u0648\u0644 \u0627\u0644\u062c\u0630\u0631 + +users.and.groups.tables = \u062c\u062f\u0627\u0648\u0644 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645\u064a\u0646 \u0648\u0627\u0644\u0645\u062c\u0645\u0648\u0639\u0627\u062a + +note.restart.application = \u0645\u0644\u0627\u062d\u0638\u0647: \u064a\u062c\u0628 \u0627\u0639\u0627\u062f\u0629 \u062a\u0634\u063a\u064a\u0644 \u0647\u0630\u0627 \u0627\u0644\u062a\u0637\u0628\u064a\u0642 \u0644\u062a\u0641\u0639\u064a\u0644 \u0647\u0630\u0647 \u0627\u0644\u062e\u0635\u0627\u0626\u0635 +warning.change.mail.queue = \u0643\u0646 \u062d\u0630\u0631\u0627 \u0625\u0630\u0627 \u0642\u0645\u062a \u0628\u062a\u063a\u064a\u064a\u0631 \u0645\u0643\u0627\u0646 \u0642\u0627\u0626\u0645\u0629 \u0627\u0646\u062a\u0638\u0627\u0631 \u0627\u0644\u0628\u0631\u064a\u062f \u0623\u062b\u0646\u0627\u0621 \u0642\u064a\u0627\u0645 \u0627\u0644\u0646\u0638\u0627\u0645 \u0628\u0636\u0628\u0637 \u0627\u0644\u0628\u0631\u064a\u062f: \u0633\u062a\u062d\u062a\u0627\u062c \u0625\u0644\u0649 \ +\u00a0\u00a0\u00a0\u00a0 \u0646\u0642\u0644 \u0627\u0644\u0628\u0631\u064a\u062f \u063a\u064a\u0631 \u0627\u0644\u0645\u0631\u0633\u0644 \u064a\u062f\u0648\u064a\u0627 \u0625\u0644\u0649 \u0627\u0644\u0645\u0648\u0642\u0639 \u0627\u0644\u062c\u062f\u064a\u062f \u0639\u0646\u062f \u0625\u0639\u0627\u062f\u0629 \u062a\u0634\u063a\u064a\u0644 \u0627\u0644\u062a\u0637\u0628\u064a\u0642. +warning.configuring.user.management.will.overwrite = \u062a\u062d\u0630\u064a\u0631: \u0641\u0625\u0646 \u062a\u0647\u064a\u0626\u0629 \u0625\u062f\u0627\u0631\u0629 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645 \u0633\u062a\u0633\u062a\u0628\u062f\u0644 \u0627\u0644\u0643\u062a\u0627\u0628\u0629 \u0627\u0644\u062d\u0627\u0644\u064a\u0629 Security.groovy +if.you.want.more.control.on.password.encryption =\u0645\u0644\u0627\u062d\u0638\u0629: \u0625\u0630\u0627 \u0643\u0646\u062a \u062a\u0631\u064a\u062f \u0627\u0644\u0645\u0632\u064a\u062f \u0645\u0646 \u0627\u0644\u062a\u062d\u0643\u0645 \u0641\u064a \u062a\u0634\u0641\u064a\u0631 \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 \ +\u00a0\u00a0 (\u0627\u0644\u062a\u0645\u0644\u064a\u062d\u060c \u0648\u062a\u0643\u0631\u0627\u0631 \u062a\u062c\u0632\u0626\u0629 \u0645\u062a\u0639\u062f\u062f\u0629\u060c \u062e\u0648\u0627\u0631\u0632\u0645\u064a\u0627\u062a \u0645\u062e\u062a\u0644\u0641\u0629) \u064a\u0645\u0643\u0646\u0643 \u062a\u062d\u0631\u064a\u0631 \u064a\u062f\u0648\u064a\u0627 Security.groovy afterwards, which \ + already provides the necessary hooks. +users.table.setup = \u0625\u0639\u062f\u0627\u062f \u062c\u062f\u0648\u0644 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645\u064a\u0646 +users.table = \u062c\u062f\u0648\u0644 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645\u064a\u0646 +password.encryption.algorithm = \u062e\u0648\u0627\u0631\u0632\u0645\u064a\u0629 \u062a\u0634\u0641\u064a\u0631 \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 +plain.text = \u0646\u0635 \u0639\u0627\u062f\u064a +md5.base64.encoded = MD5 (Base64 encoded) +md5.hex.encoded = MD5 (Hex encoded) +sha1.base64.encoded.portofino3 = SHA-1 (Base64 encoded) - Portofino 3 +sha1.hex.encoded = SHA-1 (Hex encoded) +sha256.base64.encoded=SHA-256 (Base64 encoded) +sha256.hex.encoded=SHA-256 (Hex encoded) +user.id.property = \u062e\u0635\u0627\u0626\u0635 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645 +username.property = \u062e\u0635\u0627\u0626\u0635 \u0627\u0633\u0645 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645 +password.property = \u062e\u0635\u0627\u0626\u0635 \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 +email.property = \u062e\u0635\u0627\u0626\u0635 \u0627\u0644\u0627\u064a\u0645\u064a\u0644 +token.property = \u062e\u0635\u0627\u0626\u0635 \u0627\u0644\u0631\u0645\u0632 +groups.tables.setup = \u0627\u0639\u062f\u0627\u062f \u062c\u062f\u0627\u0648\u0644 \u0627\u0644\u0645\u062c\u0645\u0648\u0639\u0627\u062a +groups.table = \u062c\u062f\u0627\u0648\u0644 \u0627\u0644\u0645\u062c\u0645\u0648\u0639\u0627\u062a +name.of.the.administrators.group = \u0627\u0633\u0645 \u0645\u062c\u0645\u0648\u0639\u0629 \u0627\u0644\u0645\u0634\u0631\u0641\u064a\u0646 +user-group.join.table = \u062c\u062f\u0648\u0644 \u0645\u062c\u0645\u0648\u0639\u0629 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645\u064a\u0646 +property.that.links.to.user = \u0627\u0644\u0645\u0644\u0643\u064a\u0629 \u0627\u0644\u062a\u064a \u062a\u0631\u0628\u0637 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645 +property.that.links.to.group = \u0627\u0644\u062e\u0627\u0635\u064a\u0629 \u0627\u0644\u062a\u064a \u062a\u0631\u0628\u0637 \u0625\u0644\u0649 \u0627\u0644\u0645\u062c\u0645\u0648\u0639\u0629 +select.the.generation.strategy = \u062d\u062f\u062f \u0627\u0644\u0627\u0633\u062a\u0631\u0627\u062a\u064a\u062c\u064a\u0629 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645\u0629 \u0644\u0625\u0646\u0634\u0627\u0621 \u0627\u0644\u0635\u0641\u062d\u0627\u062a: +dont.generate.anything = \u0644\u0627 \u062a\u0648\u0644\u062f \u0623\u064a \u0634\u064a\u0621 +automatic = \u062a\u0644\u0642\u0627\u0626\u064a +manual.choose.which.pages.will.be.created = \u062f\u0644\u064a\u0644 (\u062a\u062d\u062f\u064a\u062f \u0627\u0644\u0635\u0641\u062d\u0627\u062a \u0627\u0644\u062a\u064a \u0633\u064a\u062a\u0645 \u0625\u0646\u0634\u0627\u0624\u0647\u0627) +generate.a.calendar.page = \u0625\u0646\u0634\u0627\u0621 \u0635\u0641\u062d\u0629 \u062a\u0642\u0648\u064a\u0645 + +press.finish.to.build.the.application = \u0627\u0636\u063a\u0637 \u0639\u0644\u0649 \u0625\u0646\u0647\u0627\u0621 \u0644\u0628\u0646\u0627\u0621 \u0627\u0644\u062a\u0637\u0628\u064a\u0642. \ +\u00a0\u00a0 \u0642\u062f \u062a\u0633\u062a\u063a\u0631\u0642 \u0647\u0630\u0647 \u0627\u0644\u0639\u0645\u0644\u064a\u0629 \u0639\u062f\u0629 \u062f\u0642\u0627\u0626\u0642 \u0644\u0625\u0643\u0645\u0627\u0644\u0647\u0627. +application.created = \ + \u062a\u0645 \u0625\u0646\u0634\u0627\u0621 \u0627\u0644\u062a\u0637\u0628\u064a\u0642 \u0627\u0644\u0622\u0646 \u062a\u0635\u0641\u062d \u0648\u062a\u062e\u0635\u064a\u0635 \u0630\u0644\u0643! \u062a\u0630\u0643\u0631 \u0623\u0646 \u0627\u0644\u0645\u0639\u0627\u0644\u062c \u0647\u0648 \u0645\u062c\u0631\u062f \u0646\u0642\u0637\u0629 \u0627\u0646\u0637\u0644\u0627\u0642\u060c \u0648\u0647\u0646\u0627\u0643 \ + \u0623\u0643\u062b\u0631 \u0645\u0646 \u0630\u0644\u0643 \u0628\u0643\u062b\u064a\u0631 \u0641\u064a \u0628\u0648\u0631\u062a\u0648\u0641\u064a\u0646\u0648! \u0642\u062f \u062a\u062c\u062f \u062a\u0648\u062b\u064a\u0642 \ + \u0645\u0641\u064a\u062f. +user.management.has.been.configured.please.edit.security.groovy = \ + \u062a\u0645\u062a \u062a\u0647\u064a\u0626\u0629 \u0625\u062f\u0627\u0631\u0629 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645. \u064a\u0631\u062c\u0649 \u062a\u0639\u062f\u064a\u0644 \u0648\u0644\u062f\u062a Security.groovy \ + \u0645\u0644\u0641 \u0644\u062a\u0646\u0627\u0633\u0628 \u0627\u0644\u0628\u064a\u0626\u0629 \u0627\u0644\u062e\u0627\u0635\u0629 \u0628\u0643 \u0648\u0625\u0632\u0627\u0644\u0629 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645 \u0627\u0644\u0645\u0633\u0624\u0648\u0644 \u0627\u0644\u0645\u0634\u0641\u0631\u0629 \u0644\u0644\u0645\u0639\u0627\u0644\u062c. \ +\u00a0\u00a0 \u0644\u0642\u062f \u062a\u0645 \u062a\u0633\u062c\u064a\u0644 \u062e\u0631\u0648\u062c\u0643 \u062a\u0644\u0642\u0627\u0626\u064a\u0627 \u0645\u0646 \u0627\u0644\u0646\u0638\u0627\u0645. \u064a\u0631\u062c\u0649 \u062a\u0633\u062c\u064a\u0644 \u0627\u0644\u062f\u062e\u0648\u0644 \u0645\u0631\u0629 \u0623\u062e\u0631\u0649. + +step._ = \u062e\u0637\u0648\u0647 {0} +connect.to.your.database = \u0627\u0644\u0627\u062a\u0635\u0627\u0644 \u0628\u0642\u0627\u0639\u062f\u0629 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a +select.the.database.schemas.to.import = \u062d\u062f\u062f \u0645\u062e\u0637\u0637 (\u0642\u0648\u0627\u0639\u062f) \u0642\u0627\u0639\u062f\u0629 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a \u0644\u0644\u0627\u0633\u062a\u064a\u0631\u0627\u062f +set.up.user.management = \u0625\u0639\u062f\u0627\u062f \u0625\u062f\u0627\u0631\u0629 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645\u064a\u0646 +customize.user.management = \u062a\u062e\u0635\u064a\u0635 \u0625\u062f\u0627\u0631\u0629 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645 +generate.pages = \u0625\u0646\u0634\u0627\u0621 \u0635\u0641\u062d\u0627\u062a +build.the.application = \u0628\u0646\u0627\u0621 \u0627\u0644\u062a\u0637\u0628\u064a\u0642! +reset.groovy.script.engine = \u0625\u0639\u0627\u062f\u0629 \u062a\u0639\u064a\u064a\u0646 \u0645\u062d\u0631\u0643 \u0627\u0644\u0628\u0631\u0646\u0627\u0645\u062c \u0627\u0644\u0646\u0635\u064a \u0631\u0627\u0626\u0639 +layouts.admin.groovy.text = \u0625\u0639\u0627\u062f\u0629 \u062a\u062d\u0645\u064a\u0644 \u0627\u0644\u0637\u0628\u0642\u0627\u062a \u063a\u0631\u0648\u0641\u064a \u062f\u0648\u0646 \u0625\u0639\u0627\u062f\u0629 \u062a\u0634\u063a\u064a\u0644 \u0627\u0644\u0645\u0644\u0642\u0645. \u0623\u064a\u0636\u0627 \u0645\u062e\u0627\u0628\u0626 \u0648\u0627\u0636\u062d\u0629 (e.g. in OGNL) \ + \u0648\u0627\u0644\u062a\u064a \u0642\u062f \u062a\u062d\u0645\u0644 \u0625\u0635\u062f\u0627\u0631\u0627\u062a \u0642\u062f\u064a\u0645\u0629 \u0645\u0646 \u0627\u0644\u0637\u0628\u0642\u0627\u062a \u063a\u0631\u0648\u0641\u064a\u060c \u0648\u0645\u0646\u0639 \u062c\u0645\u0639 \u0627\u0644\u0642\u0645\u0627\u0645\u0629 \u0648\u062a\u0633\u0628\u0628 \u0627\u0644\u0627\u0633\u062a\u062b\u0646\u0627\u0621\u0627\u062a. +script.engine.successfully.reset = \u0645\u062d\u0631\u0643 \u0627\u0644\u0646\u0635\u064a \u0625\u0639\u0627\u062f\u0629 \u062a\u0639\u064a\u064a\u0646 \u0628\u0646\u062c\u0627\u062d +configuration = \u062a\u0631\u062a\u064a\u0628 +modules = \u0648\u062d\u062f\u0627\u062a +servlet.context = \u0633\u064a\u0627\u0642 \u0633\u064a\u0631\u0641\u0644\u064a\u062a +security = \u0623\u0645\u0646 +data.modeling = \u0646\u0645\u0630\u062c\u0629 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a +wizard = Wizard +connection.providers = \u0645\u0632\u0648\u062f\u064a \u0627\u0644\u0627\u062a\u0635\u0627\u0644 +tables = \u062c\u062f\u0627\u0648\u0644 +reload.model = \u0625\u0639\u0627\u062f\u0629 \u062a\u062d\u0645\u064a\u0644 \u0627\u0644\u0646\u0645\u0648\u0630\u062c +mail = \u0627\u064a\u0645\u064a\u0644 +groovy = Groovy +info = \u0645\u0639\u0644\u0648\u0645\u0627\u062a +info.portofino.intro = \u0628\u0648\u0631\u062a\u0648\u0641\u064a\u0646\u0648 \u0647\u0648 \u0645\u0646\u0635\u0629 \u062d\u0631\u0629 \u0648\u0645\u0641\u062a\u0648\u062d\u0629 \u0627\u0644\u0645\u0635\u062f\u0631 \u0639\u0644\u0649 \u0634\u0628\u0643\u0629 \u0627\u0644\u0625\u0646\u062a\u0631\u0646\u062a \u0627\u0644\u062a\u064a \u062a\u0633\u0627\u0639\u062f \u0627\u0644\u0645\u0637\u0648\u0631\u064a\u0646 \u062e\u0644\u0642 \u0627\u0644\u0623\u0639\u0645\u0627\u0644 \u0627\u0644\u0645\u0639\u0644\u0642\u0629 \ + \u0627\u0644\u062a\u0637\u0628\u064a\u0642\u0627\u062a \u0645\u0646 \u062e\u0644\u0627\u0644 \u0645\u0639\u0627\u0644\u062c\u0629 \u062b\u0644\u0627\u062b\u0629 \u0627\u062d\u062a\u064a\u0627\u062c\u0627\u062a \u0645\u062d\u062f\u062f\u0629: \u0627\u0644\u0625\u0646\u062a\u0627\u062c\u064a\u0629 \u0648\u0627\u0644\u0645\u064a\u0632\u0627\u062a \u0648\u0627\u0644\u0647\u0646\u062f\u0633\u0629 \u0627\u0644\u0645\u0639\u0645\u0627\u0631\u064a\u0629. +info.portofino.features = \u0645\u0646 \u0628\u064a\u0646 \u0645\u0639\u0627\u0644\u0645\u0647: \u0625\u062f\u0627\u0631\u0629 \u0627\u0644\u0645\u062d\u062a\u0648\u0649\u060c \u0643\u0631\u0648\u062f\u060c \u0627\u062a\u0635\u0627\u0644 \u0642\u0627\u0639\u062f\u0629 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a\u060c \u0648\u0627\u0644\u062a\u0642\u0648\u064a\u0645\u0627\u062a\u060c \u0648\u0627\u0644\u0631\u0633\u0648\u0645 \u0627\u0644\u0628\u064a\u0627\u0646\u064a\u0629 \u0648\u0627\u0644\u0623\u0645\u0646 \u0648\u0627\u0644\u062a\u062e\u0635\u064a\u0635 \u0633\u0647\u0644\u0629 \u0628\u0627\u0633\u062a\u062e\u062f\u0627\u0645 \u0631\u0627\u0626\u0639. +content.type.property = \u062e\u0627\u0635\u064a\u0629 \u0646\u0648\u0639 \u0627\u0644\u0645\u062d\u062a\u0648\u0649 +file.name.property = \u0627\u0633\u0645 \u0645\u0644\u0641 \u0627\u0644\u062e\u0627\u0635\u064a\u0629 +timestamp.property = \u062e\u0627\u0635\u064a\u0629 \u0627\u0644\u0637\u0627\u0628\u0639 \u0627\u0644\u0632\u0645\u0646\u064a +filter = \u0645\u0631\u0634\u062d +og.out= \u062a\u0633\u062c\u064a\u0644 \u0627\u0644\u062e\u0631\u0648\u062c +ok = Ok +login= \u062a\u0633\u062c\u064a\u0644 \u0627\u0644\u062f\u062e\u0648\u0644 +update= \u062a\u062d\u062f\u064a\u062b +object.updated.successfully = \u062a\u0645 \u062a\u062d\u062f\u064a\u062b \u0627\u0644\u0643\u0627\u0626\u0646 \u0628\u0646\u062c\u0627\u062d +update.failed = \u0641\u0634\u0644 \u0627\u0644\u062a\u062d\u062f\u064a\u062b +cancel= \u0627\u0644\u063a\u0627\u0621 +create.new= \u0627\u0646\u0634\u0627\u0621 \u062c\u062f\u064a\u062f +delete= \u062d\u0630\u0641 +edit = \u062a\u0639\u062f\u064a\u0644 +test = \u062a\u062c\u0631\u0628\u0647 +return.to.pages= \u0627\u0644\u0639\u0648\u062f\u0647 \u0627\u0644\u0649 \u0627\u0644\u0635\u0641\u062d\u0627\u062a +login.to=\u062a\u0633\u062c\u064a\u0644 \u0627\u0644\u062f\u062e\u0648\u0644 \u0625\u0644\u0649 {0} +user.name= \u0627\u0633\u0645 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645 +email= \u0627\u0644\u0627\u064a\u0645\u064a\u0644 +password= \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 +remember.me.on.this.computer=\u062a\u0630\u0643\u0631\u0646\u064a \u0639\u0644\u0649 \u0647\u0630\u0627 \u0627\u0644\u0643\u0645\u0628\u064a\u0648\u062a\u0631 +current.password= \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 \u0627\u0644\u062d\u0627\u0644\u064a\u0629 +new.password= \u0643\u0644\u0645\u0629 \u0645\u0631\u0648\u0631 \u062c\u062f\u064a\u062f\u0647 +confirm.new.password=\u062a\u0623\u0643\u064a\u062f \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 \u0627\u0644\u062c\u062f\u064a\u062f\u0629 +forgot.your.password=\u0647\u0644 \u0646\u0633\u064a\u062a \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631\u061f +sign.up = \u0627\u0644\u062a\u0633\u062c\u064a\u0644 +please.type.the.text.shown.in.the.image = \u0627\u0644\u0631\u062c\u0627\u0621 \u0643\u062a\u0627\u0628\u0629 \u0627\u0644\u0646\u0635 \u0627\u0644\u0638\u0627\u0647\u0631 \u0639\u0644\u0649 \u0627\u0644\u0635\u0648\u0631\u0647 +wrong.text = \u0646\u0635 \u062e\u0627\u0637\u0626 +this.page.is.not.correctly.configured = \u0644\u0645 \u062a\u062a\u0645 \u062a\u0647\u064a\u0626\u0629 \u0647\u0630\u0647 \u0627\u0644\u0635\u0641\u062d\u0629 \u0628\u0634\u0643\u0644 \u0635\u062d\u064a\u062d. + +#User management +user._.logged.in.successfully = \u062a\u0645 \u062a\u0633\u062c\u064a\u0644 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645 {0} \u0628\u0646\u062c\u0627\u062d +login.failed.for.user._ = \u0641\u0634\u0644 \u062a\u0633\u062c\u064a\u0644 \u0627\u0644\u062f\u062e\u0648\u0644 \u0644\u0644\u0645\u0633\u062a\u062e\u062f\u0645 {0} +user._.is.not.active = \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645 {0} \u063a\u064a\u0631 \u0646\u0634\u0637. \u064a\u0631\u062c\u0649 \u0627\u0644\u0627\u062a\u0635\u0627\u0644 \u0628\u0627\u0644\u0645\u0634\u0631\u0641. +user.disconnected = \u062a\u0645 \u0642\u0637\u0639 \u0627\u062a\u0635\u0627\u0644 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645 +password.successfully.reset = \u062a\u0645\u062a \u0625\u0639\u0627\u062f\u0629 \u062a\u0639\u064a\u064a\u0646 \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 \u0628\u0646\u062c\u0627\u062d. +password.reset.failed = \u0641\u0634\u0644 \u0627\u0639\u0627\u062f\u0629 \u062a\u0639\u064a\u064a\u0646 \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 +the.password.reset.link.is.no.longer.active = \u0644\u0645 \u064a\u0639\u062f \u0631\u0627\u0628\u0637 \u0625\u0639\u0627\u062f\u0629 \u062a\u0639\u064a\u064a\u0646 \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 \u0627\u0644\u0630\u064a \u062a\u062a\u0627\u0628\u0639\u0647 \u0646\u0634\u0637\u0627. \u064a\u0631\u062c\u0649 \u0625\u0635\u062f\u0627\u0631 \u062c\u062f\u064a\u062f \ +\u00a0\u00a0 \u0637\u0644\u0628 \u0625\u0639\u0627\u062f\u0629 \u062a\u0639\u064a\u064a\u0646 \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631. +check.your.mailbox.and.follow.the.instructions = \u062a\u062d\u0642\u0642 \u0645\u0646 \u0635\u0646\u062f\u0648\u0642 \u0627\u0644\u0628\u0631\u064a\u062f \u0648\u0627\u062a\u0628\u0639 \u0627\u0644\u0625\u0631\u0634\u0627\u062f\u0627\u062a +user.created = \u062a\u0645 \u0625\u0646\u0634\u0627\u0621 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645 +signup.failed = \u0641\u0634\u0644 \u0627\u0644\u062a\u0633\u062c\u064a\u0644 +a.user.with.the.same.username.already.exists = \u064a\u0648\u062c\u062f \u0628\u0627\u0644\u0641\u0639\u0644 \u0645\u0633\u062a\u062e\u062f\u0645 \u064a\u062d\u0645\u0644 \u0646\u0641\u0633 \u0627\u0633\u0645 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645 \u0623\u0648 \u0627\u0644\u0628\u0631\u064a\u062f \u0627\u0644\u0625\u0644\u0643\u062a\u0631\u0648\u0646\u064a \u0641\u064a \u0627\u0644\u0646\u0638\u0627\u0645. +please.correct.the.errors.before.proceeding = \u064a\u0631\u062c\u0649 \u062a\u0635\u062d\u064a\u062d \u0627\u0644\u0623\u062e\u0637\u0627\u0621 \u0642\u0628\u0644 \u0627\u0644\u0645\u062a\u0627\u0628\u0639\u0629 +the.sign.up.confirmation.link.is.no.longer.active = \u0644\u0645 \u064a\u0639\u062f \u0631\u0627\u0628\u0637 \u062a\u0623\u0643\u064a\u062f \u0627\u0644\u0627\u0634\u062a\u0631\u0627\u0643 \u0627\u0644\u0630\u064a \u062a\u062a\u0627\u0628\u0639\u0647 \u0646\u0634\u0637\u0627. \u064a\u0631\u062c\u0649 \u0625\u0635\u062f\u0627\u0631 \u062c\u062f\u064a\u062f \ +\u00a0\u00a0 \u0637\u0644\u0628 \u0627\u0644\u0627\u0634\u062a\u0631\u0627\u0643 +confirm.signup = \u062a\u0623\u0643\u064a\u062f \u0627\u0644\u0627\u0634\u062a\u0631\u0627\u0643 +password.changed.successfully = \u062a\u0645 \u062a\u063a\u064a\u064a\u0631 \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 \u0628\u0646\u062c\u0627\u062d +password.change.failed = \u0641\u0634\u0644 \u062a\u063a\u064a\u064a\u0631 \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 +wrong.password = \u0643\u0644\u0645\u0629 \u0645\u0631\u0648\u0631 \u062e\u0627\u0637\u0626\u0629 +passwords.dont.match = \u0643\u0644\u0645\u0627\u062a \u0627\u0644\u0645\u0631\u0648\u0631 \u063a\u064a\u0631 \u0645\u062a\u0637\u0627\u0628\u0642\u0629 +password.reset.confirmation.required = \u0627\u0639\u0627\u062f\u0629 \u062a\u0639\u064a\u064a\u0646 \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 : \u0627\u0644\u062a\u0627\u0643\u064a\u062f \u0645\u0637\u0644\u0648\u0628\u0647 +dont.have.an.account=\u0644\u064a\u0633 \u0644\u062f\u064a\u0643 \u062d\u0633\u0627\u0628\u061f +sign.up.now=\u0627\u0634\u062a\u0631\u0643 \u0627\u0644\u0622\u0646 +null.password = \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 \u0627\u0644\u0641\u0627\u0631\u063a\u0629 +password.too.short = \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 \u0642\u0635\u064a\u0631\u0629 \u062c\u062f\u0627 (\u064a\u062c\u0628 \u0623\u0644\u0627 \u064a\u0642\u0644 \u0637\u0648\u0644\u0647\u0627 \u0639\u0646 {0} \u062d\u0631\u0641\u0627) +password.only.letters = \u062a\u062d\u062a\u0648\u064a \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 \u0639\u0644\u0649 \u0623\u062d\u0631\u0641 \u0641\u0642\u0637 +password.spam.filter =\u0625\u0630\u0627 \u0644\u0645 \u062a\u062a\u0644\u0642 \u0628\u0631\u064a\u062f\u0627 \u0625\u0644\u0643\u062a\u0631\u0648\u0646\u064a\u0627 \u0645\u0646\u0627 \u062e\u0644\u0627\u0644 \u0628\u0636\u0639 \u062f\u0642\u0627\u0626\u0642\u060c \u0641\u064a\u0631\u062c\u0649 \u0627\u0644\u062a\u062d\u0642\u0642 \u0645\u0646 \u0641\u0644\u062a\u0631 \u0627\u0644\u0631\u0633\u0627\u0626\u0644 \u063a\u064a\u0631 \u0627\u0644\u0645\u0631\u063a\u0648\u0628 \u0641\u064a\u0647\u0627. \u0633\u0648\u0641 \u0646\u0631\u0633\u0644 \u0644\u0643 \u0631\u0633\u0627\u0626\u0644 \u0625\u0644\u0643\u062a\u0631\u0648\u0646\u064a\u0629 \u0645\u0646 \u0627\u0644\u0639\u0646\u0648\u0627\u0646 \u0627\u0644\u062a\u0627\u0644\u064a: {0} +password.resend = \u0623\u062f\u062e\u0644 \u0639\u0646\u0648\u0627\u0646 \u0628\u0631\u064a\u062f\u0643 \u0627\u0644\u0625\u0644\u0643\u062a\u0631\u0648\u0646\u064a \u0623\u062f\u0646\u0627\u0647 \u0648\u0633\u0646\u0631\u0633\u0644 \u0625\u0644\u064a\u0643 \u062a\u0639\u0644\u064a\u0645\u0627\u062a \u0625\u0639\u0627\u062f\u0629 \u062a\u0639\u064a\u064a\u0646 \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631. + +#Default number format +elements.fields.format.decimal=#.# +log.in= \u062a\u0633\u062c\u064a\u0644 \u062f\u062e\u0648\u0644 +this.page.has.thrown.an.exception.during.execution = \u0647\u0630\u0647 \u0627\u0644\u0635\u0641\u062d\u0629 \u0642\u062f \u0623\u0644\u0642\u064a\u062a \u0627\u0633\u062a\u062b\u0646\u0627\u0621 \u0623\u062b\u0646\u0627\u0621 \u0627\u0644\u062a\u0646\u0641\u064a\u0630 ({0}). \u0647\u0630\u0627 \u0627\u0644\u0633\u062c\u0644 \u0644\u0644\u062d\u0635\u0648\u0644 \u0639\u0644\u0649 \u0627\u0644\u062a\u0641\u0627\u0635\u064a\u0644. +this.page.has.thrown.an.exception.during.rendering = \u0647\u0630\u0647 \u0627\u0644\u0635\u0641\u062d\u0629 ({0}) \u0623\u0644\u0642\u064a\u062a \u0627\u0633\u062a\u062b\u0646\u0627\u0621 \u0623\u062b\u0646\u0627\u0621 \u0627\u0644\u0639\u0631\u0636. \u0647\u0630\u0627 \u0627\u0644\u0633\u062c\u0644 \u0644\u0644\u062d\u0635\u0648\u0644 \u0639\u0644\u0649 \u0627\u0644\u062a\u0641\u0627\u0635\u064a\u0644. +settings = \u0625\u0639\u062f\u0627\u062f\u0627\u062a + +#Page configuration +configure=\u062a\u0643\u0648\u064a\u0646 +update.configuration=\u062a\u062d\u062f\u064a\u062b \u0627\u0644\u062a\u0643\u0648\u064a\u0646 +configuration.updated.successfully =\u062a\u0645 \u062a\u062d\u062f\u064a\u062b \u0627\u0644\u062a\u0647\u064a\u0626\u0629 \u0628\u0646\u062c\u0627\u062d +the.configuration.could.not.be.saved = \u062a\u0639\u0630\u0631 \u062d\u0641\u0638 \u0627\u0644\u062a\u0647\u064a\u0626\u0629. \u0631\u0627\u062c\u0639 \u0623\u064a\u0629 \u0623\u062e\u0637\u0627\u0621 \u0623\u062f\u0646\u0627\u0647 \u0648\u0623\u0631\u0633\u0644\u0647\u0627 \u0645\u0631\u0629 \u0623\u062e\u0631\u0649. +configure.page._ =\u062a\u0647\u064a\u0626\u0629 \u0627\u0644\u0635\u0641\u062d\u0629: {0} +edit.page._ = \u062a\u0639\u062f\u064a\u0644 \u0627\u0644\u0635\u0641\u062d\u0629: {0} +id = \u0627\u0644\u0647\u0648\u064a\u0629 +title = \u0627\u0644\u0639\u0646\u0648\u0627\u0646 +description = \u0648\u0635\u0641 +embed.in.parent = \u062a\u0636\u0645\u064a\u0646 \u0641\u064a \u0627\u0644\u0623\u0635\u0644\u061f +show.in.navigation = \u0639\u0631\u0636 \u0641\u064a \u0627\u0644\u0645\u0644\u0627\u062d\u0629\u061f +navigation.root = Navigation root +inherit = Inherit +root = Root +ghost.root = Ghost root +template = \u0642\u0627\u0644\u0628 +detail.template = \u062a\u0641\u0627\u0635\u064a\u0644 \u0627\u0644\u0642\u0627\u0644\u0628 +apply.template.recursively = \u062a\u0637\u0628\u064a\u0642 \u0627\u0644\u0642\u0627\u0644\u0628 \u0628\u0634\u0643\u0644 \u0645\u062a\u0643\u0631\u0631 + +#Scripting +couldnt.compile.script = \u0644\u0627 \u064a\u0645\u0643\u0646 \u062a\u062c\u0645\u064a\u0639 \u0627\u0644\u0628\u0631\u0646\u0627\u0645\u062c \u0627\u0644\u0646\u0635\u064a - \u0627\u0646\u0638\u0631 \u0633\u062c\u0644\u0627\u062a \u0644\u0644\u062d\u0635\u0648\u0644 \u0639\u0644\u0649 \u0627\u0644\u062a\u0641\u0627\u0635\u064a\u0644 +couldnt.write.script.to._ = \u0644\u0627 \u064a\u0645\u0643\u0646 \u0643\u062a\u0627\u0628\u0629 \u0627\u0644\u0646\u0635 \u0627\u0644\u0628\u0631\u0645\u062c\u064a \u0625\u0644\u0649 {0} - \u0631\u0627\u062c\u0639 \u0633\u062c\u0644\u0627\u062a \u0644\u0644\u062d\u0635\u0648\u0644 \u0639\u0644\u0649 \u0627\u0644\u062a\u0641\u0627\u0635\u064a\u0644 +script.class.is.not.valid = \u0641\u0626\u0629 \u0627\u0644\u0646\u0635 \u0627\u0644\u0628\u0631\u0645\u062c\u064a \u063a\u064a\u0631 \u0635\u0627\u0644\u062d\u0629. \u0647\u0630\u0627 \u0627\u0644\u0633\u062c\u0644 \u0644\u0644\u062d\u0635\u0648\u0644 \u0639\u0644\u0649 \u0627\u0644\u062a\u0641\u0627\u0635\u064a\u0644. + +#Common +first = \u0627\u0644\u0627\u0648\u0644 +last = \u0627\u0644\u0627\u062e\u064a\u0631 +submit = Submit + +#Text action +browse = \u062a\u0635\u0641\u062d +browse.server = \u062a\u0635\u0641\u062d \u0627\u0644\u062e\u0627\u062f\u0645 +pages = \u0627\u0644\u0635\u0641\u062d\u0627\u062a +there.are.no.attachments = \u0644\u0627 \u062a\u0648\u062c\u062f \u0645\u0631\u0641\u0642\u0627\u062a +close.window = \u063a\u0644\u0642 \u0627\u0644\u0646\u0627\u0641\u0630\u0647 +edit.content = \u062a\u0639\u062f\u064a\u0644 \u0627\u0644\u0645\u062d\u062a\u0648\u0649 +edit.header = Edit header +manage.attachments = \u0625\u062f\u0627\u0631\u0629 \u0627\u0644\u0645\u0631\u0641\u0642\u0627\u062a +manage.attachments.for.page._ = {\u0625\u062f\u0627\u0631\u0629 \u0627\u0644\u0645\u0631\u0641\u0642\u0627\u062a \u0644\u0644\u0635\u0641\u062d\u0629: {0 +upload.a.new.file = \u062a\u062d\u0645\u064a\u0644 \u0645\u0644\u0641 \u062c\u062f\u064a\u062f +downloadable = \u0644\u0644\u062a\u062d\u0645\u064a\u0644 +delete.selected.attachments = \u0647\u0644 \u062a\u0631\u064a\u062f \u062d\u0630\u0641 \u0627\u0644\u0645\u0631\u0641\u0642\u0627\u062a \u0627\u0644\u0645\u062d\u062f\u062f\u0629\u061f +permission.text.edit = \u062a\u0639\u062f\u064a\u0628\u0644 \u0627\u0644\u0645\u062d\u062a\u0648\u0649 +text.attachment.upload = \u0631\u0641\u0639 +text.attachment.noFileSelected = \u0644\u0645 \u064a\u062a\u0645 \u062a\u062d\u062f\u064a\u062f \u0645\u0644\u0641 \u0644\u0644\u062a\u062d\u0645\u064a\u0644 +text.attachment.uploadSuccessful = \u062a\u0645 \u062a\u062d\u0645\u064a\u0644 \u0627\u0644\u0645\u0644\u0641 \u0628\u0646\u062c\u0627\u062d +text.attachment.uploadFailed = \u0641\u0634\u0644 \u0631\u0641\u0639 \u0627\u0644\u0645\u0644\u0641 +text.attachment.noAttachmentSelected = \u0644\u0645 \u064a\u062a\u0645 \u062a\u062d\u062f\u064a\u062f \u0623\u064a\u0629 \u0645\u0631\u0641\u0642\u0627\u062a +text.attachment.oneDeleted = \u062a\u0645 \u062d\u0630\u0641 \u0645\u0631\u0641\u0642 \u0648\u0627\u062d\u062f \u0628\u0646\u062c\u0627\u062d +text.attachment.nDeleted = \u062a\u0645 \u062d\u0630\u0641 \u0627\u0644\u0645\u0631\u0641\u0642\u0627\u062a {0} \u0628\u0646\u062c\u0627\u062d +title.cannot.be.empty =\u0644\u0627 \u064a\u0645\u0643\u0646 \u0623\u0646 \u064a\u0643\u0648\u0646 \u0627\u0644\u0639\u0646\u0648\u0627\u0646 \u0641\u0627\u0631\u063a\u0627 +change.password = \u062a\u063a\u064a\u064a\u0631 \u0643\u0644\u0645\u0629 \u0627\u0644\u0633\u0631 \ No newline at end of file diff --git a/portofino-pageactions/src/main/resources/portofino-messages_es.properties b/portofino-pageactions/src/main/resources/portofino-messages_es.properties index d6e2929824..a2917cc85f 100644 --- a/portofino-pageactions/src/main/resources/portofino-messages_es.properties +++ b/portofino-pageactions/src/main/resources/portofino-messages_es.properties @@ -46,6 +46,6 @@ there.are.no.attachments=No hay adjuntos this.page.has.thrown.an.exception.during.execution=Ha ocurrido un error durante la ejecuci\u00F3n de la p\u00E1gina ({0}). Revisa los logs para m\u00E1s detalles. this.page.has.thrown.an.exception.during.rendering=Ha ocurrido un error al renderizar la p\u00E1gina ({0}). Revisa los logs para m\u00E1s detalles. title=T\u00EDtulo -title.cannot.be.empty=El t\u00EDtulo no puede estar vacio. +title.cannot.be.empty=El t\u00EDtulo no puede estar vacio update.configuration=Actualizar documentaci\u00F3n upload.a.new.file=Cargar un fichero nuevo \ No newline at end of file diff --git a/portofino-pageactions/src/main/resources/portofino-messages_fr.properties b/portofino-pageactions/src/main/resources/portofino-messages_fr.properties new file mode 100644 index 0000000000..641da7c02a --- /dev/null +++ b/portofino-pageactions/src/main/resources/portofino-messages_fr.properties @@ -0,0 +1,170 @@ +ok = Ok +login=Entrer +update=Mise \u00E0 jour +object.updated.successfully = Objet modifi\u00E9 avec succ\u00E8s +update.failed = Sauvegarder a \u00E9chou\u00E9 +cancel= Annuler +create.new = Cr\u00E9er un nouveau +delete = Supprimer +edit = Modifier +test = Essai +return.to.pages = Retour aux pages +login.to= Entrer au {0} +user.name=Utilisateur +email=Email +password=Mot de passe +remember.me.on.this.computer = Se souvenir de moi sur cet ordinateur +current.password= Mot de passe actuel +new.password = Nouveau mot de passe +confirm.new.password = Confermez nouveau mot de passe +forgot.your.password = Vous avez oubli\u00E9 votre mot de passe? +sign.up = Enregistr\u00E9 +please.type.the.text.shown.in.the.image = Entrez le texte figurant dans l''image +wrong.text = Texte incorrect +this.page.is.not.correctly.configured = Cette page n''est pas configur\u00E9 correctement. +modules = Modules +servlet.context = Servlet context + +#User management +user._.logged.in.successfully = L''utilisateur {0} a effectu\u00E9 son identification correctement +login.failed.for.user._ = identification \u00E9cheuer pour l''utilisateur {0} +user._.is.not.active = L''Utilisateur non est active. Contactez votre administrateur. +user.disconnected = Utilisateur d\u00E9connect\u00E9. +password.successfully.reset = Mot de passe r\u00E9initialiser correctement. +password.reset.failed = R\u00E9initialisation du mot de passe a \u00E9chou\u00E9 + +the.password.reset.link.is.no.longer.active = Le lien pour r\u00E9initialiser le mot de passe que vous avez suivi non est valable. S''il vous pla\u0094t,faite une nouvelle demande de r\u00E9initialisation du mot de passe. +check.your.mailbox.and.follow.the.instructions = V\u00E9rifiez votre bo\u0094te de r\u00E9ception email et suivez les instructions. +user.created = Utilisateur cr\u00E9\u00E9. +signup.failed = Enregistrement \u00E9chou\u00E9 . +a.user.with.the.same.username.already.exists = Il existe d\u00E9j\u00E0 un utilisateur avec le m\u00EAme nom ou le m\u00EAme email. +please.correct.the.errors.before.proceeding = Corriger les erreurs pour continuer. +the.sign.up.confirmation.link.is.no.longer.active = Le lien d''inscription que vous avez choisi est non valide. S''il vous pla\u0094t,faire un nouvelledemande d''inscription. +confirm.signup = Confermez votre inscription +password.changed.successfully = Mot de passe chang\u00E9 avec succ\u00E8s +password.change.failed = Changer le mot de passe a \u00E9chou\u00E9 +wrong.password = Mot de passe erron\u00E9 +passwords.dont.match = Les mots de passe ne correspondent pas +password.reset.confirmation.required = R\u00E9initialiser Mot de passe: demande de confirmation +dont.have.an.account = Vous n''\u00EAtes pas inscrit? +sign.up.now = Inscrivez-vous maintenant +null.password = Le mot de passe est vide +password.too.short = Le mot de passe est trop court (doit \u00EAtre au moins {0} caract\u00E8res) +password.only.letters = Le mot de passe contient que des lettres +password.spam.filter = Si vous ne recevez pas de courriel de notre part dans les prochaines minutes,v\u00E9rifier votre dossier spam. Les e-mails sont envoy\u00E9s \u00E0 l''adresse suivante: +password.resend = Entrez votre adresse e-mail ci-dessous et nous vous enverrons des instructions pour r\u00E9initialiser votre mot de passe. + +#Default number format +elements.fields.format.decimal=#.# + + +############################################################################################ +#CRUD +object.not.found._= Objet non trouv\u00E9: {0} +incorrect.field.type = Mod\u00E8le incorrect de champ +save.failed.because.constraint.violated = Sauvegarder a \u00E9chou\u00E9 en raison d''une contrainte viol\u00E9e. +object._.saved = L''objet {0} a \u00E9t\u00E9 sauvegarder . +create.another.object = Cr\u00E9er un autre objet +update.of._.objects.successful = La Modification des {0} objets r\u00E9ussi +no.object.was.selected = Aucun objet s\u00E9lectionn\u00E9 +object.deleted.successfully = objet a \u00E9t\u00E9 bien supprim\u00E9 +_.objects.deleted.successfully = {0} objets \u00E9t\u00E9 bien supprim\u00E9 +fields.marked.with.a.star.are.required = Les champs marqu\u00E9s d''un \"*\" sont obligatoires +search = Recherche +page._.of._ = page {0} di {1} +_.of._ = {0} di {1} +crud-create = Cr\u00E9er +crud-delete = Effacer +crud-edit = Modifier +name = Nom +in.the.first.column.select.the.fields.you.want.to.edit = S\u00E9lectionnez le champ que vous voulez editer dans la premi\u00E8re colonne. Ensuite,remplissez leurs valeurs.. +properties = Propri\u00E9t\u00E9 +you.must.write.a.query.first = Ecrire une requ\u00EAte avant. +selection.providers = Selectioner un provider +none.available = Aucun disponibile. +return.to.search = Retour \u00E0 la recherche +show.search = Recherche +hide.search = Cacher + +#M2M +this.page.has.thrown.an.exception.during.execution = Cette page a soulev\u00E9 une exception d''ex\u00E9cution ({0}). Consultez le journal log pour plus de d\u00E9tails. +this.page.has.thrown.an.exception.during.rendering = Cette page a soulev\u00E9 une exception de visualisation ({0}). Consultez le journal log pour plus de d\u00E9tails. +settings=Impostazioni + +#Page configuration +configure = Configurez +update.configuration = Configuration de la mise \u00E0 jour +configuration.updated.successfully = Configuration mis \u00E0 jour avec succ\u00E8s +the.configuration.could.not.be.saved = La configuration n''est pas enregistr\u00E9e. V\u00E9rifie les erreurs ci-dessous et envoy\u00E9 \u00E0 nouveau le formulaire. +configure.page._ = Configurez la page: {0} +edit.page._ = Modifier la page: {0} +id = Id +title = Titre +description = Description +embed.in.parent = Inclure dans parent? +show.in.navigation = Afficher dans la navigation? +navigation.root = Navigation +inherit = h\u00E9riter +root = Racine +ghost.root = Fant\u00F4me racine +template = Mod\u00E8le +detail.template = Mod\u00E8le de d\u00E9tails +apply.template.recursively = Appliquer le mod\u00E8le r\u00E9cursivement + +#Scripting +couldnt.compile.script = Impossible de compiler le script - voir le journal pour plus de d\u00E9tails +couldnt.write.script.to._= Impossible d''\u00E9crire le script {0} - voir le journal pour plus de d\u00E9tails +script.class.is.not.valid = La classe de script n''est pas valide. Consultez le journal pour plus de d\u00E9tails. + +#Common +first = Premi\u00E8r +previous = Pr\u00E9c\u00E9dent +next = Suivant +last = Dernier +submit = Envoyer + +#Text action +browse = Explorer +browse.server = Ressources sur le serveur +pages = Pages +close.window = Fermer la fen\u00EAtre +there.are.no.attachments = Il n''y a pas de pi\u00E8ces jointes. +edit.content= Modifier le contenu +edit.header = Modifier en-t\u00EAte +manage.attachments = G\u00E9rer les pi\u00E8ces jointes +manage.attachments.for.page._= G\u00E9rer les pi\u00E8ces jointes de la page: {0} +upload.a.new.file = Charger un nouveau document +downloadable = T\u00E9l\u00E9chargeable +delete.selected.attachments = Supprimer les pi\u00E8ces jointes s\u00E9lectionn\u00E9es? +permission.text.edit = Modifier le texte +text.attachment.upload = Charger +text.attachment.noFileSelected = Aucun fichier s\u00E9lectionn\u00E9 pour le t\u00E9l\u00E9chargement +text.attachment.uploadSuccessful = Fichier envoy\u00E9 avec succ\u00E8s +text.attachment.uploadFailed = \u00E9chec de l''envoi! +text.attachment.noAttachmentSelected = Aucune pi\u00E8ce jointe s\u00E9lectionn\u00E9e +text.attachment.oneDeleted = 1 Pi\u00E8ce jointe supprim\u00E9e avec succ\u00E8s +text.attachment.nDeleted = {0} Pi\u00E8ces jointes supprim\u00E9es avec succ\u00E8s +title.cannot.be.empty = Le titre ne peut pas \u00EAtre vide +attachments = Pi\u00E8ces jointes +#Elements +elements.null= +elements.Yes=oui +elements.No=non +elements.Any=Tout +elements.Undefined=Ind\u00E9fini +elements.field.upload.keep=Conserver +elements.field.upload.update=Mettre \u00E0 jour +elements.field.upload.delete=Effacer +elements.field.password.confirm=Confirmer +elements.field.select.select=-- S\u00E9lectionner {0} -- +elements.field.select.none=Aucun +elements.search.range.from=De +elements.search.range.to=\u00E0 +elements.search.select.none=Not filtered +elements.search.select.notset.radio=(Pas encore d\u00E9fini) +elements.search.select.notset=-- Pas encore d\u00E9fini -- +elements.search.text.match.mode.contains=contient +elements.search.text.match.mode.equals=\u00E9gal +elements.search.text.match.mode.starts.with=commence avec +elements.search.text.match.mode.ends.with=se termine par +elements.error.field.required=Champs requis \ No newline at end of file diff --git a/portofino-pageactions/src/main/resources/portofino-messages_it.properties b/portofino-pageactions/src/main/resources/portofino-messages_it.properties index e7330f3bf2..c3f3030c40 100644 --- a/portofino-pageactions/src/main/resources/portofino-messages_it.properties +++ b/portofino-pageactions/src/main/resources/portofino-messages_it.properties @@ -26,7 +26,7 @@ apply.template.recursively = Applica template ricorsivamente #Scripting couldnt.compile.script = Impossibile compilare lo script - vedere i log per maggiori dettagli -couldnt.write.script.to._=Impossibile scrivere lo scipt {0} - vedere i log per i dettagli +couldnt.write.script.to._=Impossibile scrivere lo script {0} - vedere i log per i dettagli script.class.is.not.valid = La classe dello script non \u00E8 valida. Vedere i log per i dettagli. #Common diff --git a/portofino-postgresql/pom.xml b/portofino-postgresql/pom.xml index f45bd2f14d..bf0ae4aae9 100644 --- a/portofino-postgresql/pom.xml +++ b/portofino-postgresql/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-postgresqljar diff --git a/portofino-quartz/pom.xml b/portofino-quartz/pom.xml index b7dfcd6299..3f28927339 100644 --- a/portofino-quartz/pom.xml +++ b/portofino-quartz/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-quartzjar diff --git a/portofino-resteasy/pom.xml b/portofino-resteasy/pom.xml index 42aaf69922..60a056975f 100644 --- a/portofino-resteasy/pom.xml +++ b/portofino-resteasy/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-resteasyjar diff --git a/portofino-stripes/pom.xml b/portofino-stripes/pom.xml index 7887efab9b..f782f54425 100644 --- a/portofino-stripes/pom.xml +++ b/portofino-stripes/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-stripesjar diff --git a/portofino-theme/pom.xml b/portofino-theme/pom.xml index 31c97d7999..d35bc87224 100755 --- a/portofino-theme/pom.xml +++ b/portofino-theme/pom.xml @@ -6,7 +6,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-themejar diff --git a/portofino-theme/src/main/resources/META-INF/resources/theme/portofino.css b/portofino-theme/src/main/resources/META-INF/resources/theme/portofino.css index 40d342491a..babe85be95 100644 --- a/portofino-theme/src/main/resources/META-INF/resources/theme/portofino.css +++ b/portofino-theme/src/main/resources/META-INF/resources/theme/portofino.css @@ -14,8 +14,8 @@ html, body { margin: 0; padding: 0; height: 100%; - letter-spacing: 0.02em; - color: #333; + letter-spacing: 0.035em; + color: #5a5a5a; } /******************************************************************************* @@ -433,7 +433,7 @@ Content } .navigation { - letter-spacing: 0.03em; + letter-spacing: 0.045em; margin-bottom: 1em; } @@ -859,7 +859,18 @@ Brand image / Navbar vertical-align: text-top; } -.navbar{ box-shadow: 1px 0px 5px #666666 } +.navbar{ + border: none; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); +} + +.dropdown-menu { + margin-top: 0; + border: none; + -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); +} /******************************************************************************* Menu diff --git a/portofino-theme/src/main/resources/META-INF/resources/theme/templates/naked/modal.jsp b/portofino-theme/src/main/resources/META-INF/resources/theme/templates/naked/modal.jsp index 365bef01a7..098c759e5e 100644 --- a/portofino-theme/src/main/resources/META-INF/resources/theme/templates/naked/modal.jsp +++ b/portofino-theme/src/main/resources/META-INF/resources/theme/templates/naked/modal.jsp @@ -1,55 +1,59 @@ <%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" -%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" -%><%@ taglib prefix="stripes" uri="http://stripes.sourceforge.net/stripes-dynattr.tld" -%><%@ taglib prefix="mde" uri="/manydesigns-elements" -%><%-- +%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" +%> +<%@ taglib prefix="stripes" uri="http://stripes.sourceforge.net/stripes-dynattr.tld" +%> +<%@ taglib prefix="mde" uri="/manydesigns-elements" +%> +<%-- --%> - + + type="com.manydesigns.portofino.dispatcher.PageAction"/> - + -
-
-
-
-
- - - -
- -
- -
- - - + \ No newline at end of file diff --git a/portofino-war-archetype/pom.xml b/portofino-war-archetype/pom.xml index efb31a8751..13b37c3283 100644 --- a/portofino-war-archetype/pom.xml +++ b/portofino-war-archetype/pom.xml @@ -5,7 +5,7 @@ com.manydesigns portofino - 4.2.4-SNAPSHOT + 4.2.4 portofino-war-archetype maven-archetype