diff --git a/dataverse-persistence/src/main/java/edu/harvard/iq/dataverse/persistence/dataverse/bannersandmessages/DataverseBanner.java b/dataverse-persistence/src/main/java/edu/harvard/iq/dataverse/persistence/dataverse/bannersandmessages/DataverseBanner.java index 96149a8271..a240914bc7 100644 --- a/dataverse-persistence/src/main/java/edu/harvard/iq/dataverse/persistence/dataverse/bannersandmessages/DataverseBanner.java +++ b/dataverse-persistence/src/main/java/edu/harvard/iq/dataverse/persistence/dataverse/bannersandmessages/DataverseBanner.java @@ -1,90 +1,123 @@ package edu.harvard.iq.dataverse.persistence.dataverse.bannersandmessages; -import edu.harvard.iq.dataverse.persistence.dataverse.Dataverse; +import static edu.harvard.iq.dataverse.common.DateUtil.convertToDate; +import static javax.persistence.CascadeType.ALL; +import static javax.persistence.FetchType.LAZY; +import static javax.persistence.GenerationType.IDENTITY; +import static javax.persistence.TemporalType.TIMESTAMP; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Optional; -import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; -import javax.persistence.FetchType; import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; + +import edu.harvard.iq.dataverse.common.DataverseClock; +import edu.harvard.iq.dataverse.persistence.JpaEntity; +import edu.harvard.iq.dataverse.persistence.dataverse.Dataverse; @Entity -public class DataverseBanner { +public class DataverseBanner implements JpaEntity { @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) + @GeneratedValue(strategy = IDENTITY) private Long id; @Column(nullable = false) - @Temporal(TemporalType.TIMESTAMP) + @Temporal(TIMESTAMP) private Date fromTime; @Column(nullable = false) - @Temporal(TemporalType.TIMESTAMP) + @Temporal(TIMESTAMP) private Date toTime; private boolean active; - @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "dataverseBanner") - private List dataverseLocalizedBanner = new ArrayList<>(); + @OneToMany(cascade = ALL, orphanRemoval = true, mappedBy = "dataverseBanner") + private List localizedBanners = new ArrayList<>(); - @ManyToOne(fetch = FetchType.LAZY) + @ManyToOne(fetch = LAZY) private Dataverse dataverse; + @Override public Long getId() { - return id; + return this.id; } - public void setId(Long id) { + public void setId(final Long id) { this.id = id; } public Date getFromTime() { - return fromTime; + return this.fromTime; } - public void setFromTime(Date fromTime) { + public void setFromTime(final Date fromTime) { this.fromTime = fromTime; } public Date getToTime() { - return toTime; + return this.toTime; } - public void setToTime(Date toTime) { + public void setToTime(final Date toTime) { this.toTime = toTime; } + public boolean isFromTimePresent() { + return this.fromTime != null; + } + + public boolean isToTimePresent() { + return this.toTime != null; + } + + public boolean isFromTimeBeforeEndTime() { + return this.fromTime.before(this.toTime); + } + + public boolean isToTimeInFuture() { + return this.toTime.after(convertToDate(DataverseClock.now())); + } + public boolean isActive() { - return active; + return this.active; } - public void setActive(boolean active) { + public void setActive(final boolean active) { this.active = active; } - public List getDataverseLocalizedBanner() { - return dataverseLocalizedBanner; + public List getLocalizedBanners() { + return this.localizedBanners; + } + + public void setLocalizedBanners( + final List localizedBanners) { + this.localizedBanners = localizedBanners; + } + + public void addLocalizedBanner(final String locale) { + this.localizedBanners.add(new DataverseLocalizedBanner(locale)); } - public void setDataverseLocalizedBanner(List dataverseLocalizedBanner) { - this.dataverseLocalizedBanner = dataverseLocalizedBanner; + public Optional getBannerFor(final String locale) { + return this.localizedBanners.stream() + .filter(banner -> banner.getLocale().equals(locale)).findAny(); } public Dataverse getDataverse() { - return dataverse; + return this.dataverse; } - public void setDataverse(Dataverse dataverse) { + public void setDataverse(final Dataverse dataverse) { this.dataverse = dataverse; } } diff --git a/dataverse-persistence/src/main/java/edu/harvard/iq/dataverse/persistence/dataverse/bannersandmessages/DataverseBannerRepository.java b/dataverse-persistence/src/main/java/edu/harvard/iq/dataverse/persistence/dataverse/bannersandmessages/DataverseBannerRepository.java new file mode 100644 index 0000000000..f75beb9138 --- /dev/null +++ b/dataverse-persistence/src/main/java/edu/harvard/iq/dataverse/persistence/dataverse/bannersandmessages/DataverseBannerRepository.java @@ -0,0 +1,14 @@ +package edu.harvard.iq.dataverse.persistence.dataverse.bannersandmessages; + +import javax.ejb.Singleton; + +import edu.harvard.iq.dataverse.persistence.JpaRepository; + +@Singleton +public class DataverseBannerRepository extends JpaRepository { + + public DataverseBannerRepository() { + super(DataverseBanner.class); + } + +} diff --git a/dataverse-persistence/src/main/java/edu/harvard/iq/dataverse/persistence/dataverse/bannersandmessages/DataverseLocalizedBanner.java b/dataverse-persistence/src/main/java/edu/harvard/iq/dataverse/persistence/dataverse/bannersandmessages/DataverseLocalizedBanner.java index 80070a055d..965db40514 100644 --- a/dataverse-persistence/src/main/java/edu/harvard/iq/dataverse/persistence/dataverse/bannersandmessages/DataverseLocalizedBanner.java +++ b/dataverse-persistence/src/main/java/edu/harvard/iq/dataverse/persistence/dataverse/bannersandmessages/DataverseLocalizedBanner.java @@ -1,21 +1,30 @@ package edu.harvard.iq.dataverse.persistence.dataverse.bannersandmessages; +import static javax.persistence.FetchType.LAZY; +import static javax.persistence.GenerationType.IDENTITY; +import static org.apache.commons.lang3.StringUtils.isEmpty; +import static org.apache.commons.lang3.StringUtils.trim; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; + import javax.persistence.Basic; import javax.persistence.Column; import javax.persistence.Entity; -import javax.persistence.FetchType; import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Lob; import javax.persistence.ManyToOne; -import java.util.Optional; + +import edu.harvard.iq.dataverse.persistence.JpaEntity; @Entity -public class DataverseLocalizedBanner { +public class DataverseLocalizedBanner implements JpaEntity { @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) + @GeneratedValue(strategy = IDENTITY) private Long id; @Column(nullable = false) @@ -23,7 +32,7 @@ public class DataverseLocalizedBanner { @Column(nullable = false) @Lob - @Basic(fetch = FetchType.LAZY) + @Basic(fetch = LAZY) private byte[] image; private String contentType; @@ -32,62 +41,96 @@ public class DataverseLocalizedBanner { private String imageLink; - @ManyToOne(fetch = FetchType.LAZY) + @ManyToOne(fetch = LAZY) private DataverseBanner dataverseBanner; + public DataverseLocalizedBanner() { + } + + public DataverseLocalizedBanner(final String locale) { + this.locale = locale; + } + + @Override public Long getId() { - return id; + return this.id; } - public void setId(Long id) { + public void setId(final Long id) { this.id = id; } public String getLocale() { - return locale; + return this.locale; } - public void setLocale(String locale) { + public void setLocale(final String locale) { this.locale = locale; } public byte[] getImage() { - return image; + return this.image; } - public void setImage(byte[] image) { + public InputStream getImageAsStream() { + return new ByteArrayInputStream(this.image); + } + + public boolean isImagePresent() { + return this.image != null; + } + + public void setImage(final byte[] image) { this.image = image; } public String getContentType() { - return contentType; + return this.contentType; } - public void setContentType(String contentType) { + public void setContentType(final String contentType) { this.contentType = contentType; } public String getImageName() { - return imageName; + return this.imageName; } - public void setImageName(String imageName) { + public void setImageName(final String imageName) { this.imageName = imageName; } - public Optional getImageLink() { - return Optional.ofNullable(imageLink); + public String getImageLink() { + return this.imageLink; } - public void setImageLink(String imageLink) { - this.imageLink = imageLink; + public void setImageLink(final String link) { + this.imageLink = trim(link); + } + + public boolean isImageLinkValid() { + if (isEmpty(this.imageLink)) { + return true; + } else { + try { + new URL(this.imageLink); + return true; + } catch (final MalformedURLException e) { + return false; + } + } } public DataverseBanner getDataverseBanner() { - return dataverseBanner; + return this.dataverseBanner; } - public void setDataverseBanner(DataverseBanner dataverseBanner) { + public void setDataverseBanner(final DataverseBanner dataverseBanner) { this.dataverseBanner = dataverseBanner; } + + public static boolean isOfAllowableType(final String bannerFileName) { + return bannerFileName.endsWith(".jpg") || bannerFileName.endsWith(".jpeg") + || bannerFileName.endsWith(".png"); + } } diff --git a/dataverse-persistence/src/main/resources/Bundle_en.properties b/dataverse-persistence/src/main/resources/Bundle_en.properties index 22768e7cd2..ff34cf038a 100755 --- a/dataverse-persistence/src/main/resources/Bundle_en.properties +++ b/dataverse-persistence/src/main/resources/Bundle_en.properties @@ -77,6 +77,7 @@ show=Show hide=Hide opensInNewTab=(opens in new tab) copyToClipboard=Copy to clipboard +field.required=Value required. common.forms.asterisk.tip=Asterisks indicate required fields common.forms.autocomplete.resultsMessage=results are available, use up and down arrow keys to navigate @@ -189,6 +190,7 @@ dataversemessages.banners.sizeError=The image size was too big. dataversemessages.banners.resolutionError=The image could not be uploaded. Please try again with a image with smaller resolution. dataversemessages.banners.missingError=The image is missing dataversemessages.banners.extensionError=The image could not be uploaded. Please try again with a JPG or PNG file. +dataversemessages.banners.formatError=The image is malformed. dataversemessages.textmessages.new=New Message dataversemessages.textmessages.new.success=Message was saved. dataversemessages.textmessages.noResults=No messages found. @@ -2874,6 +2876,7 @@ edittextmessages.message.watermark=Write up text message for this dataverse. edittextmessages.message.tip=Shown while visiting dataverse using application language option: {0}. textmessages.endDateTime.valid=End date and time must not be earlier than starting date and time. textmessages.endDateTime.future=End date and time must be a future date and time. +textmessages.url.invalid=Invalid URL. error.general.message=An unknown error occured. #language tags language.en=English diff --git a/dataverse-persistence/src/main/resources/Bundle_pl.properties b/dataverse-persistence/src/main/resources/Bundle_pl.properties index 66657fe73b..094c2bb2c6 100644 --- a/dataverse-persistence/src/main/resources/Bundle_pl.properties +++ b/dataverse-persistence/src/main/resources/Bundle_pl.properties @@ -77,6 +77,7 @@ show=Poka\u017C hide=Schowaj opensInNewTab=(otwiera si\u0119 w nowej zak\u0142adce) copyToClipboard=Kopiuj do schowka +field.required=Pole wymagane. common.forms.asterisk.tip=Wymagane pola oznaczone s\u0105 gwiazdk\u0105 common.forms.autocomplete.resultsMessage=wynik\u00F3w jest dost\u0119pnych, u\u017Cyj klawiszy strza\u0142ek w g\u00F3r\u0119 i w d\u00F3\u0142 by wybra\u0107 @@ -189,6 +190,7 @@ dataversemessages.banners.sizeError=Za du\u017Cy rozmiar obrazka dataversemessages.banners.resolutionError=Nie uda\u0142o si\u0119 wczyta\u0107 pliku. Spr\u00F3buj ponownie z plikiem graficznym o ni\u017Cszej rozdzielczo\u015Bci. dataversemessages.banners.missingError=Brak obrazka dataversemessages.banners.extensionError=Nie uda\u0142o si\u0119 wczyta\u0107 pliku. Spr\u00F3buj ponownie z plikiem w formacie JPG, PNG. +dataversemessages.banners.formatError=Obraz jest uszkodzony. dataversemessages.textmessages.new=Nowy komunikat dataversemessages.textmessages.new.success=Komunikat zosta\u0142 zapisany. dataversemessages.textmessages.noResults=Brak komunikat\u00F3w. @@ -2822,6 +2824,7 @@ edittextmessages.message.watermark=Wpisz tre\u015B\u0107 komunikatu dla tej kole edittextmessages.message.tip=Ustawienie j\u0119zyka aplikacji dla kt\u00F3rej komunikat bedzie widoczny: {0}. textmessages.endDateTime.valid=Data i czas zako\u0144czenia nie mo\u017Ce by\u0107 wcze\u015Bniejsza od daty i czasu rozpocz\u0119cia. textmessages.endDateTime.future=Data i czas zako\u0144czenia musi by\u0107 dat\u0105 i czasem w przysz\u0142o\u015Bci. +textmessages.url.invalid=Nieprawid\u0142owy adres URL. error.general.message=Wyst\u0105pi\u0142 nieznany b\u0142\u0105d. #language tags language.en=Angielski diff --git a/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/PermissionsWrapper.java b/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/PermissionsWrapper.java index f87093f27d..663ee17ada 100644 --- a/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/PermissionsWrapper.java +++ b/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/PermissionsWrapper.java @@ -1,5 +1,16 @@ package edu.harvard.iq.dataverse; +import static org.apache.commons.lang.StringUtils.EMPTY; + +import java.util.HashMap; +import java.util.Map; + +import javax.ejb.EJB; +import javax.inject.Inject; +import javax.inject.Named; + +import org.omnifaces.cdi.ViewScoped; + import edu.harvard.iq.dataverse.engine.command.Command; import edu.harvard.iq.dataverse.engine.command.DataverseRequest; import edu.harvard.iq.dataverse.engine.command.impl.AbstractCreateDatasetCommand; @@ -15,13 +26,7 @@ import edu.harvard.iq.dataverse.persistence.dataset.Dataset; import edu.harvard.iq.dataverse.persistence.dataverse.Dataverse; import edu.harvard.iq.dataverse.persistence.user.Permission; -import org.omnifaces.cdi.ViewScoped; - -import javax.ejb.EJB; -import javax.inject.Inject; -import javax.inject.Named; -import java.util.HashMap; -import java.util.Map; +import edu.harvard.iq.dataverse.persistence.user.User; /** * @author gdurand @@ -113,6 +118,12 @@ public boolean canIssueCreateDataverseCommand(DvObject dvo) { public boolean canEditDataverseTextMessagesAndBanners(Long dataverseId) { return permissionService.isUserCanEditDataverseTextMessagesAndBanners(dvRequestService.getDataverseRequest().getUser(), dataverseId); } + + public String authorizedToEditTextMessagesAndBannersOf(final Long dataverseId) { + return canEditDataverseTextMessagesAndBanners(dataverseId) + ? EMPTY + : notAuthorized(); + } public boolean canManagePermissions(DvObject dvo) { if (dvo == null || (dvo.getId() == null)) { diff --git a/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/bannersandmessages/banners/NewBannerPage.java b/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/bannersandmessages/banners/NewBannerPage.java index fd1b182f53..056349f9ce 100644 --- a/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/bannersandmessages/banners/NewBannerPage.java +++ b/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/bannersandmessages/banners/NewBannerPage.java @@ -1,20 +1,15 @@ package edu.harvard.iq.dataverse.bannersandmessages.banners; +import static edu.harvard.iq.dataverse.bannersandmessages.validation.ImageValidator.imageExceedes; import static edu.harvard.iq.dataverse.common.BundleUtil.getStringFromBundle; -import static edu.harvard.iq.dataverse.persistence.config.URLValidator.isURLValid; -import static javax.faces.application.FacesMessage.SEVERITY_ERROR; +import static edu.harvard.iq.dataverse.persistence.dataverse.bannersandmessages.DataverseLocalizedBanner.isOfAllowableType; import static org.apache.commons.lang.StringUtils.EMPTY; -import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.Serializable; -import java.util.Date; - -import javax.ejb.EJB; -import javax.faces.application.FacesMessage; -import javax.faces.component.UIComponent; -import javax.faces.component.UIInput; -import javax.faces.context.FacesContext; -import javax.faces.validator.ValidatorException; +import java.util.List; + +import javax.annotation.PostConstruct; import javax.inject.Inject; import javax.inject.Named; @@ -24,223 +19,194 @@ import org.primefaces.model.StreamedContent; import edu.harvard.iq.dataverse.PermissionsWrapper; -import edu.harvard.iq.dataverse.bannersandmessages.UnsupportedLanguageCleaner; -import edu.harvard.iq.dataverse.bannersandmessages.banners.dto.BannerMapper; -import edu.harvard.iq.dataverse.bannersandmessages.banners.dto.DataverseBannerDto; -import edu.harvard.iq.dataverse.bannersandmessages.banners.dto.DataverseLocalizedBannerDto; -import edu.harvard.iq.dataverse.bannersandmessages.validation.BannerErrorHandler; -import edu.harvard.iq.dataverse.bannersandmessages.validation.DataverseTextMessageValidator; -import edu.harvard.iq.dataverse.bannersandmessages.validation.EndDateMustBeAFutureDate; -import edu.harvard.iq.dataverse.bannersandmessages.validation.EndDateMustNotBeEarlierThanStartingDate; -import edu.harvard.iq.dataverse.bannersandmessages.validation.ImageValidator; import edu.harvard.iq.dataverse.persistence.dataverse.Dataverse; import edu.harvard.iq.dataverse.persistence.dataverse.DataverseRepository; import edu.harvard.iq.dataverse.persistence.dataverse.bannersandmessages.DataverseBanner; -import edu.harvard.iq.dataverse.util.JsfHelper; +import edu.harvard.iq.dataverse.persistence.dataverse.bannersandmessages.DataverseBannerRepository; +import edu.harvard.iq.dataverse.persistence.dataverse.bannersandmessages.DataverseLocalizedBanner; +import edu.harvard.iq.dataverse.settings.SettingsWrapper; +import edu.harvard.iq.dataverse.util.UIMessages; +@SuppressWarnings("serial") @ViewScoped -@Named("EditBannerPage") +@Named public class NewBannerPage implements Serializable { - @EJB - private BannerDAO dao; - - @Inject - private PermissionsWrapper permissionsWrapper; - - @Inject - private BannerErrorHandler errorHandler; - - @Inject - private BannerMapper mapper; - - @EJB - private DataverseRepository dataverseRepo; - - @Inject - private UnsupportedLanguageCleaner languageCleaner; + private final PermissionsWrapper permissionsWrapper; + private final DataverseRepository dataverseRepo; + private final BannerLimits bannerLimits; + private final UIMessages uiMessages; + private final DataverseBannerRepository bannerRepo; + private final SettingsWrapper settingsWrapper; - @Inject - private BannerLimits bannerLimits; - - private Long dataverseId; private Dataverse dataverse; - private Long bannerId; - private String link; - - private UIInput fromTimeInput; - - private DataverseBannerDto dto; - - public String init() { - if (!permissionsWrapper.canEditDataverseTextMessagesAndBanners(dataverseId)) { - return permissionsWrapper.notAuthorized(); - } - - if (dataverseId == null) { - return permissionsWrapper.notFound(); - } - - this.dataverse = this.dataverseRepo.findById(this.dataverseId).get(); + private final DataverseBanner banner = new DataverseBanner(); - dto = bannerId != null ? - mapper.mapToDto(dao.getBanner(bannerId)) : - mapper.mapToNewBanner(dataverseId); - - if (dto.getId() != null) { - languageCleaner.removeBannersLanguagesNotPresentInDataverse(dto); - } - - return EMPTY; + @Inject + public NewBannerPage(final PermissionsWrapper permissionsWrapper, + final DataverseRepository dataverseRepo, + final BannerLimits bannerLimits, + final UIMessages uiMessages, + final DataverseBannerRepository bannerRepo, + final SettingsWrapper settingsWrapper) { + this.permissionsWrapper = permissionsWrapper; + this.dataverseRepo = dataverseRepo; + this.bannerLimits = bannerLimits; + this.uiMessages = uiMessages; + this.bannerRepo = bannerRepo; + this.settingsWrapper = settingsWrapper; } - public boolean hasDisplayLocalizedBanner(DataverseLocalizedBannerDto localizedBanner) { - return localizedBanner.getContent() != null; - } - - public StreamedContent getDisplayLocalizedBanner(DataverseLocalizedBannerDto localizedBanner) { - if (localizedBanner.getContent() == null) { - return null; - } - return DefaultStreamedContent.builder() - .contentType(localizedBanner.getContentType()) - .name(localizedBanner.getFilename()) - .stream(() -> new ByteArrayInputStream(localizedBanner.getContent())) - .build(); - } - - public void uploadFileEvent(FileUploadEvent event) { - - if (ImageValidator.isImageResolutionTooBig(event.getFile().getContent(), - bannerLimits.getMaxWidth(), bannerLimits.getMaxHeight())) { - - FacesContext context = FacesContext.getCurrentInstance(); - context.validationFailed(); - FacesMessage message = new FacesMessage(SEVERITY_ERROR, "", getStringFromBundle("dataversemessages.banners.resolutionError")); - FacesContext.getCurrentInstance().addMessage(event.getComponent().getClientId(context), message); - return; - } - - String locale = (String) event.getComponent().getAttributes() - .get("imageLocale"); - - dto.getDataverseLocalizedBanner().stream() - .filter(dlb -> dlb.getLocale().equals(locale)) - .forEach(dlb -> { - dlb.setContentType(event.getFile().getContentType()); - dlb.setFilename(event.getFile().getFileName()); - dlb.setContent(event.getFile().getContent()); - }); + @PostConstruct + public void init() { + this.settingsWrapper.getConfiguredLocales().keySet() + .forEach(this.banner::addLocalizedBanner); } - public String save() { - DataverseBanner banner = - mapper.mapToEntity(dto, this.dataverseRepo.findById(dto.getDataverseId()).get()); - - banner.getDataverseLocalizedBanner().forEach(dlb -> - errorHandler.handleBannerAddingErrors(banner, dlb, FacesContext.getCurrentInstance())); - - if (errorsOccurred()) { - return EMPTY; - } - - dao.save(banner); - JsfHelper.addFlashSuccessMessage(getStringFromBundle("dataversemessages.banners.new.success")); - return redirectToTextMessages(); + public String verifyAccess() { + return this.dataverseId == null + ? this.permissionsWrapper.notFound() + : this.permissionsWrapper + .authorizedToEditTextMessagesAndBannersOf(this.dataverseId); } - public void validateLink(FacesContext context, UIComponent toValidate, Object rawValue) throws ValidatorException { - String valueStr = (String)rawValue; - - if (!isURLValid(valueStr)) { - String message = "'" + valueStr + "' " + getStringFromBundle("url.invalid"); - throw new ValidatorException(new FacesMessage(SEVERITY_ERROR, "", message)); - } + public DataverseBanner getBanner() { + return this.banner; } - - public void validateEndDateTime(FacesContext context, UIComponent toValidate, Object rawValue) throws ValidatorException { - Date toDate = (Date) rawValue; - Date fromDate = (Date)fromTimeInput.getValue(); - try { - DataverseTextMessageValidator.validateEndDate(fromDate, toDate); - } catch (EndDateMustNotBeEarlierThanStartingDate e) { - throw new ValidatorException(new FacesMessage(SEVERITY_ERROR, "", getStringFromBundle("textmessages.endDateTime.valid"))); - } catch (EndDateMustBeAFutureDate e) { - throw new ValidatorException(new FacesMessage(SEVERITY_ERROR, "", getStringFromBundle("textmessages.endDateTime.future"))); + public StreamedContent getBannerImage( + final DataverseLocalizedBanner localizedBanner) { + if (localizedBanner.isImagePresent()) { + return DefaultStreamedContent.builder() + .contentType(localizedBanner.getContentType()) + .name(localizedBanner.getImageName()) + .stream(localizedBanner::getImageAsStream) + .build(); + } else { + return null; } } - public int getBannerFileSizeLimit() { - return bannerLimits.getMaxSizeInBytes(); - } - - private boolean errorsOccurred() { - return FacesContext.getCurrentInstance().getMessageList().size() > 0; - } - - public String cancel() { - return redirectToTextMessages(); - } - - private String redirectToTextMessages() { - return "/dataverse-textMessages.xhtml?dataverseId=" + dataverseId + "&activeTab=banners&faces-redirect=true"; - } - - public PermissionsWrapper getPermissionsWrapper() { - return permissionsWrapper; - } - - public void setPermissionsWrapper(PermissionsWrapper permissionsWrapper) { - this.permissionsWrapper = permissionsWrapper; - } - public Long getDataverseId() { - return dataverseId; + return this.dataverseId; } - public void setDataverseId(Long dataverseId) { + public void setDataverseId(final Long dataverseId) { this.dataverseId = dataverseId; + this.dataverse = this.dataverseRepo.findById(this.dataverseId).orElse(null); } public Dataverse getDataverse() { - return dataverse; + return this.dataverse; } - public void setDataverse(Dataverse dataverse) { - this.dataverse = dataverse; - } + public void uploadFileEvent(final FileUploadEvent event) { + if (isFileCorrect(event)) { + final String locale = (String) event.getComponent().getAttributes() + .get("imageLocale"); - public Long getBannerId() { - return bannerId; - } - - public void setBannerId(Long bannerId) { - this.bannerId = bannerId; + this.banner.getBannerFor(locale).ifPresent(lb -> { + lb.setContentType(event.getFile().getContentType()); + lb.setImageName(event.getFile().getFileName()); + lb.setImage(event.getFile().getContent()); + }); + } } - public DataverseBannerDto getDto() { - return dto; + private boolean isFileCorrect(final FileUploadEvent event) { + boolean result = true; + try { + if (event.getFile().getSize() > this.bannerLimits.getMaxSizeInBytes()) { + this.uiMessages.addComponentErrorMessage(event.getComponent(), + getStringFromBundle("dataversemessages.banners.sizeError")); + result = false; + } + if (imageExceedes(event.getFile().getInputStream(), this.bannerLimits)) { + this.uiMessages.addComponentErrorMessage(event.getComponent(), + getStringFromBundle( + "dataversemessages.banners.resolutionError")); + result = false; + } + if (!isOfAllowableType(event.getFile().getFileName())) { + this.uiMessages.addComponentErrorMessage(event.getComponent(), + getStringFromBundle( + "dataversemessages.banners.extensionError")); + result = false; + } + } catch (final IOException e) { + this.uiMessages.addComponentErrorMessage(event.getComponent(), + getStringFromBundle("dataversemessages.banners.formatError")); + result = false; + } + return result; } - public void setDto(DataverseBannerDto dto) { - this.dto = dto; + public String save() { + if (isDataCorrect()) { + this.bannerRepo.save(banner); + this.uiMessages.addFlashSuccessMessage( + getStringFromBundle("dataversemessages.banners.new.success")); + return redirectToTextMessages(); + } else { + return EMPTY; + } } - public UIInput getFromTimeInput() { - return fromTimeInput; - } + private boolean isDataCorrect() { + boolean result = true; + final List banners = this.banner + .getLocalizedBanners(); + for (int index = 0; index < banners.size(); ++index) { + if (!banners.get(index).isImagePresent()) { + this.uiMessages.addComponentErrorMessage( + "edit-text-messages-form:repeater:" + index + ":upload", + getStringFromBundle( + "dataversemessages.banners.missingError")); + result = false; + } + if (!banners.get(index).isImageLinkValid()) { + this.uiMessages.addComponentErrorMessage( + "edit-text-messages-form:repeater:" + index + + ":message-link", + getStringFromBundle("textmessages.url.invalid")); + result = false; + } + } - public void setFromTimeInput(UIInput fromTimeInput) { - this.fromTimeInput = fromTimeInput; + if (!this.banner.isFromTimePresent()) { + this.uiMessages.addComponentErrorMessage( + "edit-text-messages-form:message-fromtime", + getStringFromBundle("field.required")); + result = false; + } + if (!this.banner.isToTimePresent()) { + this.uiMessages.addComponentErrorMessage( + "edit-text-messages-form:message-totime", + getStringFromBundle("field.required")); + result = false; + } + if (!this.banner.isFromTimeBeforeEndTime()) { + this.uiMessages.addComponentErrorMessage( + "edit-text-messages-form:message-totime", + getStringFromBundle("textmessages.endDateTime.valid")); + result = false; + } + if (!this.banner.isToTimeInFuture()) { + this.uiMessages.addComponentErrorMessage( + "edit-text-messages-form:message-totime", + getStringFromBundle("textmessages.endDateTime.future")); + result = false; + } + return result; } - public String getLink() { - return link; + public String cancel() { + return redirectToTextMessages(); } - public void setLink(String link) { - this.link = link; + private String redirectToTextMessages() { + return "/dataverse-textMessages.xhtml?activeTab=banners&faces-redirect=true&dataverseId=" + + this.dataverseId; } } diff --git a/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/bannersandmessages/banners/dto/BannerMapper.java b/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/bannersandmessages/banners/dto/BannerMapper.java index 1b2ccb27a9..2c7cf83076 100644 --- a/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/bannersandmessages/banners/dto/BannerMapper.java +++ b/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/bannersandmessages/banners/dto/BannerMapper.java @@ -41,12 +41,12 @@ public DataverseBannerDto mapToDto(DataverseBanner dataverseBanner) { List dlbDto = new ArrayList<>(); - for (DataverseLocalizedBanner dlb : dataverseBanner.getDataverseLocalizedBanner()) { + for (DataverseLocalizedBanner dlb : dataverseBanner.getLocalizedBanners()) { DataverseLocalizedBannerDto localBannerDto = new DataverseLocalizedBannerDto(dlb.getId(), dlb.getLocale(), - dlb.getImageLink().isPresent() ? - dlb.getImageLink().get() : StringUtils.EMPTY); + dlb.getImageLink() != null ? + dlb.getImageLink(): StringUtils.EMPTY); localBannerDto.setContent(dlb.getImage()); localBannerDto.setContentType(dlb.getContentType()); @@ -80,7 +80,7 @@ public DataverseBanner mapToEntity(DataverseBannerDto dto, Dataverse dataverse) .forEach(fuDto -> { DataverseLocalizedBanner dataverseLocalizedBanner = mapToLocalizedBanner(banner, fuDto); - banner.getDataverseLocalizedBanner().add(dataverseLocalizedBanner); + banner.getLocalizedBanners().add(dataverseLocalizedBanner); }); return banner; @@ -114,8 +114,9 @@ private DataverseLocalizedBanner mapToLocalizedBanner(DataverseBanner banner, Da } private List mapDefaultLocales() { + Map locales = settingsWrapper.getConfiguredLocales(); - + return locales.entrySet().stream() .map(e -> new DataverseLocalizedBannerDto(e.getKey())) .collect(Collectors.toList()); diff --git a/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/bannersandmessages/banners/dto/DataverseBannerDto.java b/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/bannersandmessages/banners/dto/DataverseBannerDto.java index 80cffa97f2..6643485e4f 100644 --- a/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/bannersandmessages/banners/dto/DataverseBannerDto.java +++ b/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/bannersandmessages/banners/dto/DataverseBannerDto.java @@ -3,7 +3,6 @@ import edu.harvard.iq.dataverse.common.DateUtil; import javax.validation.Valid; -import javax.validation.constraints.NotNull; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; @@ -13,10 +12,8 @@ public class DataverseBannerDto { private Long id; - @NotNull(message = "{field.required}") private Date fromTime; - @NotNull(message = "{field.required}") private Date toTime; private boolean active; diff --git a/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/bannersandmessages/validation/BannerErrorHandler.java b/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/bannersandmessages/validation/BannerErrorHandler.java deleted file mode 100644 index 3f6b51f891..0000000000 --- a/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/bannersandmessages/validation/BannerErrorHandler.java +++ /dev/null @@ -1,68 +0,0 @@ -package edu.harvard.iq.dataverse.bannersandmessages.validation; - -import edu.harvard.iq.dataverse.bannersandmessages.banners.BannerLimits; -import edu.harvard.iq.dataverse.common.BundleUtil; -import edu.harvard.iq.dataverse.persistence.dataverse.bannersandmessages.DataverseBanner; -import edu.harvard.iq.dataverse.persistence.dataverse.bannersandmessages.DataverseLocalizedBanner; - -import javax.ejb.Stateless; -import javax.faces.application.FacesMessage; -import javax.faces.context.FacesContext; -import javax.inject.Inject; - -import java.util.List; - -/** - * Class which handles errors when adding new banner that can't be validated by standard jsf - * validators. Errors are displayed thanks to - */ -@Stateless -public class BannerErrorHandler { - - private BannerLimits bannerLimits; - - public BannerErrorHandler() { - } - - @Inject - public BannerErrorHandler(BannerLimits bannerLimits) { - this.bannerLimits = bannerLimits; - } - - // -------------------- LOGIC -------------------- - - public List handleBannerAddingErrors(DataverseBanner banner, - DataverseLocalizedBanner dlb, - FacesContext faceContext) { - - int localizedBannerIndex = banner.getDataverseLocalizedBanner().indexOf(dlb); - - if (dlb.getImage().length < 1) { - addErrorMessageImageWasMissing(faceContext, localizedBannerIndex); - - } else if (ImageValidator.isImageResolutionTooBig(dlb.getImage(), - bannerLimits.getMaxWidth(), bannerLimits.getMaxHeight())) { - addErrorMessageResolutionTooBigError(faceContext, localizedBannerIndex); - } - - return faceContext.getMessageList(); - } - - // -------------------- PRIVATE -------------------- - - private void addErrorMessageResolutionTooBigError(FacesContext faceContext, int index) { - - faceContext.addMessage("edit-text-messages-form:repeater:" + index + ":upload", - new FacesMessage(FacesMessage.SEVERITY_ERROR, BundleUtil.getStringFromBundle("messages.error"), - BundleUtil.getStringFromBundle("dataversemessages.banners.resolutionError"))); - - } - - private void addErrorMessageImageWasMissing(FacesContext faceContext, int index) { - - faceContext.addMessage("edit-text-messages-form:repeater:" + index + ":upload", - new FacesMessage(FacesMessage.SEVERITY_ERROR, BundleUtil.getStringFromBundle("messages.error"), - BundleUtil.getStringFromBundle("dataversemessages.banners.missingError"))); - - } -} diff --git a/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/bannersandmessages/validation/ImageValidator.java b/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/bannersandmessages/validation/ImageValidator.java index 484b0365cb..30c455c712 100644 --- a/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/bannersandmessages/validation/ImageValidator.java +++ b/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/bannersandmessages/validation/ImageValidator.java @@ -1,6 +1,9 @@ package edu.harvard.iq.dataverse.bannersandmessages.validation; import javax.imageio.ImageIO; + +import edu.harvard.iq.dataverse.bannersandmessages.banners.BannerLimits; + import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -25,4 +28,14 @@ public static boolean isImageResolutionTooBig(byte[] imageBytes, int maxWidth, i return buf != null && (buf.getWidth() > maxWidth || buf.getHeight() > maxHeight); } + + public static boolean imageExceedes(final InputStream in, final BannerLimits limits) + throws IOException { + final BufferedImage img = ImageIO.read(in); + if (img != null) { + return img.getWidth() > limits.getMaxWidth() || img.getHeight() > limits.getMaxHeight(); + } else { + throw new IOException("Unsupported image format"); + } + } } diff --git a/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/util/UIMessages.java b/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/util/UIMessages.java index 6113718b1e..738f0bc177 100644 --- a/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/util/UIMessages.java +++ b/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/util/UIMessages.java @@ -1,15 +1,67 @@ package edu.harvard.iq.dataverse.util; +import static edu.harvard.iq.dataverse.common.BundleUtil.getStringFromBundle; +import static javax.faces.application.FacesMessage.SEVERITY_ERROR; + import javax.ejb.Stateless; +import javax.faces.application.FacesMessage; +import javax.faces.component.UIComponent; +import javax.faces.context.FacesContext; + +import org.primefaces.PrimeFaces; @Stateless public class UIMessages { - + public void addSuccessMessage(final String message) { - JsfHelper.addSuccessMessage(message); + addComponentSuccessMessage("successMessage", + getStringFromBundle("messages.success"), message); } - + public void addErrorMessage(final String message) { - JsfHelper.addErrorMessage(message); + addAjaxHasErrorParam(); + addComponentErrorMessage((String) null, message); + } + + public void addFlashSuccessMessage(final String message) { + addAjaxHasErrorParam(); + addSuccessMessage(message); + } + + private static void addAjaxHasErrorParam() { + PrimeFaces.current().ajax().addCallbackParam("hasErrorMessage", true); + } + + public void addComponentSuccessMessage(final String componentId, + final String summary, final String detail) { + FacesContext.getCurrentInstance().addMessage(componentId, + new FacesMessage(summary, detail)); + } + + public void addComponentErrorMessage(final String componentId, + final String summary, final String detail) { + FacesContext.getCurrentInstance().addMessage(componentId, + new FacesMessage(SEVERITY_ERROR, summary, detail)); + } + + public void addComponentErrorMessage(final String componentId, + final String detail) { + FacesContext.getCurrentInstance().addMessage(componentId, + new FacesMessage(SEVERITY_ERROR, + getStringFromBundle("messages.error"), detail)); + } + + public void addComponentErrorMessage(final UIComponent component, + final String summary, final String detail) { + final FacesContext context = FacesContext.getCurrentInstance(); + final String componentId = component.getClientId(context); + addComponentErrorMessage(componentId, summary, detail); + } + + public void addComponentErrorMessage(final UIComponent component, + final String detail) { + final FacesContext context = FacesContext.getCurrentInstance(); + final String componentId = component.getClientId(context); + addComponentErrorMessage(componentId, detail); } } diff --git a/dataverse-webapp/src/main/webapp/dataverse-newBannerPage.xhtml b/dataverse-webapp/src/main/webapp/dataverse-newBannerPage.xhtml index 4835bb9a9f..249edb5149 100644 --- a/dataverse-webapp/src/main/webapp/dataverse-newBannerPage.xhtml +++ b/dataverse-webapp/src/main/webapp/dataverse-newBannerPage.xhtml @@ -10,17 +10,16 @@ - - - - + + + + ('/dataverse-textMessages.xhtml?dataverseId='.concat(newBannerPage.dataverseId),bundle['dataverse.option.textMessages'])}"/> - +

#{bundle['dataversemessages.banners.new']}

@@ -31,55 +30,60 @@

- + +

- +
-
-
- #{settingsWrapper.getConfiguredLocaleName(lm.locale)} - +
+
+ #{settingsWrapper.getConfiguredLocaleName(localizedBanner.locale)} +

#{bundle['dataversemessages.banners.file.tip']}

- -
- - - -
+ + +
- +
-
- -
+
+ +
- + - - +
@@ -95,17 +99,13 @@

#{bundle['edittextmessages.startDateTime.format.tip']}

+ converterMessage="#{bundle['common.forms.calendar.dateAndTime.conversionMessage']}"/>

#{bundle['edittextmessages.endDateTime.format.tip']}

+ converterMessage="#{bundle['common.forms.calendar.dateAndTime.conversionMessage']}"/> +
@@ -152,11 +149,10 @@
+ action="#{newBannerPage.save()}" update="@form"/> + action="#{newBannerPage.cancel()}" immediate="true"/>
-
diff --git a/dataverse-webapp/src/test/java/edu/harvard/iq/dataverse/bannersandmessages/banners/dto/BannerMapperTest.java b/dataverse-webapp/src/test/java/edu/harvard/iq/dataverse/bannersandmessages/banners/dto/BannerMapperTest.java index 9e46f27dbe..104a11b0d2 100644 --- a/dataverse-webapp/src/test/java/edu/harvard/iq/dataverse/bannersandmessages/banners/dto/BannerMapperTest.java +++ b/dataverse-webapp/src/test/java/edu/harvard/iq/dataverse/bannersandmessages/banners/dto/BannerMapperTest.java @@ -45,14 +45,14 @@ public void shouldMapToDto() throws IOException { //when DataverseBannerDto bannerDto = bannerMapper.mapToDto(dataverseBanner); DataverseLocalizedBannerDto localizedBannerDto = bannerDto.getDataverseLocalizedBanner().get(0); - DataverseLocalizedBanner localizedBanner = dataverseBanner.getDataverseLocalizedBanner().get(0); + DataverseLocalizedBanner localizedBanner = dataverseBanner.getLocalizedBanners().get(0); //then Assertions.assertEquals(bannerDto.getDataverseId(), dataverseBanner.getDataverse().getId()); Assertions.assertEquals(bannerDto.getFromTime(), dataverseBanner.getFromTime()); Assertions.assertEquals(bannerDto.getToTime(), dataverseBanner.getToTime()); Assertions.assertEquals(localizedBanner.getLocale(), localizedBannerDto.getLocale()); - Assertions.assertEquals(localizedBanner.getImageLink().get(), localizedBannerDto.getImageLink()); + Assertions.assertEquals(localizedBanner.getImageLink(), localizedBannerDto.getImageLink()); } @Test @@ -69,7 +69,7 @@ public void shouldMapToNewEntity() { DataverseBanner banner = bannerMapper.mapToEntity(bannerDto, dataverse); //then - DataverseLocalizedBanner localizedBanner = banner.getDataverseLocalizedBanner().get(0); + DataverseLocalizedBanner localizedBanner = banner.getLocalizedBanners().get(0); Assertions.assertEquals(banner.getDataverse().getId(), bannerDto.getDataverseId()); Assertions.assertEquals(banner.getFromTime(), bannerDto.getFromTime()); Assertions.assertEquals(banner.getToTime(), bannerDto.getToTime()); @@ -77,7 +77,7 @@ public void shouldMapToNewEntity() { Assertions.assertEquals(localizedBanner.getLocale(), localizedBannerDto.getLocale()); Assertions.assertEquals(localizedBanner.getContentType(), localizedBannerDto.getContentType()); Assertions.assertEquals(localizedBanner.getImageName(), localizedBannerDto.getFilename()); - Assertions.assertEquals(localizedBanner.getImageLink().get(), localizedBannerDto.getImageLink()); + Assertions.assertEquals(localizedBanner.getImageLink(), localizedBannerDto.getImageLink()); } @Test @@ -110,7 +110,7 @@ private DataverseBanner createBannerEntity() throws IOException { dataverseLocalizedBanner.setImageName("Best Image"); dataverseLocalizedBanner.setImage(bannerFile); dataverseLocalizedBanner.setImageLink("www.google.pl"); - dataverseBanner.setDataverseLocalizedBanner(Lists.newArrayList(dataverseLocalizedBanner)); + dataverseBanner.setLocalizedBanners(Lists.newArrayList(dataverseLocalizedBanner)); return dataverseBanner; } diff --git a/dataverse-webapp/src/test/java/edu/harvard/iq/dataverse/bannersandmessages/validation/BannerErrorHandlerTest.java b/dataverse-webapp/src/test/java/edu/harvard/iq/dataverse/bannersandmessages/validation/BannerErrorHandlerTest.java deleted file mode 100644 index b5c2979274..0000000000 --- a/dataverse-webapp/src/test/java/edu/harvard/iq/dataverse/bannersandmessages/validation/BannerErrorHandlerTest.java +++ /dev/null @@ -1,80 +0,0 @@ -package edu.harvard.iq.dataverse.bannersandmessages.validation; - -import com.google.common.collect.Lists; -import edu.harvard.iq.dataverse.bannersandmessages.banners.BannerLimits; -import edu.harvard.iq.dataverse.persistence.dataverse.bannersandmessages.DataverseBanner; -import edu.harvard.iq.dataverse.persistence.dataverse.bannersandmessages.DataverseLocalizedBanner; -import org.apache.commons.io.IOUtils; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; - -import javax.faces.application.FacesMessage; -import javax.faces.context.ExternalContext; -import javax.faces.context.FacesContext; -import java.util.Locale; - -@ExtendWith(MockitoExtension.class) -public class BannerErrorHandlerTest { - - @Mock - private FacesContext facesContextMock; - @Mock - private ExternalContext externalContextMock; - @Mock - private Locale locale; - @Captor - private ArgumentCaptor facesMesssage; - - - private byte[] loadImage() throws Exception { - - return IOUtils.toByteArray(getClass().getClassLoader().getResource("images/banner.png")); - } - - @Test - public void shouldAddErrorMessageImageMissing() { - //given - BannerErrorHandler bannerErrorHandler = new BannerErrorHandler(new BannerLimits()); - DataverseBanner banner = new DataverseBanner(); - DataverseLocalizedBanner dataverseLocalizedBanner = new DataverseLocalizedBanner(); - dataverseLocalizedBanner.setImage(new byte[0]); - banner.setDataverseLocalizedBanner(Lists.newArrayList(dataverseLocalizedBanner)); - - //when - bannerErrorHandler.handleBannerAddingErrors(banner, dataverseLocalizedBanner, facesContextMock); - //then - Mockito.verify(facesContextMock).addMessage(Mockito.eq("edit-text-messages-form:repeater:" + 0 + ":upload"), - facesMesssage.capture()); - FacesMessage message = facesMesssage.getValue(); - - Assertions.assertEquals("The image is missing", message.getDetail()); - - } - - @Test - public void shouldAddErrorMessageResolutionTooHigh() throws Exception { - //given - BannerErrorHandler bannerErrorHandler = new BannerErrorHandler(new BannerLimits(1, 1, Integer.MAX_VALUE)); - DataverseBanner banner = new DataverseBanner(); - DataverseLocalizedBanner dataverseLocalizedBanner = new DataverseLocalizedBanner(); - dataverseLocalizedBanner.setImage(loadImage()); - banner.setDataverseLocalizedBanner(Lists.newArrayList(dataverseLocalizedBanner)); - - //when - bannerErrorHandler.handleBannerAddingErrors(banner, dataverseLocalizedBanner, facesContextMock); - - //then - Mockito.verify(facesContextMock).addMessage(Mockito.eq("edit-text-messages-form:repeater:" + 0 + ":upload"), - facesMesssage.capture()); - FacesMessage message = facesMesssage.getValue(); - - Assertions.assertEquals("The image could not be uploaded. Please try again with a image with smaller resolution.", message.getDetail()); - - } -}