Author: fdesbois Date: 2010-01-05 16:39:31 +0000 (Tue, 05 Jan 2010) New Revision: 164 Added: trunk/suiviobsmer-business/src/test/java/fr/ifremer/suiviobsmer/ImportHelperTest.java trunk/suiviobsmer-ui/src/main/java/fr/ifremer/suiviobsmer/ui/pages/ExceptionReport.java trunk/suiviobsmer-ui/src/main/webapp/ExceptionReport.tml Modified: trunk/suiviobsmer-business/src/main/java/fr/ifremer/suiviobsmer/ImportHelper.java trunk/suiviobsmer-business/src/main/java/fr/ifremer/suiviobsmer/impl/ServiceContactImpl.java trunk/suiviobsmer-business/src/main/java/fr/ifremer/suiviobsmer/impl/ServiceSamplingImpl.java trunk/suiviobsmer-business/src/main/java/fr/ifremer/suiviobsmer/mock/ServiceContactMock.java trunk/suiviobsmer-business/src/main/xmi/suiviobsmer.zargo trunk/suiviobsmer-ui/src/main/java/fr/ifremer/suiviobsmer/ui/pages/Contacts.java trunk/suiviobsmer-ui/src/main/webapp/Administration.tml trunk/suiviobsmer-ui/src/main/webapp/Contacts.tml trunk/suiviobsmer-ui/src/main/webapp/css/common.css Log: - Improve contacts import/export - Add ExceptionReport page to show exceptions - Add missing admin field in Administration - Add missing loadProperty for getSampleRowsByUser Modified: trunk/suiviobsmer-business/src/main/java/fr/ifremer/suiviobsmer/ImportHelper.java =================================================================== --- trunk/suiviobsmer-business/src/main/java/fr/ifremer/suiviobsmer/ImportHelper.java 2010-01-05 09:55:40 UTC (rev 163) +++ trunk/suiviobsmer-business/src/main/java/fr/ifremer/suiviobsmer/ImportHelper.java 2010-01-05 16:39:31 UTC (rev 164) @@ -1,7 +1,15 @@ package fr.ifremer.suiviobsmer; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Locale; import org.apache.commons.lang.BooleanUtils; +import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.time.DurationFormatUtils; import org.slf4j.Logger; @@ -23,15 +31,15 @@ */ public static enum BOAT { /** Boat immatriculation **/ - NAVS_COD(19), + NAVS_COD(20), /** Boat name **/ - CARN_NOM(20), + CARN_NOM(21), /** Boat length **/ CARN_LONGUEUR_HT(-1), /** Boat build year **/ CARN_ANNEE(-1), /** Boat district code **/ - QUARTIER_IMMA(21), + QUARTIER_IMMA(22), /** ShipOwner code **/ PER_COD(-1), /** ShipOwner last name **/ @@ -57,27 +65,27 @@ */ public static enum SAMPLING { /** SampleRow code **/ - PLAN_CODE(5), + PLAN_CODE(6), /** Program code **/ - PROGRAMME_CODE(6), + PROGRAMME_CODE(7), /** Program period begin **/ - PROGRAMME_DEBUT(7), + PROGRAMME_DEBUT(8), /** Program period end **/ - PROGRAMME_FIN(8), + PROGRAMME_FIN(9), /** FishingZone other infos **/ - PECHE_AUTRE(12), + PECHE_AUTRE(13), /** Profession code DCF5 **/ - METIER_CODE_DCF5(13), + METIER_CODE_DCF5(14), /** Profession mesh size **/ - METIER_MAILLAGE(14), + METIER_MAILLAGE(15), /** Profession size **/ - METIER_TAILLE(15), + METIER_TAILLE(16), /** Profession other infos **/ - METIER_AUTRE(16), + METIER_AUTRE(17), /** Profession libelle **/ - METIER_LIBELLE(17), + METIER_LIBELLE(18), /** Profession species **/ - METIER_ESPECES(18), + METIER_ESPECES(19), /** SampleRow nb observants **/ PLAN_NB_OBSERV(-1), /** SampleRow average tide time **/ @@ -99,11 +107,11 @@ */ public static enum FISHING_ZONE { /** FishingZone facade **/ - PECHE_FACADE(9), + PECHE_FACADE(10), /** FishingZone sector **/ - PECHE_ZONE(10), + PECHE_ZONE(11), /** FishingZone district code **/ - PECHE_DIVISION(11); + PECHE_DIVISION(12); int contactHeader; @@ -120,38 +128,40 @@ * CSV headers for Contact */ public static enum CONTACT { + /** Contact code (create date time for existing contact) **/ + CONT_CODE(0), /** Contact create date **/ - CONT_CREATION(0), + CONT_CREATION(1), /** User id **/ - OBSERV_ID(1), + OBSERV_ID(2), /** User prenom **/ - OBSERV_PRENOM(2), + OBSERV_PRENOM(3), /** User nom **/ - OBSERV_NOM(3), + OBSERV_NOM(4), /** Company id **/ //SOCIETE_ID, /** Company nom **/ - SOCIETE_NOM(4), + SOCIETE_NOM(5), /** Contact state **/ - CONT_ETAT(22), + CONT_ETAT(23), /** Contact tide begin **/ - CONT_DEBUT_MAREE(23), + CONT_DEBUT_MAREE(24), /** Contact tide end **/ - CONT_FIN_MAREE(24), + CONT_FIN_MAREE(25), /** Contact nb observants **/ - CONT_NB_OBSERV(25), + CONT_NB_OBSERV(26), /** Contact mammals capture **/ - CONT_MAM_CAPT(26), + CONT_MAM_CAPT(27), /** Contact mammals observation **/ - CONT_MAM_OBS(27), + CONT_MAM_OBS(28), /** Contact comment **/ - CONT_COMMENT(28), + CONT_COMMENT(29), /** Contact data input **/ - CONT_ALLEGRO(29), + CONT_ALLEGRO(30), /** Contact company validation **/ - CONT_SOCIETE_VALID(30), + CONT_SOCIETE_VALID(31), /** Contact program validation **/ - CONT_PROGRAM_VALID(31); + CONT_PROGRAM_VALID(32); int contactHeader; @@ -164,7 +174,7 @@ } } - public static int CONTACT_NB_HEADERS = 31; + public static int CONTACT_NB_HEADERS = 33; public static String getHeaderForContactCsv(int index) { for (BOAT boatEnum : BOAT.values()) { @@ -219,6 +229,44 @@ return mammals.equals("X"); } + protected static String CONTACT_TIME_PATTERN = "HHmmssS"; + + protected static String CONTACT_DATE_PATTERN = "dd/MM/yyyy"; + + public static String formatContactCode(Date createDate) { + DateFormat timeFormat = new SimpleDateFormat(CONTACT_TIME_PATTERN, Locale.FRENCH); + String result = timeFormat.format(createDate); + return result; + } + + public static Date parseContactCreateDate(String code, String createDate) throws ParseException { + Calendar time = new GregorianCalendar(Locale.FRENCH); + if (!StringUtils.isEmpty(code)) { + DateFormat timeFormat = new SimpleDateFormat(CONTACT_TIME_PATTERN, Locale.FRENCH); + time = new GregorianCalendar(Locale.FRENCH); + time.setTime(timeFormat.parse(code)); + } else { + time.setTime(SuiviObsmerContext.getCurrentDate()); + } + + Calendar result = new GregorianCalendar(Locale.FRENCH); + if (!StringUtils.isEmpty(createDate)) { + DateFormat dateFormat = getContactDateFormat(); + result.setTime(dateFormat.parse(createDate)); + result.set(Calendar.HOUR_OF_DAY, time.get(Calendar.HOUR_OF_DAY)); + result.set(Calendar.MINUTE, time.get(Calendar.MINUTE)); + result.set(Calendar.SECOND, time.get(Calendar.SECOND)); + result.set(Calendar.MILLISECOND, time.get(Calendar.MILLISECOND)); + } else { + result.setTime(SuiviObsmerContext.getCurrentDate()); + } + return result.getTime(); + } + + public static DateFormat getContactDateFormat() { + return new SimpleDateFormat(CONTACT_DATE_PATTERN, Locale.FRENCH); + } + public static long logTimeAndMemory(Logger log, long tic1, String msg) { if (log.isInfoEnabled()) { log.info("RUNNING... Import : " + msg); Modified: trunk/suiviobsmer-business/src/main/java/fr/ifremer/suiviobsmer/impl/ServiceContactImpl.java =================================================================== --- trunk/suiviobsmer-business/src/main/java/fr/ifremer/suiviobsmer/impl/ServiceContactImpl.java 2010-01-05 09:55:40 UTC (rev 163) +++ trunk/suiviobsmer-business/src/main/java/fr/ifremer/suiviobsmer/impl/ServiceContactImpl.java 2010-01-05 16:39:31 UTC (rev 164) @@ -41,6 +41,7 @@ import fr.ifremer.suiviobsmer.entity.Contact; import fr.ifremer.suiviobsmer.entity.ContactDAO; import fr.ifremer.suiviobsmer.entity.ContactImpl; +import fr.ifremer.suiviobsmer.entity.ElligibleBoat; import fr.ifremer.suiviobsmer.entity.FishingZone; import fr.ifremer.suiviobsmer.entity.Profession; import fr.ifremer.suiviobsmer.entity.Program; @@ -51,15 +52,15 @@ import fr.ifremer.suiviobsmer.services.ServiceContact; import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.OutputStream; import java.nio.charset.Charset; import java.text.DateFormat; -import java.text.SimpleDateFormat; +import java.text.ParseException; +import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; -import java.util.Locale; import java.util.Map; +import org.apache.commons.lang.StringUtils; import org.nuiton.topia.TopiaContext; import org.nuiton.topia.persistence.TopiaEntity; import org.slf4j.Logger; @@ -101,6 +102,11 @@ } query.addLoad("user.company", "sampleRow.program", "sampleRow.profession", "sampleRow.company"); + + if (log.isInfoEnabled()) { + log.info("Query : " + query); + } + results = query.executeToEntityMap(); transaction.closeContext(); @@ -158,11 +164,8 @@ } } - protected static String DATE_TIME_PATTERN = "dd/MM/yyyy HH:mm:ss"; - protected static String DATE_PATTERN = "dd/MM/yyyy"; - @Override - public InputStream exportContactCsv(User user, List<Contact> contacts) + public InputStream exportContactCsv(User user, Collection<Contact> contacts) throws SuiviObsmerException { TopiaContext transaction = null; InputStream result = null; @@ -176,14 +179,18 @@ contacts = dao.findAll(); } else { // Filtered by company for a simple user - contacts = dao.createQuery(). - add("user.company", user.getCompany()). - executeToEntityList(); + contacts = dao.createQuery().add("user.company", user.getCompany()).executeToEntityList(); } } - String alea = SuiviObsmerContext.createRandomString(8); - FileOutputStream output = new FileOutputStream("/tmp/contact-" + alea + ".csv"); + String alea = SuiviObsmerContext.createRandomString(16); + String filename = "/tmp/wao-contacts-" + alea + ".csv"; + + if (log.isDebugEnabled()) { + log.debug("Export contacts into : " + filename); + } + + FileOutputStream output = new FileOutputStream(filename); CsvWriter writer = new CsvWriter(output, ',', Charset.forName("UTF-8")); // Headers @@ -191,9 +198,10 @@ String header = ImportHelper.getHeaderForContactCsv(i); writer.write(header); } + writer.endRecord(); - DateFormat dateTimeFormat = new SimpleDateFormat(DATE_TIME_PATTERN, Locale.FRENCH); - DateFormat dateFormat = new SimpleDateFormat(DATE_PATTERN, Locale.FRENCH); + + DateFormat dateFormat = ImportHelper.getContactDateFormat(); int curr = 0; for (Contact contact : contacts) { @@ -201,17 +209,24 @@ String[] record = new String[ImportHelper.CONTACT_NB_HEADERS]; // Contact part - record[CONTACT.CONT_CREATION.forContactCsv()] = dateTimeFormat.format(contact.getTopiaCreateDate()); + record[CONTACT.CONT_CODE.forContactCsv()] = ImportHelper.formatContactCode(contact.getTopiaCreateDate()); + record[CONTACT.CONT_CREATION.forContactCsv()] = dateFormat.format(contact.getTopiaCreateDate()); record[CONTACT.CONT_ETAT.forContactCsv()] = contact.getState(); - record[CONTACT.CONT_DEBUT_MAREE.forContactCsv()] = dateFormat.format(contact.getTideBeginDate()); - record[CONTACT.CONT_FIN_MAREE.forContactCsv()] = dateFormat.format(contact.getTideEndDate()); + if (contact.getTideBeginDate() != null) { + record[CONTACT.CONT_DEBUT_MAREE.forContactCsv()] = dateFormat.format(contact.getTideBeginDate()); + } + if (contact.getTideEndDate() != null) { + record[CONTACT.CONT_FIN_MAREE.forContactCsv()] = dateFormat.format(contact.getTideEndDate()); + } record[CONTACT.CONT_NB_OBSERV.forContactCsv()] = String.valueOf(contact.getNbObservants()); record[CONTACT.CONT_MAM_CAPT.forContactCsv()] = ImportHelper.formatContactMammals(contact.getMammalsCapture()); record[CONTACT.CONT_MAM_OBS.forContactCsv()] = ImportHelper.formatContactMammals(contact.getMammalsObservation()); record[CONTACT.CONT_COMMENT.forContactCsv()] = contact.getComment(); - record[CONTACT.CONT_ALLEGRO.forContactCsv()] = dateFormat.format(contact.getDataInputDate()); + if (contact.getDataInputDate() != null) { + record[CONTACT.CONT_ALLEGRO.forContactCsv()] = dateFormat.format(contact.getDataInputDate()); + } record[CONTACT.CONT_SOCIETE_VALID.forContactCsv()] = ImportHelper.formatContactValidation(contact.getValidationCompany()); record[CONTACT.CONT_PROGRAM_VALID.forContactCsv()] = @@ -264,7 +279,7 @@ } writer.close(); - result = new FileInputStream(output.getFD()); + result = new FileInputStream(filename); transaction.closeContext(); } catch (Exception eee) { @@ -275,9 +290,10 @@ } @Override - public int importContactCsv(InputStream input) throws SuiviObsmerException { + public int importContactCsv(User user, InputStream input) throws SuiviObsmerException { TopiaContext transaction = null; int result = 0; + int currRow = 1; try { transaction = rootContext.beginTransaction(); @@ -290,16 +306,14 @@ SampleRowDAO rowDAO = SuiviObsmerModelDAOHelper.getSampleRowDAO(transaction); BoatDAO boatDAO = SuiviObsmerModelDAOHelper.getBoatDAO(transaction); - DateFormat dateTimeFormat = new SimpleDateFormat(DATE_TIME_PATTERN, Locale.FRENCH); - DateFormat dateFormat = new SimpleDateFormat(DATE_PATTERN, Locale.FRENCH); - - int currRow = 0; + DateFormat dateFormat = ImportHelper.getContactDateFormat(); + long tic; tic = System.currentTimeMillis(); while(reader.readRecord()) { currRow++; - String userId = reader.get(CONTACT.OBSERV_ID.name()); + String observerId = reader.get(CONTACT.OBSERV_ID.name()); String state = reader.get(CONTACT.CONT_ETAT.name()); ContactState contactState = ContactState.createContactStateEnum(state); @@ -311,36 +325,82 @@ ContactState.availableStates()); } - User user = userDAO.findByLogin(userId); - if (user != null) { - // FIXME-FD20100104 findContains not optimized in TopiaDAOImpl - Company company = companyDAO.findContainsUser(user); + User observer = userDAO.findByLogin(observerId); + if (observer != null) { + Company company = user.getCompany(); + // For an admin, get the company from database + if (user.getAdmin()) { + // FIXME-FD20100104 findContains not optimized in TopiaDAOImpl + company = companyDAO.findContainsUser(observer); + // For a user, check if the observer as the same company as the current user + } else if (!observer.getCompany().getTopiaId().equals(company.getTopiaId())) { + throw new SuiviObsmerBusinessException(Type.IMPORT_ERROR, this.getClass(), + "Erreur ligne " + currRow + " : " + + "L'observateur avec pour login '" + observerId + "' n'appartient pas à votre société !"); + } + if (company != null) { String rowCode = reader.get(SAMPLING.PLAN_CODE.name()); - SampleRow row = rowDAO.findByCode(rowCode); + SampleRow row = rowDAO.findByProperties(SampleRow.CODE, rowCode, SampleRow.COMPANY, company); if (row != null) { int boatImmatriculation = Integer.parseInt(reader.get(BOAT.NAVS_COD.name())); - - Boat boat = boatDAO.findByImmatriculation(boatImmatriculation); + // The boat must be elligible for the row + TopiaQuery<Boat> boatQuery = boatDAO.createQuery("B").addSelect("B"). + addFrom(ElligibleBoat.class.getName() + " E"). + add("E.sampleRow", row).add("E.boat = B"). + add(Boat.IMMATRICULATION, boatImmatriculation); + + if (!user.getAdmin()) { + // Constraint on companyActive for elligibleBoat for a simple user + boatQuery.add("E.companyActive = :booleanTrue OR (E.companyActive IS NULL AND E.globalActive = :booleanTrue)"). + addParam("booleanTrue", Boolean.TRUE); + } + + Boat boat = boatQuery.executeToEntity(); + if (boat != null) { - Date createDate = dateTimeFormat.parse(reader.get(CONTACT.CONT_CREATION.name())); - Contact contact = dao.createQuery(). - add(TopiaEntity.TOPIA_CREATE_DATE, createDate). - executeToEntity(); + Contact contact = null; - if (contact == null) { // new contact to import + // Check if createDate exist + String createDateString = reader.get(CONTACT.CONT_CREATION.name()); + //Date createDate = !StringUtils.isEmpty(createDateString) ? dateFormat.parse(createDateString) : null; + + String contactCode = reader.get(CONTACT.CONT_CODE.name()); + Date createDate = ImportHelper.parseContactCreateDate(contactCode, createDateString); + if (log.isDebugEnabled()) { + log.debug("Ligne " + currRow + " : Create date : " + createDate); + } + + if (!StringUtils.isEmpty(contactCode) && !StringUtils.isEmpty(createDateString)) { + // Get entity from database + contact = dao.createQuery(). + add(TopiaEntity.TOPIA_CREATE_DATE, createDate). + add("user.company", company). + add(Contact.BOAT, boat). + add(Contact.SAMPLE_ROW, row). + executeToEntity(); + } + + // new contact to import + if (contact == null) { contact = dao.create( - Contact.USER, user, + TopiaEntity.TOPIA_CREATE_DATE, createDate, + Contact.USER, observer, Contact.SAMPLE_ROW, row, Contact.BOAT, boat); } - Date tideBegin = dateFormat.parse(CONTACT.CONT_DEBUT_MAREE.name()); - Date tideEnd = dateFormat.parse(CONTACT.CONT_FIN_MAREE.name()); - int nbObservants = Integer.parseInt(reader.get(CONTACT.CONT_NB_OBSERV.name())); + + String tideBeginString = reader.get(CONTACT.CONT_DEBUT_MAREE.name()); + String tideEndString = reader.get(CONTACT.CONT_FIN_MAREE.name()); + String nbObservantsString = reader.get(CONTACT.CONT_NB_OBSERV.name()); + + Date tideBegin = !StringUtils.isEmpty(tideBeginString) ? dateFormat.parse(tideBeginString) : null; + Date tideEnd = !StringUtils.isEmpty(tideEndString) ? dateFormat.parse(tideEndString) : null; + int nbObservants = !StringUtils.isEmpty(nbObservantsString) ? Integer.parseInt(nbObservantsString) : 0; boolean mammalsCapture = ImportHelper.parseContactMammals(reader.get(CONTACT.CONT_MAM_CAPT.name())); boolean mammalsObsv = @@ -357,11 +417,12 @@ } else if (log.isWarnEnabled()) { log.warn("Import contact ligne " + currRow + " : " + - "Navire inexistant avec l'immatriculation : " + boatImmatriculation); + "Navire inexistant ou incompatible avec la ligne d'échantillon " + + "pour l'immatriculation : " + boatImmatriculation); } } else if (log.isWarnEnabled()) { log.warn("Import contact ligne " + currRow + " : " + - "Ligne d'échantillon inexistante avec le code : " + rowCode); + "Ligne d'échantillon inexistante ou incompatible avec la société pour le code : " + rowCode); } } else if (log.isErrorEnabled()) { log.error("Import contact ligne " + currRow + " : " + @@ -369,7 +430,7 @@ } } else if (log.isWarnEnabled()) { log.warn("Import contact ligne " + currRow + " : " + - "Utilisateur inexistant avec l'identifiant : " + userId); + "Utilisateur inexistant avec l'identifiant : " + observerId); } if (result % 1000 == 0) { @@ -388,10 +449,17 @@ } } + transaction.commitTransaction(); + transaction.closeContext(); - } catch (Exception eee) { + } catch (ParseException eee) { SuiviObsmerContext.serviceException(transaction, - "Impossible d'exporter les contacts", eee); + "Erreur ligne " + currRow + " : " + + "Le format des dates est incorrect, il doit être de la forme : JJ/MM/AAAA " + + "(ou JJ/MM/AAAA HH:MM:SS pour la date de création d'un contact existant)", eee); + } catch (Exception eee) { + SuiviObsmerContext.serviceException(transaction, + "Impossible d'importer les contacts", eee); } return result; } Modified: trunk/suiviobsmer-business/src/main/java/fr/ifremer/suiviobsmer/impl/ServiceSamplingImpl.java =================================================================== --- trunk/suiviobsmer-business/src/main/java/fr/ifremer/suiviobsmer/impl/ServiceSamplingImpl.java 2010-01-05 09:55:40 UTC (rev 163) +++ trunk/suiviobsmer-business/src/main/java/fr/ifremer/suiviobsmer/impl/ServiceSamplingImpl.java 2010-01-05 16:39:31 UTC (rev 164) @@ -248,7 +248,7 @@ query.add(SampleRow.COMPANY, user.getCompany()); } - results = query.executeToEntityList(); + results = query.addLoad("program", "profession").executeToEntityList(); // SampleRowDAO dao = SuiviObsmerModelDAOHelper.getSampleRowDAO(transaction); // Modified: trunk/suiviobsmer-business/src/main/java/fr/ifremer/suiviobsmer/mock/ServiceContactMock.java =================================================================== --- trunk/suiviobsmer-business/src/main/java/fr/ifremer/suiviobsmer/mock/ServiceContactMock.java 2010-01-05 09:55:40 UTC (rev 163) +++ trunk/suiviobsmer-business/src/main/java/fr/ifremer/suiviobsmer/mock/ServiceContactMock.java 2010-01-05 16:39:31 UTC (rev 164) @@ -30,8 +30,8 @@ import fr.ifremer.suiviobsmer.entity.User; import fr.ifremer.suiviobsmer.services.ServiceContact; import java.io.InputStream; -import java.io.OutputStream; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -262,12 +262,12 @@ } @Override - public InputStream exportContactCsv(User user, List<Contact> contacts) throws SuiviObsmerException { + public InputStream exportContactCsv(User user, Collection<Contact> contacts) throws SuiviObsmerException { throw new UnsupportedOperationException("Not supported yet."); } @Override - public int importContactCsv(InputStream input) throws SuiviObsmerException { + public int importContactCsv(User user, InputStream input) throws SuiviObsmerException { throw new UnsupportedOperationException("Not supported yet."); } Modified: trunk/suiviobsmer-business/src/main/xmi/suiviobsmer.zargo =================================================================== (Binary files differ) Added: trunk/suiviobsmer-business/src/test/java/fr/ifremer/suiviobsmer/ImportHelperTest.java =================================================================== --- trunk/suiviobsmer-business/src/test/java/fr/ifremer/suiviobsmer/ImportHelperTest.java (rev 0) +++ trunk/suiviobsmer-business/src/test/java/fr/ifremer/suiviobsmer/ImportHelperTest.java 2010-01-05 16:39:31 UTC (rev 164) @@ -0,0 +1,129 @@ + +package fr.ifremer.suiviobsmer; + +import fr.ifremer.suiviobsmer.business.SuiviObsmerRunnerTest; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Locale; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author fdesbois + */ +public class ImportHelperTest { + + private static SuiviObsmerRunner runner; + + private static final Logger log = LoggerFactory.getLogger(ImportHelperTest.class); + + public ImportHelperTest() { + runner = new SuiviObsmerRunnerTest(); + } + + @BeforeClass + public static void setUpClass() throws Exception { + + } + + @AfterClass + public static void tearDownClass() throws Exception { + + } + + @Before + public void setUp() throws SuiviObsmerException { + runner.start(); + } + + @After + public void tearDown() throws SuiviObsmerException { + runner.stop(); + } + + /** + * Test of getHeaderForContactCsv method, of class ImportHelper. + */ + //@Test + public void testGetHeaderForContactCsv() { + System.out.println("getHeaderForContactCsv"); + } + + /** + * Test of formatContactValidation method, of class ImportHelper. + */ + //@Test + public void testFormatContactValidation() { + System.out.println("formatContactValidation"); + } + + /** + * Test of formatContactMammals method, of class ImportHelper. + */ + //@Test + public void testFormatContactMammals() { + System.out.println("formatContactMammals"); + } + + /** + * Test of parseContactMammals method, of class ImportHelper. + */ + //@Test + public void testParseContactMammals() { + System.out.println("parseContactMammals"); + } + + /** + * Test of formatContactCode method, of class ImportHelper. + */ + @Test + public void testFormatContactCode() { + log.info("formatContactCode"); + Date createDate = SuiviObsmerContext.getCurrentDate(); + Calendar calendar = new GregorianCalendar(Locale.FRENCH); + calendar.setTime(createDate); + calendar.set(Calendar.HOUR_OF_DAY, 10); + calendar.set(Calendar.MINUTE, 1); + calendar.set(Calendar.SECOND, 50); + calendar.set(Calendar.MILLISECOND, 260); + String expResult = "100150260"; + String result = ImportHelper.formatContactCode(calendar.getTime()); + assertEquals(expResult, result); + } + + /** + * Test of parseContactCreateDate method, of class ImportHelper. + */ + @Test + public void testParseContactCreateDate() throws Exception { + System.out.println("parseContactCreateDate"); + String code = "101250718"; + Date createDate = SuiviObsmerContext.getCurrentDate(); + Calendar calendar = new GregorianCalendar(Locale.FRENCH); + calendar.setTime(createDate); + calendar.set(Calendar.HOUR_OF_DAY, 10); + calendar.set(Calendar.MINUTE, 12); + calendar.set(Calendar.SECOND, 50); + calendar.set(Calendar.MILLISECOND, 718); + Date expResult = calendar.getTime(); + Date result = ImportHelper.parseContactCreateDate(code, "23/10/2009"); + assertEquals(expResult, result); + } + + /** + * Test of logTimeAndMemory method, of class ImportHelper. + */ + //@Test + public void testLogTimeAndMemory() { + System.out.println("logTimeAndMemory"); + } + +} \ No newline at end of file Property changes on: trunk/suiviobsmer-business/src/test/java/fr/ifremer/suiviobsmer/ImportHelperTest.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL" Modified: trunk/suiviobsmer-ui/src/main/java/fr/ifremer/suiviobsmer/ui/pages/Contacts.java =================================================================== --- trunk/suiviobsmer-ui/src/main/java/fr/ifremer/suiviobsmer/ui/pages/Contacts.java 2010-01-05 09:55:40 UTC (rev 163) +++ trunk/suiviobsmer-ui/src/main/java/fr/ifremer/suiviobsmer/ui/pages/Contacts.java 2010-01-05 16:39:31 UTC (rev 164) @@ -21,6 +21,7 @@ package fr.ifremer.suiviobsmer.ui.pages; +import fr.ifremer.suiviobsmer.SuiviObsmerBusinessException; import fr.ifremer.suiviobsmer.SuiviObsmerContext; import fr.ifremer.suiviobsmer.SuiviObsmerException; import fr.ifremer.suiviobsmer.bean.ContactState; @@ -38,6 +39,8 @@ import fr.ifremer.suiviobsmer.ui.base.SuiviObsmerPage; import fr.ifremer.suiviobsmer.ui.components.Layout; import fr.ifremer.suiviobsmer.ui.services.ContactModelFactory; +import java.io.IOException; +import java.io.InputStream; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; @@ -47,6 +50,7 @@ import org.apache.commons.lang.StringUtils; import org.apache.tapestry5.ComponentResources; import org.apache.tapestry5.Field; +import org.apache.tapestry5.StreamResponse; import org.apache.tapestry5.annotations.IncludeStylesheet; import org.apache.tapestry5.annotations.InjectComponent; import org.apache.tapestry5.annotations.Log; @@ -58,6 +62,8 @@ import org.apache.tapestry5.ioc.annotations.Inject; import org.apache.tapestry5.ioc.services.PropertyAccess; import org.apache.tapestry5.services.BeanModelSource; +import org.apache.tapestry5.services.Response; +import org.apache.tapestry5.upload.services.UploadedFile; import org.nuiton.util.DateUtils; import org.slf4j.Logger; @@ -108,6 +114,50 @@ contactsForm.clearErrors(); } + /**************************** CONTACT IMPORT/EXPORT ***********************/ + + @Property + private UploadedFile contactsCsvFile; + + @Log + void onSuccessFromImportContacts() throws SuiviObsmerException { + //importBoatsForm.clearErrors(); + try { + int result = serviceContact.importContactCsv(user, contactsCsvFile.getStream()); + // Suppress persitant list of contacts + contacts = null; + layout.getFeedBack().addInfo(result + " contacts importés"); + } catch (SuiviObsmerBusinessException eee) { + layout.getFeedBack().addError(eee.getMessage()); + } + //return importBoatsForm.getHasErrors() ? importBoatsForm : this; + } + + StreamResponse onActionFromExportShowContacts() { + return new StreamResponse() { + + @Override + public String getContentType() { + return "text/csv;charset=utf-8"; + } + + @Override + public InputStream getStream() throws IOException { + InputStream result = null; + try { + result = serviceContact.exportContactCsv(user, getContacts().values()); + } catch (SuiviObsmerException eee) { + throw new IOException(eee); + } + return result; + } + + @Override + public void prepareResponse(Response response) { + } + }; + } + /**************************** CONTACT LIST ********************************/ @Inject Added: trunk/suiviobsmer-ui/src/main/java/fr/ifremer/suiviobsmer/ui/pages/ExceptionReport.java =================================================================== --- trunk/suiviobsmer-ui/src/main/java/fr/ifremer/suiviobsmer/ui/pages/ExceptionReport.java (rev 0) +++ trunk/suiviobsmer-ui/src/main/java/fr/ifremer/suiviobsmer/ui/pages/ExceptionReport.java 2010-01-05 16:39:31 UTC (rev 164) @@ -0,0 +1,64 @@ + +package fr.ifremer.suiviobsmer.ui.pages; + +import fr.ifremer.suiviobsmer.SuiviObsmerException; +import fr.ifremer.suiviobsmer.ui.base.SuiviObsmerPage; +import fr.ifremer.suiviobsmer.ui.components.Layout; +import org.apache.tapestry5.annotations.InjectComponent; +import org.apache.tapestry5.annotations.Property; +import org.apache.tapestry5.ioc.annotations.Inject; +import org.apache.tapestry5.runtime.ComponentEventException; +import org.apache.tapestry5.services.ExceptionReporter; +import org.slf4j.Logger; + +/** + * ExceptionReport + * + * Created: 5 janv. 2010 + * + * @author fdesbois + * @version $Revision$ + * + * Mise a jour: $Date$ + * par : $Author$ + */ +public class ExceptionReport implements ExceptionReporter, SuiviObsmerPage { + + @InjectComponent + private Layout layout; + + @Inject + private Logger log; + + @Property + private Throwable exception; + + @Override + public void reportException(Throwable eee) { + this.exception = getSuiviObsmerException(eee); + if (exception != null) { + layout.getFeedBack().addError(exception.getMessage()); + this.exception = exception.getCause(); + } else { + this.exception = eee; + log.error("Unexpected exception", eee); + } + layout.getFeedBack().addError("Erreur : " + this.exception.getClass().getSimpleName() + " : " + this.exception.getMessage()); + } + + protected Throwable getSuiviObsmerException(Throwable eee) { + if (eee == null) { + return eee; + } + if (eee instanceof SuiviObsmerException) { + return eee; + } + return getSuiviObsmerException(eee.getCause()); + } + + @Override + public boolean isOnlyForAdmin() { + return false; + } + +} Property changes on: trunk/suiviobsmer-ui/src/main/java/fr/ifremer/suiviobsmer/ui/pages/ExceptionReport.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL" Modified: trunk/suiviobsmer-ui/src/main/webapp/Administration.tml =================================================================== --- trunk/suiviobsmer-ui/src/main/webapp/Administration.tml 2010-01-05 09:55:40 UTC (rev 163) +++ trunk/suiviobsmer-ui/src/main/webapp/Administration.tml 2010-01-05 16:39:31 UTC (rev 164) @@ -42,7 +42,7 @@ </form> <fieldset class="user-form clearfix"> - <form t:type="beaneditform" class="clearfix" t:id="user" t:include="firstName, lastName, login, password, phoneNumber, active"> + <form t:type="beaneditform" class="clearfix" t:id="user" t:include="firstName, lastName, login, password, phoneNumber, admin, active"> <p:password> <t:label t:for="generatePassword" /> <input t:type="checkbox" t:id="generatePassword" value="generatePassword" /> Modified: trunk/suiviobsmer-ui/src/main/webapp/Contacts.tml =================================================================== --- trunk/suiviobsmer-ui/src/main/webapp/Contacts.tml 2010-01-05 09:55:40 UTC (rev 163) +++ trunk/suiviobsmer-ui/src/main/webapp/Contacts.tml 2010-01-05 16:39:31 UTC (rev 164) @@ -3,6 +3,15 @@ xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd" xmlns:p="tapestry:parameter"> <!--t:include="creationDate, lastState, boatName, boatImmatriculation, boatDistrictCode, beginTideDate, endTideDate, nbObservants, mammals, editDate, comment, validation"--> +<form t:type="form" t:id="importContacts"> + <t:errors /> + <t:label for="contactsCsvFile" /> : + <input t:type="upload" t:id="contactsCsvFile" t:validate="required" /> + <input t:type="submit" class="ico import" value="OK" title="Importer une liste de contacts (format CSV)" /> +</form> +<a t:type="actionlink" t:id="exportShowContacts"> + EXPORT +</a> <t:zone t:id="gridZone" t:update="show"> <form t:type="form" t:id="contactsForm" t:zone="gridZone"> <t:errors id="so-contact-form-errors" t:banner="message:contactsForm-errors-banner"/> Added: trunk/suiviobsmer-ui/src/main/webapp/ExceptionReport.tml =================================================================== --- trunk/suiviobsmer-ui/src/main/webapp/ExceptionReport.tml (rev 0) +++ trunk/suiviobsmer-ui/src/main/webapp/ExceptionReport.tml 2010-01-05 16:39:31 UTC (rev 164) @@ -0,0 +1,15 @@ +<t:layout t:pageTitle="Erreur" t:contentId="so-exception-report" + xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"> + +</t:layout> + +<!--<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd" xmlns:p="tapestry:parameter"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> + <title>WAO - Web Applicatif Obsmer : Erreur</title> + </head> + <body> + <t:feedback t:id="errorFeedback" /> + </body> +</html>--> Modified: trunk/suiviobsmer-ui/src/main/webapp/css/common.css =================================================================== --- trunk/suiviobsmer-ui/src/main/webapp/css/common.css 2010-01-05 09:55:40 UTC (rev 163) +++ trunk/suiviobsmer-ui/src/main/webapp/css/common.css 2010-01-05 16:39:31 UTC (rev 164) @@ -287,7 +287,7 @@ text-align: center; } -div.so-import fieldset form input.import { +input.import { width: 22px; height: 22px; background: url(../img/file-import-22px.png) no-repeat center center;