diff --git a/.gitignore b/.gitignore index 3792e187a50799c0892a02e0d25e3c3c15df6e98..b8535f8bc274fa59fc16aa2e6535687342e435ee 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ /bin/ /target/ /cargo/ +/screenshots/ /.settings/ /.externalToolBuilders/ diff --git a/src/main/java/org/olat/admin/user/SystemRolesAndRightsController.java b/src/main/java/org/olat/admin/user/SystemRolesAndRightsController.java index 572dc4fe9cc51509bc31c612e0338163c2b74f45..6ac8f5d40a94de807539cd3bdcff452c0e046cb1 100644 --- a/src/main/java/org/olat/admin/user/SystemRolesAndRightsController.java +++ b/src/main/java/org/olat/admin/user/SystemRolesAndRightsController.java @@ -27,6 +27,7 @@ package org.olat.admin.user; import java.util.ArrayList; import java.util.Collection; +import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -46,6 +47,7 @@ import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; import org.olat.core.gui.components.form.flexible.elements.SingleSelection; import org.olat.core.gui.components.form.flexible.elements.SpacerElement; +import org.olat.core.gui.components.form.flexible.elements.StaticTextElement; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; @@ -60,6 +62,9 @@ import org.olat.core.id.Organisation; import org.olat.core.id.OrganisationRef; import org.olat.core.id.Roles; import org.olat.core.id.RolesByOrganisation; +import org.olat.core.util.Formatter; +import org.olat.user.UserLifecycleManager; +import org.olat.user.UserModule; import org.springframework.beans.factory.annotation.Autowired; /** @@ -82,6 +87,12 @@ import org.springframework.beans.factory.annotation.Autowired; */ public class SystemRolesAndRightsController extends FormBasicController { + private StaticTextElement lastLoginEl; + private StaticTextElement inactivationDateEl; + private StaticTextElement reactivationDateEl; + private StaticTextElement daysInactivationEl; + private StaticTextElement daysDeletionEl; + private SpacerElement rolesSep; private SingleSelection statusEl; private SingleSelection anonymousEl; @@ -110,10 +121,14 @@ public class SystemRolesAndRightsController extends FormBasicController { @Autowired private DB dbInstance; @Autowired + private UserModule userModule; + @Autowired private BaseSecurity securityManager; @Autowired private OrganisationService organisationService; @Autowired + private UserLifecycleManager userLifecycleManager; + @Autowired private UserBulkChangeManager userBulkChangeManager; /** @@ -182,10 +197,27 @@ public class SystemRolesAndRightsController extends FormBasicController { formLayout.add(rolesCont); initFormRoles(); - + initFormStatus(ureq, formLayout, iAmAdmin, iAmUserManager); + } + + private void initFormRoles() { + for(Organisation organisation:organisations) { + initFormRoles(rolesCont, organisation); + } + List<Organisation> upgradeableToOrganisations = new ArrayList<>(manageableOrganisations); + upgradeableToOrganisations.removeAll(organisations); + if(!upgradeableToOrganisations.isEmpty()) { + addToOrganisationButton = uifactory.addFormLink("rightsForm.add.to.organisation", rolesCont, Link.BUTTON); + } + + rolesSep = uifactory.addSpacerElement("rolesSep", rolesCont, false); + } + + private void initFormStatus(UserRequest ureq, FormItemContainer formLayout, boolean iAmAdmin, boolean iAmUserManager) { FormLayoutContainer statusCont = FormLayoutContainer.createDefaultFormLayout("statusc", getTranslator()); formLayout.add(statusCont); + // status statusEl = uifactory.addRadiosVertical("status", "rightsForm.status", statusCont, statusKeys.keys(), statusKeys.values()); statusEl.addActionListener(FormEvent.ONCHANGE); sendLoginDeniedEmailEl = uifactory.addCheckboxesHorizontal("rightsForm.sendLoginDeniedEmail", statusCont, new String[]{"y"}, new String[]{translate("rightsForm.sendLoginDeniedEmail")}); @@ -195,24 +227,18 @@ public class SystemRolesAndRightsController extends FormBasicController { statusEl.setVisible(iAmAdmin || iAmUserManager); sendLoginDeniedEmailEl.setVisible(false); + // life cycle information + lastLoginEl = uifactory.addStaticTextElement("rightsForm.last.login", "", statusCont); + inactivationDateEl = uifactory.addStaticTextElement("rightsForm.inactivation.date", "", statusCont); + reactivationDateEl = uifactory.addStaticTextElement("rightsForm.reactivation.date", "", statusCont); + daysInactivationEl = uifactory.addStaticTextElement("rightsForm.days.inactivation", "", statusCont); + daysDeletionEl = uifactory.addStaticTextElement("rightsForm.days.deletion", "", statusCont); + FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttonGroupLayout", getTranslator()); statusCont.add(buttonGroupLayout); uifactory.addFormCancelButton("cancel", buttonGroupLayout, ureq, getWindowControl()); uifactory.addFormSubmitButton("submit", buttonGroupLayout); } - - private void initFormRoles() { - for(Organisation organisation:organisations) { - initFormRoles(rolesCont, organisation); - } - List<Organisation> upgradeableToOrganisations = new ArrayList<>(manageableOrganisations); - upgradeableToOrganisations.removeAll(organisations); - if(!upgradeableToOrganisations.isEmpty()) { - addToOrganisationButton = uifactory.addFormLink("rightsForm.add.to.organisation", rolesCont, Link.BUTTON); - } - - rolesSep = uifactory.addSpacerElement("rolesSep", rolesCont, false); - } private void initFormRoles(FormItemContainer formLayout, Organisation organisation) { boolean admin = managerRoles.hasRoleInParentLine(organisation, OrganisationRoles.administrator) @@ -357,6 +383,29 @@ public class SystemRolesAndRightsController extends FormBasicController { setStatus(editedIdentity.getStatus()); wrapper.getRolesEl().setVisible(!isAnonymous()); rolesSep.setVisible(!isAnonymous()); + + Formatter formatter = Formatter.getInstance(getLocale()); + lastLoginEl.setValue(formatter.formatDateAndTime(editedIdentity.getLastLogin())); + + Date inactivationDate = editedIdentity.getInactivationDate(); + inactivationDateEl.setValue(formatter.formatDate(inactivationDate)); + inactivationDateEl.setVisible(inactivationDate != null); + + Date reactivationDate = editedIdentity.getReactivationDate(); + reactivationDateEl.setValue(formatter.formatDate(reactivationDate)); + reactivationDateEl.setVisible(reactivationDate != null); + + Date now = new Date(); + long daysBeforeDeactivation = userLifecycleManager.getDaysUntilDeactivation(editedIdentity, now); + daysInactivationEl.setValue(Long.toString(daysBeforeDeactivation)); + daysInactivationEl.setVisible(userModule.isUserAutomaticDeactivation() + && (editedIdentity.getStatus().equals(Identity.STATUS_ACTIV) + || editedIdentity.getStatus().equals(Identity.STATUS_PENDING) + || editedIdentity.getStatus().equals(Identity.STATUS_LOGIN_DENIED))); + + long daysBeforeDeletion = userLifecycleManager.getDaysUntilDeletion(editedIdentity, now); + daysDeletionEl.setValue(Long.toString(daysBeforeDeletion)); + daysDeletionEl.setVisible(userModule.isUserAutomaticDeletion() && editedIdentity.getInactivationDate() != null); } private void setStatus(Integer status) { diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties index 8ea86bd3ded7c979fe169a1775dcb853a804180a..0fde36b33dd7065b3359c7e889a92723aca5df59 100644 --- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties @@ -93,8 +93,13 @@ poolsmanager=Poolverwalter repocoach=Kursbetreuer rightForm.error.anonymous.no.roles=Anonyme G\u00E4ste k\u00F6nnen keine Systemrollen wahrnehmen rightsForm.add.to.organisation=Zur Organisation hinzuf\u00FCgen +rightsForm.days.deletion=Tage bis l\u00F6schen +rightsForm.days.inactivation=Tage bis inaktivieren rightsForm.guest=Benutzertyp +rightsForm.inactivation.date=Inaktivierungsdatum rightsForm.isLoginDenied=Login gesperrt +rightsForm.last.login=Letzter Login +rightsForm.reactivation.date=Reaktivierungsdatum rightsForm.roles=Rollen rightsForm.roles.for=Rollen f\u00FCr "{0}" rightsForm.sendLoginDeniedEmail=Benutzer \u00FCber Loginsperre informieren diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties index 0abd707398232444f1b9f1dae2f7afef70daa71e..ee23fc6ade76e7b130e38a36e19a87d75db23124 100644 --- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties @@ -93,8 +93,13 @@ poolsmanager=Question bank manager repocoach=Course coach rightForm.error.anonymous.no.roles=Anonymous guests cannot exercise system roles rightsForm.add.to.organisation=Add to organisation +rightsForm.days.deletion=Days until deletion +rightsForm.days.inactivation=Days until deactivation rightsForm.guest=User type +rightsForm.inactivation.date=Inactivation date rightsForm.isLoginDenied=Login locked +rightsForm.last.login=Last login +rightsForm.reactivation.date=Reactivation date rightsForm.roles=Roles rightsForm.roles.for=Roles for "{0}" rightsForm.sendLoginDeniedEmail=Notify user about login denied change diff --git a/src/main/java/org/olat/admin/user/imp/TransientIdentity.java b/src/main/java/org/olat/admin/user/imp/TransientIdentity.java index eaa0276b2a0c61f4f5199b30b3c6d34561778e6d..f7356fc82fa573ba6eaa6b79157748327c0c7755 100644 --- a/src/main/java/org/olat/admin/user/imp/TransientIdentity.java +++ b/src/main/java/org/olat/admin/user/imp/TransientIdentity.java @@ -136,6 +136,11 @@ public class TransientIdentity implements Identity, User { return null; } + @Override + public Date getReactivationDate() { + return null; + } + @Override public boolean equalsByPersistableKey(Persistable persistable) { return super.equals(persistable); diff --git a/src/main/java/org/olat/admin/user/imp/UpdateIdentity.java b/src/main/java/org/olat/admin/user/imp/UpdateIdentity.java index 4667a5496ceb6d74d6f6e08f44e66c0d5888f540..030ef16a307b9b6bbd868af75ab92e627753c2aa 100644 --- a/src/main/java/org/olat/admin/user/imp/UpdateIdentity.java +++ b/src/main/java/org/olat/admin/user/imp/UpdateIdentity.java @@ -123,6 +123,11 @@ public class UpdateIdentity implements Identity { return identity.getInactivationDate(); } + @Override + public Date getReactivationDate() { + return identity.getReactivationDate(); + } + @Override public int hashCode() { return identity.hashCode(); diff --git a/src/main/java/org/olat/basesecurity/IdentityImpl.java b/src/main/java/org/olat/basesecurity/IdentityImpl.java index 6b4a09d1412f4d889b5a035f6edee2ee18a9b906..4b25aa9a138bcf47214bc45c2f96cd544ee11c41 100644 --- a/src/main/java/org/olat/basesecurity/IdentityImpl.java +++ b/src/main/java/org/olat/basesecurity/IdentityImpl.java @@ -220,6 +220,7 @@ public class IdentityImpl implements Identity, IdentityRef, CreateInfo, Persista this.inactivationEmailDate = inactivationEmailDate; } + @Override public Date getReactivationDate() { return reactivationDate; } diff --git a/src/main/java/org/olat/basesecurity/manager/IdentityPowerSearchQueriesImpl.java b/src/main/java/org/olat/basesecurity/manager/IdentityPowerSearchQueriesImpl.java index 0aad97bc76c1031833b973f34ee039d7406a4127..42a9c327e55e9404b5937f4dd2b2026282db6f0d 100644 --- a/src/main/java/org/olat/basesecurity/manager/IdentityPowerSearchQueriesImpl.java +++ b/src/main/java/org/olat/basesecurity/manager/IdentityPowerSearchQueriesImpl.java @@ -97,7 +97,8 @@ public class IdentityPowerSearchQueriesImpl implements IdentityPowerSearchQuerie .append(" ident.creationDate as ident_cDate,") .append(" ident.lastLogin as ident_lDate,") .append(" ident.status as ident_Status,") - .append(" ident.inactivationDate as ident_iDate,"); + .append(" ident.inactivationDate as ident_iDate,") + .append(" ident.reactivationDate as ident_rDate,"); writeUserProperties("user", sb, userPropertyHandlers); sb.append(" user.key as ident_user_id") .append(" from ").append(IdentityImpl.class.getCanonicalName()).append(" as ident ") @@ -121,13 +122,15 @@ public class IdentityPowerSearchQueriesImpl implements IdentityPowerSearchQuerie Date lastLogin = (Date)rawObject[pos++]; Integer status = (Integer)rawObject[pos++]; Date inactivationDate = (Date)rawObject[pos++]; + Date reactivationDate = (Date)rawObject[pos++]; String[] userProperties = new String[numOfProperties]; for(int i=0; i<numOfProperties; i++) { userProperties[i] = (String)rawObject[pos++]; } - rows.add(new IdentityPropertiesRow(identityKey, creationDate, lastLogin, status, inactivationDate, + rows.add(new IdentityPropertiesRow(identityKey, creationDate, lastLogin, status, + inactivationDate, reactivationDate, userPropertyHandlers, userProperties, locale)); } return rows; diff --git a/src/main/java/org/olat/basesecurity/model/IdentityPropertiesRow.java b/src/main/java/org/olat/basesecurity/model/IdentityPropertiesRow.java index 08caed5c22d67d12185141f66867d276460f85df..140f68cd3e8c82723980953a107b08c4daf2525a 100644 --- a/src/main/java/org/olat/basesecurity/model/IdentityPropertiesRow.java +++ b/src/main/java/org/olat/basesecurity/model/IdentityPropertiesRow.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Locale; import org.olat.core.id.Identity; +import org.olat.core.id.IdentityLifecycle; import org.olat.user.UserPropertiesRow; import org.olat.user.propertyhandlers.UserPropertyHandler; @@ -33,12 +34,13 @@ import org.olat.user.propertyhandlers.UserPropertyHandler; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class IdentityPropertiesRow extends UserPropertiesRow { +public class IdentityPropertiesRow extends UserPropertiesRow implements IdentityLifecycle { private final Integer status; private final Date lastLogin; private final Date creationDate; private final Date inactivationDate; + private final Date reactivationDate; public IdentityPropertiesRow(Identity identity, List<UserPropertyHandler> userPropertyHandlers, Locale locale) { super(identity, userPropertyHandlers, locale); @@ -46,30 +48,42 @@ public class IdentityPropertiesRow extends UserPropertiesRow { lastLogin = identity.getLastLogin(); creationDate = identity.getCreationDate(); inactivationDate = identity.getInactivationDate(); + reactivationDate = identity.getReactivationDate(); } public IdentityPropertiesRow(Long identityKey, Date creationDate, Date lastLogin, Integer status, - Date inactivationDate, List<UserPropertyHandler> userPropertyHandlers, String[] identityProps, Locale locale) { + Date inactivationDate, Date reactivationDate, List<UserPropertyHandler> userPropertyHandlers, + String[] identityProps, Locale locale) { super(identityKey, userPropertyHandlers, identityProps, locale); this.status = status; this.creationDate = creationDate; this.lastLogin = lastLogin; this.inactivationDate = inactivationDate; + this.reactivationDate = reactivationDate; } + @Override public Integer getStatus() { return status; } + @Override public Date getCreationDate() { return creationDate; } + @Override public Date getLastLogin() { return lastLogin; } - + + @Override public Date getInactivationDate() { return inactivationDate; } + + @Override + public Date getReactivationDate() { + return reactivationDate; + } } diff --git a/src/main/java/org/olat/core/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/core/_i18n/LocalStrings_pt_BR.properties index 2a3ac544bc9c0d7862babc4b5ab7f9df5a68528f..605ebae25e5585ec204b5ba220946b2397d41c07 100644 --- a/src/main/java/org/olat/core/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/core/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Tue May 26 15:02:54 CEST 2020 +#Thu Sep 24 14:17:41 CEST 2020 alert=Favor selecionar no m\u00EDnimo um objeto para sua a\u00E7\u00E3o. back=Voltar calendar.choose=Escolha uma data do mini calend\u00E1rio @@ -49,6 +49,7 @@ info.header=Informa\u00E7\u00E3o info.saved=Suas modifica\u00E7\u00F5es foram salvas. input.toolong=Sua entrada \u00E9 muito longa. legend=Legend +lock.same.user.different.window=Talvez voc\u00EA tenha aberto uma segunda janela? logout=Logout module.change.warning=Para ativar as suas altera\u00E7\u00F5es, o OpenOlat precisa ser reiniciado move.down=Mover para baixo @@ -59,6 +60,7 @@ new=Novo new.form.mandatory=Este campo \u00E9 obrigat\u00F3rio. next=Pr\u00F3ximo no=N\u00E3o +noTransOnlyParam={0} off=des. ok=OK on=lig. @@ -125,5 +127,6 @@ warn.header=Aviso warn.notdispatched=Esta p\u00E1gina foi modificada. Favor considerar poss\u00EDveis mensagens. warn.reload=Favor n\u00E3o usar a tecla `Atualizar` ou `Voltar` do seu browser. warning.invalid.csrf=Incompatibilidade do CSRF +warning.multi.window=Voc\u00EA abriu a mesma janela v\u00E1rias vezes. welcome=Bemvindo yes=Sim diff --git a/src/main/java/org/olat/core/commons/controllers/linkchooser/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/core/commons/controllers/linkchooser/_i18n/LocalStrings_pt_BR.properties index 2bc852c8b6e1bf9a6aa3bfdc487e44c61ae07b01..0eadf4d5aeb765992d71ec5deab04559f431ed8c 100644 --- a/src/main/java/org/olat/core/commons/controllers/linkchooser/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/core/commons/controllers/linkchooser/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Fri Dec 11 19:45:49 CET 2009 +#Thu Sep 24 14:17:49 CEST 2020 closewindow.manually=Voc\u00EA pode agora fechar esta janela error.notsupportedcharset=Este documento n\u00E3o pode ser salvo porque essa fonte n\u00E3o \u00E9 suportada\: fonte \u00E9 "{0}". Suportados s\u00E3o os seguintes\: <br><br>{1}) error.pageeditedby=Esta p\u00E1gina \u00E9 sendo editada pelo usu\u00E1rio {0}. Por favor, tente novamente mais tarde. @@ -8,5 +8,6 @@ filechooser.upload.title=Carregar arquivo linkchooser.select.title=Selecionar link linkchooser.tabbedpane.label.filechooser=Link de arquivo linkchooser.tabbedpane.label.internallinkchooser=Link do curso +linkchooser.tabbedpane.label.internaltoolchooser=Link da ferramenta do curso selectfile=Escolher upload.error.incorrect.filetype=O documento carregado tem o tipo errado de arquivo ({0}). Os tipos de arquivo permitidos s\u00E3o\: {1} diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdDownloadZip.java b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdDownloadZip.java index 6d3e747ad590bd63ccfde5c2ec21656bb99c23c0..53112a9385fe49438f40b34fe9a575fa72fee87e 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdDownloadZip.java +++ b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdDownloadZip.java @@ -47,6 +47,7 @@ import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; import org.olat.core.util.vfs.VFSLeaf; import org.olat.core.util.vfs.VFSManager; +import org.olat.core.util.vfs.filters.VFSSystemItemFilter; /** * @@ -194,7 +195,7 @@ public class CmdDownloadZip implements FolderCommand { } for (VFSItem item:vfsFiles) { - ZipUtil.addToZip(item, "", zout); + ZipUtil.addToZip(item, "", zout, new VFSSystemItemFilter(), false); } zout.flush(); } catch (IOException e) { diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdZip.java b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdZip.java index 87a48c3b13543e95a373138b3757729743bab030..f978c5319a4361118ed2e8060ae76d8236c98062 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdZip.java +++ b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdZip.java @@ -50,6 +50,7 @@ import org.olat.core.util.vfs.VFSConstants; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; import org.olat.core.util.vfs.VFSLeaf; +import org.olat.core.util.vfs.filters.VFSSystemItemFilter; import org.springframework.beans.factory.annotation.Autowired; /** @@ -170,7 +171,7 @@ public class CmdZip extends FormBasicController implements FolderCommand { vfsFiles.add(item); } } - if (!ZipUtil.zip(vfsFiles, (VFSLeaf)zipFile, true)) { + if (!ZipUtil.zip(vfsFiles, (VFSLeaf)zipFile, new VFSSystemItemFilter(), false)) { // cleanup zip file zipFile.delete(); status = FolderCommandStatus.STATUS_FAILED; diff --git a/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java b/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java index 97abe2954304ae54890554bd92b0e9e12c2990e0..3dcd03012819a2f770ae11c48cf56d2da6acc5d8 100644 --- a/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java +++ b/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java @@ -623,6 +623,8 @@ public class VFSRepositoryServiceImpl implements VFSRepositoryService, GenericEv VFSMetadata currentMetadata = metadataDao.getMetadata(metadata.getRelativePath(), newName, (item instanceof VFSContainer)); if(currentMetadata != null && !currentMetadata.equals(metadata)) { metadata.copyValues(currentMetadata, false); + deleteThumbnailsOfMetadata(currentMetadata); + deleteRevisionsOfMetadata(currentMetadata); metadataDao.removeMetadata(currentMetadata); } diff --git a/src/main/java/org/olat/core/commons/services/vfs/ui/management/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/core/commons/services/vfs/ui/management/_i18n/LocalStrings_pt_BR.properties index 86162ea9972f8fad9049118cbddc8509624d5047..30f259ebfe685c2476e84c4f2af0b44be07188a9 100644 --- a/src/main/java/org/olat/core/commons/services/vfs/ui/management/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/core/commons/services/vfs/ui/management/_i18n/LocalStrings_pt_BR.properties @@ -1,7 +1,8 @@ -#Tue May 26 15:17:59 CEST 2020 +#Thu Sep 24 14:18:03 CEST 2020 vfs.overview.action=A\u00E7\u00E3o vfs.overview.amount=Montante vfs.overview.files=Arquivos +vfs.overview.files.note=* N\u00E3o incluindo arquivos exclu\u00EDdos, vers\u00F5es ou miniaturas vfs.overview.fileslink=Mostrar arquivos grandes vfs.overview.name=Nome vfs.overview.size=Tamanho diff --git a/src/main/java/org/olat/core/gui/media/ZippedContainerMediaResource.java b/src/main/java/org/olat/core/gui/media/ZippedContainerMediaResource.java index c329fa1add0ca57fd4d914911bbb689be5e279e0..3c60ea92b7611d0220ec0e7edb62f7833261d331 100644 --- a/src/main/java/org/olat/core/gui/media/ZippedContainerMediaResource.java +++ b/src/main/java/org/olat/core/gui/media/ZippedContainerMediaResource.java @@ -30,6 +30,7 @@ import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; import org.olat.core.util.ZipUtil; import org.olat.core.util.vfs.VFSContainer; +import org.olat.core.util.vfs.filters.VFSRevisionsAndThumbnailsFilter; /** * @@ -42,10 +43,12 @@ public class ZippedContainerMediaResource implements MediaResource { private static final Logger log = Tracing.createLoggerFor(ZippedContainerMediaResource.class); private final String filename; + private final boolean withMetadata; private final VFSContainer unzipContainer; - public ZippedContainerMediaResource(String filename, VFSContainer unzipContainer) { + public ZippedContainerMediaResource(String filename, VFSContainer unzipContainer, boolean withMetadata) { this.filename = filename; + this.withMetadata = withMetadata; this.unzipContainer = unzipContainer; } @@ -91,7 +94,7 @@ public class ZippedContainerMediaResource implements MediaResource { hres.setHeader("Content-Description", urlEncodedLabel); try(OutputStream out=hres.getOutputStream()) { - ZipUtil.zip(unzipContainer, out); + ZipUtil.zip(unzipContainer, out, new VFSRevisionsAndThumbnailsFilter(), withMetadata); } catch (IOException e) { log.error("", e); } diff --git a/src/main/java/org/olat/core/id/Identity.java b/src/main/java/org/olat/core/id/Identity.java index caaff6eadfcc26827e0d64fa348f7fec98725369..e9c00e5034b0c06bd88163ab32467c7aa7e6d87f 100644 --- a/src/main/java/org/olat/core/id/Identity.java +++ b/src/main/java/org/olat/core/id/Identity.java @@ -36,7 +36,7 @@ import org.olat.basesecurity.IdentityRef; * * @author Mike Stock */ -public interface Identity extends CreateInfo, IdentityRef, Persistable { +public interface Identity extends CreateInfo, IdentityRef, IdentityLifecycle, Persistable { // status = 1..99 User with this status are visible (e.g. user search) // 100..199 User with this status are invisible (e.g. user search) @@ -71,16 +71,17 @@ public interface Identity extends CreateInfo, IdentityRef, Persistable { */ public User getUser(); - /** - * @return Last date when the user logged in. - */ - public Date getLastLogin(); /** * @return Current identity status */ + @Override public Integer getStatus(); - public Date getInactivationDate(); + /** + * @return Last date when the user logged in. + */ + @Override + public Date getLastLogin(); } \ No newline at end of file diff --git a/src/main/java/org/olat/core/id/IdentityLifecycle.java b/src/main/java/org/olat/core/id/IdentityLifecycle.java new file mode 100644 index 0000000000000000000000000000000000000000..ddcf44e3cf664959850532c692c455c8fb721ccf --- /dev/null +++ b/src/main/java/org/olat/core/id/IdentityLifecycle.java @@ -0,0 +1,49 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.core.id; + +import java.util.Date; + +/** + * + * Initial date: 21 sept. 2020<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public interface IdentityLifecycle { + + /** + * @return Current identity status + */ + public Integer getStatus(); + + public Date getCreationDate(); + + /** + * @return Last date when the user logged in. + */ + public Date getLastLogin(); + + + public Date getInactivationDate(); + + public Date getReactivationDate(); + +} diff --git a/src/main/java/org/olat/core/logging/LogRealTimeViewerController.java b/src/main/java/org/olat/core/logging/LogRealTimeViewerController.java index ca31df99c578128358ae34e17fee45d48b21d11d..bb426cca1bc6e2b95e161a305f88582e1eeae00f 100644 --- a/src/main/java/org/olat/core/logging/LogRealTimeViewerController.java +++ b/src/main/java/org/olat/core/logging/LogRealTimeViewerController.java @@ -57,6 +57,7 @@ public class LogRealTimeViewerController extends BasicController { private final Level level; private String loggingPackage; private boolean collectLog = true; + private final String appenderName; private final LogWriter writer = new LogWriter(); private Link stopLink; @@ -80,6 +81,8 @@ public class LogRealTimeViewerController extends BasicController { super(ureq, control); this.level = level; this.loggingPackage = loggingPackage; + appenderName = "LogRealTimeApppender-" + getIdentity().getKey(); + logViewerVC = createVelocityContainer("logviewer"); logViewerVC.contextPut("loggingPackage", loggingPackage); @@ -108,7 +111,7 @@ public class LogRealTimeViewerController extends BasicController { WriterAppender appender = WriterAppender.newBuilder() .setLayout(layout) .setTarget(writer) - .setName("LogRealTimeApppender") + .setName(appenderName) .build(); appender.start(); config.addAppender(appender); @@ -118,10 +121,7 @@ public class LogRealTimeViewerController extends BasicController { refList.addAll(currentRefs); refList.add(ref); - AppenderRef[] refs = refList.toArray(new AppenderRef[refList.size()]); - LoggerConfig loggerConfig = LoggerConfig.createLogger(false, level, loggingPackage, "true", refs, null, config, null); - loggerConfig.addAppender(appender, level, null); - config.addLogger(loggingPackage, loggerConfig); + currentLoggerConfig.addAppender(appender, level, null); ctx.updateLoggers(); } @@ -131,7 +131,10 @@ public class LogRealTimeViewerController extends BasicController { } private void removeConfiguration() { - Tracing.resetLevelForAllLoggers(); + final LoggerContext ctx = (LoggerContext) LogManager.getContext(false); + final Configuration config = ctx.getConfiguration(); + LoggerConfig currentLoggerConfig = config.getLoggerConfig(loggingPackage); + currentLoggerConfig.removeAppender(appenderName); } @Override diff --git a/src/main/java/org/olat/core/util/IPUtils.java b/src/main/java/org/olat/core/util/IPUtils.java index d42a273b7bef4bc0ffe9d7881f3d1ff26f1f1687..3fe3dbfc7f3497f15c01a25f3b1d1361c5efe4fc 100644 --- a/src/main/java/org/olat/core/util/IPUtils.java +++ b/src/main/java/org/olat/core/util/IPUtils.java @@ -51,13 +51,17 @@ public class IPUtils { ipWithMask = ipWithMask.trim(); int maskIndex = ipWithMask.indexOf('/'); if(maskIndex > 0) { - long bits = Long.parseLong(ipWithMask.substring(maskIndex + 1)); - long subnet = ipToLong(textToNumericFormatV4(ipWithMask.substring(0, maskIndex))); - long ip = ipToLong(textToNumericFormatV4(address)); - - long mask = -1 << (32 - bits); - if ((subnet & mask) == (ip & mask)) { - allOk = true; + try { + long bits = Long.parseLong(ipWithMask.substring(maskIndex + 1)); + long subnet = ipToLong(textToNumericFormatV4(ipWithMask.substring(0, maskIndex))); + long ip = ipToLong(textToNumericFormatV4(address)); + + long mask = -1 << (32 - bits); + if ((subnet & mask) == (ip & mask)) { + allOk = true; + } + } catch(Exception e) { + log.warn("Range not valid: {} for IP: {}", ipWithMask, address); } } return allOk; diff --git a/src/main/java/org/olat/core/util/ZipUtil.java b/src/main/java/org/olat/core/util/ZipUtil.java index c34e63cb2b97dea5ede94b2f5cc4d12ae5d01cbe..c04a98aef047a96e750a64550526d978d8056d3b 100644 --- a/src/main/java/org/olat/core/util/ZipUtil.java +++ b/src/main/java/org/olat/core/util/ZipUtil.java @@ -68,6 +68,8 @@ import org.olat.core.util.vfs.VFSLeaf; import org.olat.core.util.vfs.VFSLockApplicationType; import org.olat.core.util.vfs.VFSLockManager; import org.olat.core.util.vfs.VFSManager; +import org.olat.core.util.vfs.filters.VFSAllItemsFilter; +import org.olat.core.util.vfs.filters.VFSItemFilter; import org.olat.core.util.vfs.filters.VFSSystemItemFilter; /** @@ -543,10 +545,11 @@ public class ZipUtil { * @param files Filenames to add to ZIP, relative to root * @param root Base path. * @param target Target ZIP file. - * @param compress to compress ot just store - * @return true if successfull, false otherwise. + * @param filter Filter to accept files in the ZIP + * @param withMetadata Add metadata as shadow file + * @return true if successful, false otherwise. */ - public static boolean zip(Set<String> files, File root, File target, boolean compress) { + public static boolean zip(Set<String> files, File root, File target, VFSItemFilter filter, boolean withMetadata) { // Create a buffer for reading the files if (target.exists()) return false; List<VFSItem> vfsFiles = new ArrayList<>(); @@ -558,8 +561,8 @@ public class ZipUtil { } vfsFiles.add(item); } - return zip(vfsFiles, new LocalFileImpl(target), compress); - } // zip + return zip(vfsFiles, new LocalFileImpl(target), filter, withMetadata); + } /** * Add the set of files residing in root to the ZIP file named target. @@ -568,11 +571,11 @@ public class ZipUtil { * @param files Filenames to add to ZIP, relative to root * @param root Base path. * @param target Target ZIP file. - * @param compress to compress ot just store - * @return true if successfull, false otherwise. + * @param withMetadata Add metadata as shadow file + * @return true if successful, false otherwise. */ - public static boolean zip(Set<String> files, File root, File target) { - return zip(files, root, target, true); + public static boolean zip(Set<String> files, File root, File target, boolean withMetadata) { + return zip(files, root, target, VFSAllItemsFilter.ACCEPT_ALL, withMetadata); } /** @@ -583,9 +586,9 @@ public class ZipUtil { * @param outputFile The output ZIP file * @return true if successful */ - public static boolean zip(VFSContainer container, File outputFile) { + public static boolean zip(VFSContainer container, File outputFile, VFSItemFilter filter, boolean withMetadata) { try(OutputStream out = new FileOutputStream(outputFile)) { - zip(container, out); + zip(container, out, filter, withMetadata); return true; } catch(IOException e) { handleIOException("", e); @@ -601,11 +604,11 @@ public class ZipUtil { * @param out The output stream * @return true if successful */ - public static boolean zip(VFSContainer container, OutputStream out) { + public static boolean zip(VFSContainer container, OutputStream out, VFSItemFilter filter, boolean withMetadata) { try(ZipOutputStream zipOut = new ZipOutputStream(new BufferedOutputStream(out, FileUtils.BSIZE))) { List<VFSItem> items=container.getItems(new VFSSystemItemFilter()); for(VFSItem item:items) { - addToZip(item, "", zipOut); + addToZip(item, "", zipOut, filter, withMetadata); } return true; } catch(IOException e) { @@ -614,7 +617,7 @@ public class ZipUtil { } } - public static boolean zip(List<VFSItem> vfsFiles, VFSLeaf target, boolean compress) { + public static boolean zip(List<VFSItem> vfsFiles, VFSLeaf target, VFSItemFilter filter, boolean withMetadata) { boolean success = true; String zname = target.getName(); @@ -624,9 +627,9 @@ public class ZipUtil { try(OutputStream out = target.getOutputStream(false); ZipOutputStream zipOut = new ZipOutputStream(new BufferedOutputStream(out, FileUtils.BSIZE))) { - zipOut.setLevel(compress?9:0); + zipOut.setLevel(9); for (VFSItem item:vfsFiles) { - success = addToZip(item, "", zipOut); + success = addToZip(item, "", zipOut, filter, withMetadata); } zipOut.flush(); } catch (IOException e) { @@ -636,39 +639,43 @@ public class ZipUtil { return success; } - public static boolean addToZip(VFSItem vfsItem, String currentPath, ZipOutputStream out) { + public static boolean addToZip(VFSItem vfsItem, String currentPath, ZipOutputStream out, VFSItemFilter filter, boolean withMetadata) { boolean success = true; try { + if(filter == null) { + filter = VFSAllItemsFilter.ACCEPT_ALL; + } + // The separator / is the separator defined by the ZIP standard String itemName = currentPath.length() == 0 ? vfsItem.getName() : currentPath + "/" + vfsItem.getName(); + if(filter.accept(vfsItem)) { + if (vfsItem instanceof VFSContainer ) { + out.putNextEntry(new ZipEntry(itemName + "/")); + out.closeEntry(); - if (vfsItem instanceof VFSContainer) { - out.putNextEntry(new ZipEntry(itemName + "/")); - out.closeEntry(); - - List<VFSItem> items = ((VFSContainer)vfsItem).getItems(); - for (VFSItem item:items) { - if (!addToZip(item, itemName, out)) { - success = false; - break; + List<VFSItem> items = ((VFSContainer)vfsItem).getItems(); + for (VFSItem item:items) { + if (!addToZip(item, itemName, out, filter, withMetadata)) { + success = false; + break; + } } - } - - } else { - VFSLeaf leaf = (VFSLeaf)vfsItem; - ZipEntry entry = new ZipEntry(itemName); - out.putNextEntry(entry); - copyShielded(leaf, out); - out.closeEntry(); - - if(leaf.canMeta() == VFSConstants.YES) { - byte[] metadata = MetaInfoReader.toBinaries(leaf.getMetaInfo()); - if(metadata != null && metadata.length > 0) { - ZipEntry metaEntry = new ZipEntry("._oo_meta_".concat(itemName)); - out.putNextEntry(metaEntry); - out.write(metadata); - out.closeEntry(); + } else { + VFSLeaf leaf = (VFSLeaf)vfsItem; + ZipEntry entry = new ZipEntry(itemName); + out.putNextEntry(entry); + copyShielded(leaf, out); + out.closeEntry(); + + if(withMetadata && leaf.canMeta() == VFSConstants.YES) { + byte[] metadata = MetaInfoReader.toBinaries(leaf.getMetaInfo()); + if(metadata != null && metadata.length > 0) { + ZipEntry metaEntry = new ZipEntry(currentPath + "/._oo_meta_".concat(vfsItem.getName())); + out.putNextEntry(metaEntry); + out.write(metadata); + out.closeEntry(); + } } } } @@ -689,16 +696,16 @@ public class ZipUtil { * * @param rootFile * @param targetZipFile - * @param compress to compress or just store (if already compressed) + * @param withMetadata A metadata as shadow file * @return true = success, false = exception/error */ - public static boolean zipAll(File rootFile, File targetZipFile, boolean compress) { + public static boolean zipAll(File rootFile, File targetZipFile, boolean withMetadata) { Set<String> fileSet = new HashSet<>(); String[] files = rootFile.list(); for (int i = 0; i < files.length; i++) { fileSet.add(files[i]); } - return zip(fileSet, rootFile, targetZipFile, compress); + return zip(fileSet, rootFile, targetZipFile, VFSAllItemsFilter.ACCEPT_ALL, withMetadata); } /** @@ -832,17 +839,6 @@ public class ZipUtil { } } - /** - * Zip all files under a certain root directory. (with compression) - * - * @param rootFile - * @param targetZipFile - * @return true = success, false = exception/error - */ - public static boolean zipAll(File rootFile, File targetZipFile) { - return zipAll(rootFile, targetZipFile, true); - } - /** * Unzip files from stream into target dir and do NOTHING ELSE!!! * See OLAT-6213 diff --git a/src/main/java/org/olat/core/util/mail/ui/EMailIdentity.java b/src/main/java/org/olat/core/util/mail/ui/EMailIdentity.java index 69af87462bcedb96ecbc107ac2957d1ca4beb16c..e9be3a72b8e5a0b1676b8e8cb6d9c6d35e726b97 100644 --- a/src/main/java/org/olat/core/util/mail/ui/EMailIdentity.java +++ b/src/main/java/org/olat/core/util/mail/ui/EMailIdentity.java @@ -88,6 +88,11 @@ public class EMailIdentity implements Identity { public Date getInactivationDate() { return null; } + + @Override + public Date getReactivationDate() { + return null; + } private class EMailUser implements User, ModifiedInfo { diff --git a/src/main/java/org/olat/core/util/vfs/filters/VFSAllItemsFilter.java b/src/main/java/org/olat/core/util/vfs/filters/VFSAllItemsFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..8a24adb105459c6047172155a53be3fcfb8009f4 --- /dev/null +++ b/src/main/java/org/olat/core/util/vfs/filters/VFSAllItemsFilter.java @@ -0,0 +1,23 @@ +package org.olat.core.util.vfs.filters; + +import org.olat.core.util.vfs.VFSItem; + +/** + * + * Initial date: 24 sept. 2020<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class VFSAllItemsFilter implements VFSItemFilter { + + public static final VFSItemFilter ACCEPT_ALL = new VFSAllItemsFilter(); + + private VFSAllItemsFilter() { + // + } + + @Override + public boolean accept(VFSItem vfsItem) { + return true; + } +} diff --git a/src/main/java/org/olat/core/util/vfs/filters/VFSRevisionsAndThumbnailsFilter.java b/src/main/java/org/olat/core/util/vfs/filters/VFSRevisionsAndThumbnailsFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..b81534ba2a5393e9b9a5c4e5a3276e267c088c0a --- /dev/null +++ b/src/main/java/org/olat/core/util/vfs/filters/VFSRevisionsAndThumbnailsFilter.java @@ -0,0 +1,19 @@ +package org.olat.core.util.vfs.filters; + +import org.olat.core.util.vfs.VFSItem; + +/** + * Accept all files but thumbnails and revisions. + * + * Initial date: 24 sept. 2020<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class VFSRevisionsAndThumbnailsFilter implements VFSItemFilter { + + @Override + public boolean accept(VFSItem vfsItem) { + String name = vfsItem.getName(); + return !name.startsWith("._oo_th_") && !name.startsWith("._oo_vr_"); + } +} diff --git a/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeEditController.java b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeEditController.java index b8a710260d5b7c258dad33782979e26b0d18ce89..de59c36f8a2d15da37a0c9215b3027263b5c1481 100644 --- a/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeEditController.java +++ b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeEditController.java @@ -27,6 +27,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; +import java.util.StringTokenizer; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; @@ -592,8 +593,31 @@ public class AssessmentModeEditController extends FormBasicController { if(ipsMultiselect.getSelectedKeys().size() < 1) { ipsMultiselect.setErrorKey("form.legende.mandatory", null); allOk &= false; + } else { + allOk &= validIpList(ipListEl.getValue()); + } + } + return allOk; + } + + /** + * Try to begin some validation of the list but the list allowed + * a lot of possibilities. + * + * @param ipList The list of IPs + * @return true if valid + */ + private boolean validIpList(String ipList) { + boolean allOk = true; + + for(StringTokenizer tokenizer = new StringTokenizer(ipList, "\n\r", false); tokenizer.hasMoreTokens(); ) { + String ipRange = tokenizer.nextToken(); + if(StringHelper.containsNonWhitespace(ipRange) && ipRange.startsWith("/")) { + ipListEl.setErrorKey("error.ip.range.cannot.start.slash", new String[] { ipRange } ); + allOk &= false; } } + return allOk; } diff --git a/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_de.properties index 1bdfda03b1d0c88a9787cab03a388998f9750be0..7393dc4bb22258681d7889d1980167bec814b940 100644 --- a/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_de.properties @@ -58,6 +58,7 @@ error.atleastone=Bitte w\u00E4hlen Sie mindestens ein Pr\u00FCfungskonfiguration error.course.element.mandatory=Bitte w\u00E4hlen Sie die entsprechenden Kursbausteine. error.in.assessment=Sie d\u00FCrfen kein Pr\u00FCfungen l\u00F6schen die gerade gestartet sind. error.ip.range=Sie sind nicht im richtigen Netzwerk. +error.ip.range.cannot.start.slash=Eine Adresse IP darf nicht mit einem Slash (/) anfangen: {0} error.ip.range.desc=Diese Pr\u00FCfung kann nur in den daf\u00FCr vorgesehenen Netzwerken durchgef\u00FChrt werden, bitte kontaktieren Sie Ihren Pr\u00FCfungsverantwortlichen. Ihre IP-Adresse lautet: {0} error.safe.exam=Bitte benutzen Sie den Safe Exam Browser. error.safe.exam.desc=Sie verwenden entweder nicht den <a href\="http://safeexambrowser.org" target\="_blank">Safe Exam Browser</a> oder eine falsche Safe Exam Browser Konfigurationsdatei. Bitte verwenden Sie ausschliesslich die von Ihrem Pr\u00FCfungsverantwortlichen bereitgestellte Safe Exam Browser Konfigurationsdatei f\u00FCr Ihr Betriebssystem. diff --git a/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_en.properties index 556b01e8f0488ff3ac690d9a1bd628dfd8af9415..dc0d7233583dc0b2a87fec6a26f048fc1e8d0ad9 100644 --- a/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_en.properties @@ -61,6 +61,7 @@ error.curriculum.missing=You must choose at least one curriculum element. error.group.missing=You must choose at least one group. error.in.assessment=You cannot delete an assessment which is running. error.ip.range=You are not in the right network. +error.ip.range.cannot.start.slash=An IP cannot start with a slash: {0} error.ip.range.desc=The exam can only be taken in the registered networks, please contact your exam manager. Your IP address is\: {0} error.safe.exam=Please, use the Safe Exam Browser. error.safe.exam.desc=You are either not using the <a href\="http\://safeexambrowser.org" target\="_blank">Safe Exam Browser</a> or a wrong Safe Exam Browser configuration file. Please use the configuration file specific to your operating system that was made available by your exam manager. diff --git a/src/main/java/org/olat/course/export/CourseExportMediaResource.java b/src/main/java/org/olat/course/export/CourseExportMediaResource.java index 134aa58d03f7977444961201c5c3f0e212730a51..a3a29f91505fdecd537c014efd35130b12f5f6d5 100644 --- a/src/main/java/org/olat/course/export/CourseExportMediaResource.java +++ b/src/main/java/org/olat/course/export/CourseExportMediaResource.java @@ -48,6 +48,7 @@ import org.olat.core.util.tree.TreeVisitor; import org.olat.core.util.vfs.LocalFolderImpl; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSManager; +import org.olat.core.util.vfs.filters.VFSRevisionsAndThumbnailsFilter; import org.olat.course.CourseFactory; import org.olat.course.ICourse; import org.olat.course.PersistingCourseImpl; @@ -391,7 +392,7 @@ public class CourseExportMediaResource implements MediaResource, StreamingOutput String nodeDirectory = ZipUtil.concat(ICourse.EXPORTED_DATA_FOLDERNAME, courseNode.getIdent()); zout.putNextEntry(new ZipEntry(ZipUtil.concat(nodeDirectory, "oonode.zip"))); - ZipUtil.zip(nodeContainer, fOut); + ZipUtil.zip(nodeContainer, fOut, new VFSRevisionsAndThumbnailsFilter(), true); zout.closeEntry(); } catch (IOException e) { diff --git a/src/main/java/org/olat/course/nodes/BCCourseNode.java b/src/main/java/org/olat/course/nodes/BCCourseNode.java index 2cf38dcdc345bd41fffb64f8baeba965fb7b649e..644b83efdf8c41d2939067b9e81f3b81bddcdc7c 100644 --- a/src/main/java/org/olat/course/nodes/BCCourseNode.java +++ b/src/main/java/org/olat/course/nodes/BCCourseNode.java @@ -51,6 +51,7 @@ import org.olat.core.util.vfs.NamedContainerImpl; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; import org.olat.core.util.vfs.VFSManager; +import org.olat.core.util.vfs.filters.VFSRevisionsAndThumbnailsFilter; import org.olat.core.util.vfs.filters.VFSSystemItemFilter; import org.olat.course.CourseModule; import org.olat.course.ICourse; @@ -202,7 +203,7 @@ public class BCCourseNode extends AbstractAccessableCourseNode { File fNodeExportDir = new File(exportDirectory, getIdent()); fNodeExportDir.mkdirs(); File outputFile = new File(fNodeExportDir, "oonode.zip"); - ZipUtil.zip(nodeContainer, outputFile); + ZipUtil.zip(nodeContainer, outputFile, new VFSRevisionsAndThumbnailsFilter(), true); } @Override diff --git a/src/main/java/org/olat/course/nodes/CheckListCourseNode.java b/src/main/java/org/olat/course/nodes/CheckListCourseNode.java index 1a7ddfac05478d99108bf14dc0806541d2145f3a..6c6a6ca33bd5b9cb07f10574002a3c9d72314589 100644 --- a/src/main/java/org/olat/course/nodes/CheckListCourseNode.java +++ b/src/main/java/org/olat/course/nodes/CheckListCourseNode.java @@ -54,6 +54,7 @@ import org.olat.core.util.resource.OresHelper; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; import org.olat.core.util.vfs.VFSLeaf; +import org.olat.core.util.vfs.filters.VFSSystemItemFilter; import org.olat.course.ICourse; import org.olat.course.assessment.AssessmentManager; import org.olat.course.assessment.CourseAssessmentService; @@ -302,7 +303,7 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode { } else { usedNames.add(checkbox.getTitle()); } - ZipUtil.addToZip(item, path, exportStream); + ZipUtil.addToZip(item, path, exportStream, new VFSSystemItemFilter(), false); } } } diff --git a/src/main/java/org/olat/course/nodes/DialogCourseNode.java b/src/main/java/org/olat/course/nodes/DialogCourseNode.java index e427085f1ad7609747e271f98bc34db1ff261094..5d81b57d53500f62d113f08fc6b617d083bde81e 100644 --- a/src/main/java/org/olat/course/nodes/DialogCourseNode.java +++ b/src/main/java/org/olat/course/nodes/DialogCourseNode.java @@ -51,6 +51,7 @@ import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; import org.olat.core.util.vfs.callbacks.FullAccessCallback; import org.olat.core.util.vfs.filters.VFSLeafFilter; +import org.olat.core.util.vfs.filters.VFSSystemItemFilter; import org.olat.course.CourseModule; import org.olat.course.ICourse; import org.olat.course.condition.Condition; @@ -307,7 +308,7 @@ public class DialogCourseNode extends AbstractAccessableCourseNode { VFSContainer forumContainer = depm.getDialogContainer(element); for(VFSItem item: forumContainer.getItems(new VFSLeafFilter())) { - ZipUtil.addToZip(item, exportDirName, exportStream); + ZipUtil.addToZip(item, exportDirName, exportStream, new VFSSystemItemFilter(), false); } try { diff --git a/src/main/java/org/olat/course/nodes/GTACourseNode.java b/src/main/java/org/olat/course/nodes/GTACourseNode.java index dd2ed3532eb5732d522fe7e115b0473e7b11ddcd..ba1fa7cd762e0a97f3215d61940b0766b5a9f6f0 100644 --- a/src/main/java/org/olat/course/nodes/GTACourseNode.java +++ b/src/main/java/org/olat/course/nodes/GTACourseNode.java @@ -620,7 +620,7 @@ public class GTACourseNode extends AbstractAccessableCourseNode { if (solutions.exists()) { String solutionDirName = dirName + "/solutions"; for(VFSItem solution:solutions.getItems(new VFSSystemItemFilter())) { - ZipUtil.addToZip(solution, solutionDirName, exportStream); + ZipUtil.addToZip(solution, solutionDirName, exportStream, new VFSSystemItemFilter(), false); } } } diff --git a/src/main/java/org/olat/course/nodes/ProjectBrokerCourseNode.java b/src/main/java/org/olat/course/nodes/ProjectBrokerCourseNode.java index 8a9dbcad3813663e9bb3d845039eb23cc8eda022..5609e7cbc4a625d6f9dc70f14104c35aeae0008a 100644 --- a/src/main/java/org/olat/course/nodes/ProjectBrokerCourseNode.java +++ b/src/main/java/org/olat/course/nodes/ProjectBrokerCourseNode.java @@ -635,7 +635,7 @@ public class ProjectBrokerCourseNode extends AbstractAccessableCourseNode { if (!VFSManager.isDirectoryAndNotEmpty(userFolder)) continue; String path = exportDirName + "/dropboxes/" + themaItem.getName(); - ZipUtil.addToZip(userFolder, path, exportStream); + ZipUtil.addToZip(userFolder, path, exportStream, new VFSSystemItemFilter(), false); } } } @@ -650,7 +650,7 @@ public class ProjectBrokerCourseNode extends AbstractAccessableCourseNode { if (!VFSManager.isDirectoryAndNotEmpty(userFolder)) continue; String path = exportDirName + "/returnboxes/" + themaItem.getName(); - ZipUtil.addToZip(userFolder, path, exportStream); + ZipUtil.addToZip(userFolder, path, exportStream, new VFSSystemItemFilter(), false); } } } diff --git a/src/main/java/org/olat/course/nodes/TACourseNode.java b/src/main/java/org/olat/course/nodes/TACourseNode.java index 2e6f0a9944f687652b08aa86573fafa43488b113..e46877bde855ab16af49cbe1b6f54d5aa1517a29 100644 --- a/src/main/java/org/olat/course/nodes/TACourseNode.java +++ b/src/main/java/org/olat/course/nodes/TACourseNode.java @@ -516,7 +516,7 @@ public class TACourseNode extends GenericCourseNode { if (solutionDir.exists()) { for(VFSItem child:solutionDir.getItems(new VFSSystemItemFilter())) { dataFound = true; - ZipUtil.addToZip(child, dirName + "/solutions", exportStream); + ZipUtil.addToZip(child, dirName + "/solutions", exportStream, new VFSSystemItemFilter(), false); } } @@ -527,7 +527,7 @@ public class TACourseNode extends GenericCourseNode { for (VFSItem file:dropBoxContent) { if((dropboxNames == null || dropboxNames.contains(file.getName())) && VFSManager.isDirectoryAndNotEmpty(file)){ dataFound = true; - ZipUtil.addToZip(file, dirName + "/dropboxes", exportStream); + ZipUtil.addToZip(file, dirName + "/dropboxes", exportStream, new VFSSystemItemFilter(), false); } } } @@ -542,7 +542,7 @@ public class TACourseNode extends GenericCourseNode { VFSItem item = taskfolderDir.resolve(assignedTask); if(item != null) { // copy choosen task to user folder - ZipUtil.addToZip(item, dirName + "/taskfolders/" + identity.getName(), exportStream); + ZipUtil.addToZip(item, dirName + "/taskfolders/" + identity.getName(), exportStream, new VFSSystemItemFilter(), false); dataFound = true; } } @@ -555,7 +555,7 @@ public class TACourseNode extends GenericCourseNode { for (VFSItem file : returnBoxContent) { if((dropboxNames == null || dropboxNames.contains(file.getName())) && VFSManager.isDirectoryAndNotEmpty(file)){ dataFound = true; - ZipUtil.addToZip(file, dirName + "/returnboxes", exportStream); + ZipUtil.addToZip(file, dirName + "/returnboxes", exportStream, new VFSSystemItemFilter(), false); } } } diff --git a/src/main/java/org/olat/course/nodes/gta/GTAManager.java b/src/main/java/org/olat/course/nodes/gta/GTAManager.java index 1544d6661f747cd64204809c525023bfb749a814..c1d552dbd8b220657ed88bcf8ecc958ee6e8ce67 100644 --- a/src/main/java/org/olat/course/nodes/gta/GTAManager.java +++ b/src/main/java/org/olat/course/nodes/gta/GTAManager.java @@ -232,7 +232,7 @@ public interface GTAManager { * @param by The role of the doer * @return true if the status is done */ - public boolean syncAssessmentEntry(Task task, GTACourseNode cNode, UserCourseEnvironment assessedUserCourseEnv, Identity doerIdentity, Role by); + public boolean syncAssessmentEntry(Task task, GTACourseNode cNode, UserCourseEnvironment assessedUserCourseEnv, boolean incrementUserAttempts, Identity doerIdentity, Role by); /** * Are users already processing this task? diff --git a/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java b/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java index 61e473327487f20a6f0977cdbac1212d84355dff..926115ed67296f45777ab9eb1fec24dd41b7c379 100644 --- a/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java +++ b/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java @@ -1025,7 +1025,7 @@ public class GTAManagerImpl implements GTAManager { task = dbInstance.getCurrentEntityManager().merge(task); } dbInstance.commit(); - syncAssessmentEntry(task, cNode, null, doerIdentity, Role.user); + syncAssessmentEntry(task, cNode, null, false, doerIdentity, Role.user); response = new AssignmentResponse(task, Status.ok); } } else { @@ -1033,7 +1033,7 @@ public class GTAManagerImpl implements GTAManager { ((TaskImpl)currentTask).setTaskStatus(TaskProcess.submit); } currentTask = dbInstance.getCurrentEntityManager().merge(currentTask); - syncAssessmentEntry(currentTask, cNode, null, doerIdentity, Role.user); + syncAssessmentEntry(currentTask, cNode, null, false, doerIdentity, Role.user); response = new AssignmentResponse(currentTask, Status.ok); } @@ -1156,7 +1156,7 @@ public class GTAManagerImpl implements GTAManager { TaskImpl task = createTask(taskName, reloadedTasks, nextStep, businessGroup, identity, cNode); task.setAssignmentDate(new Date()); dbInstance.getCurrentEntityManager().persist(task); - syncAssessmentEntry(task, cNode, null, doerIdentity, Role.user); + syncAssessmentEntry(task, cNode, null, false, doerIdentity, Role.user); response = new AssignmentResponse(task, Status.ok); } dbInstance.commit(); @@ -1169,7 +1169,7 @@ public class GTAManagerImpl implements GTAManager { } } currentTask = dbInstance.getCurrentEntityManager().merge(currentTask); - syncAssessmentEntry(currentTask, cNode, null, doerIdentity, Role.user); + syncAssessmentEntry(currentTask, cNode, null, false, doerIdentity, Role.user); response = new AssignmentResponse(currentTask, Status.ok); } return response; @@ -1421,7 +1421,7 @@ public class GTAManagerImpl implements GTAManager { taskImpl.setTaskStatus(nextStep); TaskImpl mergedTask = dbInstance.getCurrentEntityManager().merge(taskImpl); dbInstance.commit();//make the thing definitive - syncAssessmentEntry(mergedTask, cNode, null, doerIdentity, by); + syncAssessmentEntry(mergedTask, cNode, null, incrementUserAttempts, doerIdentity, by); return mergedTask; } @@ -1650,7 +1650,7 @@ public class GTAManagerImpl implements GTAManager { taskImpl.setTaskStatus(newStatus); syncDates(taskImpl, newStatus); taskImpl = dbInstance.getCurrentEntityManager().merge(taskImpl); - syncAssessmentEntry(taskImpl, cNode, null, doerIdentity, by); + syncAssessmentEntry(taskImpl, cNode, null, incrementUserAttempts, doerIdentity, by); // mark the publishers OLATResource resource = taskImpl.getTaskList().getEntry().getOlatResource(); @@ -1701,7 +1701,7 @@ public class GTAManagerImpl implements GTAManager { taskImpl = dbInstance.getCurrentEntityManager().merge(taskImpl); //log date createAndPersistTaskRevisionDate(taskImpl, iteration, newStatus); - syncAssessmentEntry(taskImpl, cNode, null, doerIdentity, by); + syncAssessmentEntry(taskImpl, cNode, null, incrementUserAttempts, doerIdentity, by); return taskImpl; } @@ -1769,7 +1769,7 @@ public class GTAManagerImpl implements GTAManager { @Override public boolean syncAssessmentEntry(Task taskImpl, GTACourseNode cNode, - UserCourseEnvironment assessedUserCourseEnv, Identity doerIdentity, Role by) { + UserCourseEnvironment assessedUserCourseEnv, boolean incrementUserAttempts, Identity doerIdentity, Role by) { if(taskImpl == null || taskImpl.getTaskStatus() == null || cNode == null) return false; TaskList taskList = getTaskList(taskImpl); @@ -1788,7 +1788,7 @@ public class GTAManagerImpl implements GTAManager { } AssessmentEvaluation scoreEvaluation = courseAssessmentService.getAssessmentEvaluation(cNode, userCourseEnv); AssessmentEvaluation newScoreEvaluation = new AssessmentEvaluation(scoreEvaluation, assessmentStatus); - courseAssessmentService.saveScoreEvaluation(cNode, doerIdentity, newScoreEvaluation, userCourseEnv, false, by); + courseAssessmentService.saveScoreEvaluation(cNode, doerIdentity, newScoreEvaluation, userCourseEnv, incrementUserAttempts, by); if(doerIdentity != null && doerIdentity.equals(assessedIdentity)) { currentAssessmentStatus = scoreEvaluation.getAssessmentStatus(); } @@ -1805,7 +1805,7 @@ public class GTAManagerImpl implements GTAManager { AssessmentEvaluation scoreEvaluation = courseAssessmentService.getAssessmentEvaluation(cNode, userCourseEnv); currentAssessmentStatus = scoreEvaluation.getAssessmentStatus(); AssessmentEvaluation newScoreEvaluation = new AssessmentEvaluation(scoreEvaluation, assessmentStatus); - courseAssessmentService.saveScoreEvaluation(cNode, doerIdentity, newScoreEvaluation, userCourseEnv, false, by); + courseAssessmentService.saveScoreEvaluation(cNode, doerIdentity, newScoreEvaluation, userCourseEnv, incrementUserAttempts, by); } return currentAssessmentStatus != assessmentStatus; } diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantController.java index 113a79aac89cfdc3e5a293dbd9144caa8c1bb879..43ae2950c992395ff04884989492e69757b64bd1 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantController.java @@ -619,7 +619,7 @@ public class GTAParticipantController extends GTAAbstractController implements A if(gtaManager.firstStep(gtaNode) == TaskProcess.solution) { assignedTask = gtaManager.ensureTaskExists(assignedTask, assessedGroup, assessedIdentity, courseEntry, gtaNode); - gtaManager.syncAssessmentEntry(assignedTask, gtaNode, userCourseEnv, getIdentity(), Role.user); + gtaManager.syncAssessmentEntry(assignedTask, gtaNode, userCourseEnv, false, getIdentity(), Role.user); } } else { VelocityContainer waitVC = createVelocityContainer("no_solutions_foryou"); diff --git a/src/main/java/org/olat/course/nodes/st/STCourseNodeRunController.java b/src/main/java/org/olat/course/nodes/st/STCourseNodeRunController.java index 5f8d1cb374c5b7d9622a6d3c8408b0ee0118c833..2a453b5e5f47a52196907bbc0903bd0343c46b28 100644 --- a/src/main/java/org/olat/course/nodes/st/STCourseNodeRunController.java +++ b/src/main/java/org/olat/course/nodes/st/STCourseNodeRunController.java @@ -129,7 +129,7 @@ public class STCourseNodeRunController extends BasicController { .withFilter(AccessibleFilter.create()) .build() .getNodeById(stCourseNode.getIdent()); - int chdCnt = courseTreeNode.getChildCount(); + int chdCnt = courseTreeNode == null ? 0 : courseTreeNode.getChildCount(); for (int i = 0; i < chdCnt; i++) { INode childNode = courseTreeNode.getChildAt(i); if (childNode instanceof CourseTreeNode) { @@ -141,7 +141,7 @@ public class STCourseNodeRunController extends BasicController { Controller childPeekViewController = null; boolean accessible = childCourseTreeNode.isAccessible(); if (displayType.equals(STCourseNodeEditController.CONFIG_VALUE_DISPLAY_PEEKVIEW)) { - if (peekviewChildNodes.size() == 0) { + if (peekviewChildNodes.isEmpty()) { // Special case: no child nodes configured. This is the case when // the node has been configured before it had any children. We just // use the first children as they appear in the list diff --git a/src/main/java/org/olat/course/run/preview/PreviewIdentity.java b/src/main/java/org/olat/course/run/preview/PreviewIdentity.java index 7eaa1570696c97060ae9beccf7f97f9526f08103..47b6c2ae51a66ab4a8e25793575ad7b8e7a22e21 100644 --- a/src/main/java/org/olat/course/run/preview/PreviewIdentity.java +++ b/src/main/java/org/olat/course/run/preview/PreviewIdentity.java @@ -164,6 +164,11 @@ public final class PreviewIdentity implements Identity, User { return null; } + @Override + public Date getReactivationDate() { + return null; + } + @Override public boolean equalsByPersistableKey(Persistable persistable) { return equals(persistable); diff --git a/src/main/java/org/olat/course/statistic/ExportManager.java b/src/main/java/org/olat/course/statistic/ExportManager.java index a67dd704a8a9847119189e2851901ece10309d98..63a36cbc8260bb09eb40a7911ebfb49c9e0c9527 100644 --- a/src/main/java/org/olat/course/statistic/ExportManager.java +++ b/src/main/java/org/olat/course/statistic/ExportManager.java @@ -152,16 +152,18 @@ public class ExportManager { File outFile = new File(dir, filename); // trigger the course log exporter - it will store the file to outFile - log.info("createLogFile: start exporting course log file "+outFile.getAbsolutePath()); + log.info("createLogFile: start exporting course log file {}", outFile); courseLogExporter.exportCourseLog(outFile, oresID, begin, end, resourceAdminAction, anonymize, isAdministrativeUser); - log.info("createLogFile: finished exporting course log file "+outFile.getAbsolutePath()); + log.info("createLogFile: finished exporting course log file {}", outFile); return outFile; } private void saveFile(String targetDir, String zipName, File tmpDir, List<File> files, String email, String emailI18nSubkey, Locale locale) { File zipFile = new File(targetDir, zipName); - Set<String> filenames = files.stream().map(File::getName).collect(Collectors.toSet()); - if (ZipUtil.zip(filenames, tmpDir, zipFile)) { + Set<String> filenames = files.stream() + .map(File::getName) + .collect(Collectors.toSet()); + if (ZipUtil.zip(filenames, tmpDir, zipFile, false)) { sendEMail(email, locale, emailI18nSubkey); } FileUtils.deleteDirsAndFiles(tmpDir, true, true); diff --git a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_pt_BR.properties index b1969e9ce7ea433ef2fc6b64858eb0d9f968ed30..4355a2e950576815ee3588315a4bc3a0a02ac02f 100644 --- a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Tue May 26 15:24:24 CEST 2020 +#Thu Sep 24 14:18:24 CEST 2020 accept=Confirmar action=A\u00E7\u00E3o add.member=Adicionar membro @@ -74,6 +74,7 @@ msg.alleastone.editable.group=Voc\u00EA deve selecionar pelo menos um grupo que msg.alleasttwo.editable.group=Voc\u00EA deve selecionar pelo menos um grupo em que tenha a fun\u00E7\u00E3o de treinador. msg.atleastone=Deve haver no m\u00EDnimo um propriet\u00E1rio neste grupo de projeto. msg.only.editable.group=Voc\u00EA deve selecionar grupos onde voc\u00EA tem a fun\u00E7\u00E3o de treinador. +msg.send.ok=Sua mensagem foi enviada com sucesso. my.groups=Meus grupos my.groups.alt=Trabalhar com seus grupos nomembers=Nenhum membro encontrado que se enquadra nos crit\u00E9rios estabelecidos. @@ -162,6 +163,7 @@ table.header.graduate=Admitir table.header.group.full=Completo table.header.groups=Grupo table.header.identifier=Identificador +table.header.identity.status=Status table.header.key=ID table.header.lastName=\u00DAltimo nome table.header.lastTime=\u00DAltima visita diff --git a/src/main/java/org/olat/group/ui/run/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/group/ui/run/_i18n/LocalStrings_pt_BR.properties index 5b79e5e5844a3734f8b2a20777912ee737514206..eddc474bd355406673e2c68e10cf05007a0a9f2c 100644 --- a/src/main/java/org/olat/group/ui/run/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/group/ui/run/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Wed May 27 00:02:54 CEST 2020 +#Thu Sep 24 20:15:48 CEST 2020 businessgroup.contact.bodytext=<p></p>---<p>Ir imediatamente para o grupo "{0}"\: {1}</p> businessgroup.contact.subject=Mensagem para grupo {0} contact.all.coaches=Todos os treinadores (coaches) de grupo diff --git a/src/main/java/org/olat/gui/control/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/gui/control/_i18n/LocalStrings_pt_BR.properties index fe270411ba05ad884b51c988a0d3aae771b3ed25..990de91d1beacaeeb9001356816af858249d6d65 100644 --- a/src/main/java/org/olat/gui/control/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/gui/control/_i18n/LocalStrings_pt_BR.properties @@ -1,6 +1,6 @@ -#Wed Nov 04 23:14:08 CET 2015 - +#Thu Sep 24 14:18:39 CEST 2020 command.closeprinting=Fechar visualiza\u00E7\u00E3o de impress\u00E3o +contact.to=Suporte footer.ajax.hover=Modo AJAX est\u00E1 ativo, o que significa respostas r\u00E1pidas no OLAT. footer.login=Entrar logged.in.invitee=(convidado) @@ -19,6 +19,7 @@ topnav.login.alt=Entrar no servidor OLAT topnav.logout=Sair do OLAT topnav.logout.alt=Sair do servidor OLAT topnav.my.menu.configurations=Configura\u00E7\u00E3o +topnav.my.menu.help=Ajuda topnav.my.menu.label={0} topnav.my.menu.systems=Sistema topnav.my.menu.tools=Ferramentas pessoais diff --git a/src/main/java/org/olat/ims/qti/editor/QTIEditorPackageImpl.java b/src/main/java/org/olat/ims/qti/editor/QTIEditorPackageImpl.java index 771c827b7c95c76cd50a8984568e013ff6921a73..1898f50112477b5f08c66aa71057fc2874ffe9a8 100644 --- a/src/main/java/org/olat/ims/qti/editor/QTIEditorPackageImpl.java +++ b/src/main/java/org/olat/ims/qti/editor/QTIEditorPackageImpl.java @@ -58,6 +58,7 @@ import org.olat.core.util.vfs.NamedContainerImpl; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; import org.olat.core.util.vfs.callbacks.VFSSecurityCallback; +import org.olat.core.util.vfs.filters.VFSAllItemsFilter; import org.olat.core.util.xml.XMLParser; import org.olat.core.util.xml.XStreamHelper; import org.olat.fileresource.FileResourceManager; @@ -303,7 +304,7 @@ public class QTIEditorPackageImpl implements QTIEditorPackage { files.add(ImsRepositoryResolver.QTI_FILE); files.add("media"); files.add("changelog"); - return ZipUtil.zip(files, packageDir, fOut, false); + return ZipUtil.zip(files, packageDir, fOut, VFSAllItemsFilter.ACCEPT_ALL, false); } /** diff --git a/src/main/java/org/olat/ims/qti/qpool/QTIExportProcessor.java b/src/main/java/org/olat/ims/qti/qpool/QTIExportProcessor.java index 9400329e66e4682e6f4d15ff4459248ac79b2832..40ea29e5d038ac09a1a206065ef0d13573b8a472 100644 --- a/src/main/java/org/olat/ims/qti/qpool/QTIExportProcessor.java +++ b/src/main/java/org/olat/ims/qti/qpool/QTIExportProcessor.java @@ -49,6 +49,7 @@ import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; import org.olat.core.util.vfs.VFSLeaf; import org.olat.core.util.vfs.VFSManager; +import org.olat.core.util.vfs.filters.VFSSystemItemFilter; import org.olat.core.util.xml.XMLParser; import org.olat.ims.qti.QTIConstants; import org.olat.ims.qti.editor.QTIEditHelper; @@ -84,7 +85,7 @@ public class QTIExportProcessor { List<VFSItem> items = container.getItems(); addMetadata(fullItem, rootDir, zout); for(VFSItem item:items) { - ZipUtil.addToZip(item, rootDir, zout); + ZipUtil.addToZip(item, rootDir, zout, new VFSSystemItemFilter(), false); } } diff --git a/src/main/java/org/olat/ims/qti/repository/handlers/QTIHandler.java b/src/main/java/org/olat/ims/qti/repository/handlers/QTIHandler.java index d25ab9f9fbf98b00c4614ad8c4b7e211333ad1ca..8aaf95ba116351f62d4c35c5d92af7e5e8bdeb21 100644 --- a/src/main/java/org/olat/ims/qti/repository/handlers/QTIHandler.java +++ b/src/main/java/org/olat/ims/qti/repository/handlers/QTIHandler.java @@ -106,7 +106,7 @@ public abstract class QTIHandler extends FileHandler { File fResourceFileroot = FileResourceManager.getInstance().getFileResourceRootImpl(resource).getBasefile(); File zipDir = new File(fResourceFileroot, FileResourceManager.ZIPDIR); FileResource.copyResource(file, filename, zipDir); - ZipUtil.zipAll(zipDir, new File(fResourceFileroot, "qti.zip")); + ZipUtil.zipAll(zipDir, new File(fResourceFileroot, "qti.zip"), false); RepositoryEntry re = CoreSpringFactory.getImpl(RepositoryService.class).create(initialAuthor, null, "", displayname, description, resource, RepositoryEntryStatusEnum.preparation, organisation); DBFactory.getInstance().commit(); @@ -124,7 +124,7 @@ public abstract class QTIHandler extends FileHandler { File targetDir = new File(targetRootDir, FileResourceManager.ZIPDIR); FileResource.copyResource(sourceFile, sourceFile.getName(), targetDir, new ChangeLogFilter()); - ZipUtil.zipAll(targetDir, new File(targetRootDir, "qti.zip")); + ZipUtil.zipAll(targetDir, new File(targetRootDir, "qti.zip"), false); return target; } diff --git a/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_pt_BR.properties index 0782eac332e9c3916941f5e07a0169ee08cf991c..23bbdc87517e54fa2f20602a59c11c7879efb301 100644 --- a/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Tue May 26 15:37:35 CEST 2020 +#Thu Sep 24 14:23:44 CEST 2020 actualPoints=$org.olat.modules.iq\:actualPoints admin.menu.title=QTI 2.1 admin.menu.title.alt=Defini\u00E7\u00F5es do QTI 2.1 @@ -80,6 +80,8 @@ confirm.suspend.test=$org.olat.modules.iq\:confirmSuspend confirmation=Confirma\u00E7\u00E3o correct.solution=Solu\u00E7\u00E3o correta correction=Grau +correction.alternatives=Alternativa +correction.readonly=Ver corre\u00E7\u00E3o somente leitura correction.workflow=Workflow de corre\u00E7\u00E3o correction.workflow.anonymous=An\u00F4nimo countdown.running=Limite de tempo {1} segundos\: <strong>{0} segundos restantes</strong> @@ -140,6 +142,10 @@ interaction.order.drag.msg=Arraste itens n\u00E3o utilizados daqui ... interaction.order.drop.msg=Solte e ordene os itens selecionados aqui ... interaction.order.source=Fonte interaction.order.target=Alvo +invalidate=Invalidar +invalidate.overwrite=Invalidar e transferir o resultado +invalidate.test.confirm.text=Quer marcar esta sess\u00E3o de teste como inv\u00E1lida? Os dados n\u00E3o ser\u00E3o exclu\u00EDdos. +invalidate.test.confirm.title=Invalidar item.comment=Coment\u00E1rio kprim.minus=Falso kprim.plus=Verdadeiro @@ -189,6 +195,9 @@ question.progress.noMaxScore=$org.olat.modules.iq\:noMaxScore question.progress.score=$org.olat.modules.iq\:actualPoints question.title=Pergunta {0} questions=N\u00FAmero de perguntas no teste +reopen.assessment=Reabrir avalia\u00E7\u00E3o +reopen.assessment.text=Esta avalia\u00E7\u00E3o j\u00E1 est\u00E1 encerrada. Quer reabri-la para corrigir o teste? +reopen.assessment.title=Reabrir avalia\u00E7\u00E3o encerrada reset.data=Resetar dados reset.test.data.acknowledge=Eu entendo que os dados ser\u00E3o exclu\u00EDdos definitivamente. reset.test.data.text=Deseja realmente redefinir os dados de avalia\u00E7\u00E3o do teste? Os resultados de <strong>{0} usu\u00E1rios</strong> ser\u00E3o exclu\u00EDdos definitivamente. @@ -222,11 +231,19 @@ results.title.failed=Desculpe, voc\u00EA falhou no teste. results.title.for=para {0} results.title.generic=Estes s\u00E3o os resultados do seu teste results.title.passed=Voc\u00EA passou no teste\! +results.visibility.correction=Visibilidade dos resultados ap\u00F3s a corre\u00E7\u00E3o +results.visibility.correction.not.visible=N\u00E3o vis\u00EDvel +results.visibility.correction.visible=Vis\u00EDvel retrievetest.confirm.text=$org.olat.ims.qti\:retrievetest.confirm.text retrievetest.confirm.text.plural=$org.olat.ims.qti.statistics.ui\:retrievetest.confirm.text.plural retrievetest.confirm.title=$org.olat.ims.qti.statistics.ui\:retrievetest.confirm.title retrievetest.nothing.todo=$org.olat.ims.qti.statistics.ui\:retrievetest.nothing.todo retry.item=Tente novamente +revalidate=Marcar como v\u00E1lido +revalidate.overwrite=Marcar como v\u00E1lido e transferir o resultado +revalidate.test=Marque novamente como v\u00E1lido +revalidate.test.confirm.text=Quer marcar novamente esta sess\u00E3o de teste como v\u00E1lida? +revalidate.test.confirm.title=$\:revalidate.test review.responses=Revise suas respostas review.responses.desc=Voc\u00EA pode rever suas respostas de algumas (ou todas) perguntas. Estes s\u00E3o listados abaixo. score.cut=$org.olat.ims.qti\:score.cut @@ -249,6 +266,8 @@ table.header.corrected=Corrigido table.header.correction=$\:correction table.header.duration=Dura\u00E7\u00E3o table.header.finalScore=Pontua\u00E7\u00E3o final +table.header.id=ID +table.header.invalidate=Invalidar table.header.itemSessions=\# quest\u00F5es table.header.lastModified=Data table.header.manualScore=Pontua\u00E7\u00E3o manual @@ -276,8 +295,11 @@ upload.explanation=Selecione um arquivo do seu computador para fazer o upload validate.xml.signature=Validar recibo de teste validate.xml.signature.file=Arquivo XML validate.xml.signature.ok=O recibo do teste e os resultados foram validados com sucesso. +warning.assignment.done=A classifica\u00E7\u00E3o deste teste j\u00E1 foi conclu\u00EDda. Se esta sess\u00E3o de teste for marcada como inv\u00E1lida, todas as corre\u00E7\u00F5es existentes ser\u00E3o perdidas. +warning.assignment.inProcess=A pontua\u00E7\u00E3o da prova j\u00E1 come\u00E7ou. Se esta sess\u00E3o de teste for marcada como inv\u00E1lida, todas as corre\u00E7\u00F5es existentes ser\u00E3o perdidas. warning.download.log=N\u00E3o h\u00E1 um arquivo de log para este teste. warning.reset.assessmenttest.data=Os resultados do teste foram redefinidos por um administrador ou propriet\u00E1rio do curso. Voc\u00EA n\u00E3o pode continuar o teste e precisa reinici\u00E1-lo. warning.reset.test.data.nobody=N\u00E3o h\u00E1 nenhum participante que os dados possam ser resetados. +warning.suspended.ended.assessmenttest=Voc\u00EA j\u00E1 interrompeu ou finalizou o teste, provavelmente em outra janela. Por favor, feche esta janela agora. warning.xml.signature.notok=A assinatura e os resultados n\u00E3o podem ser validados um ao outro. warning.xml.signature.session.not.found=Resultados de testes n\u00E3o podem ser encontrados. diff --git a/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_pt_BR.properties index ef952030c571d869408d854b0e2be50459155b3d..fe554b792f67302332ff0a5def063f373c3caefa 100644 --- a/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Tue May 26 15:40:50 CEST 2020 +#Thu Sep 24 14:23:53 CEST 2020 anonymous.user=Examinando assessed.identity=Usu\u00E1rio avaliado back.overview=Voltar ao menu principal @@ -26,8 +26,10 @@ override.score=Substituir pontua\u00E7\u00E3o overview.tests=Vis\u00E3o geral e fechamento previous.item=Quest\u00E3o anterior previous.user=Usu\u00E1rio anterior +reopen.assessment.title=$org.olat.ims.qti21.ui\:reopen.assessment.title save.back=Salvar e voltar \u00E0 vis\u00E3o geral save.next=Salvar e pr\u00F3xima pergunta +save.next.identity=Salvar e pr\u00F3ximo participante save.tests=Salvar resultados como conclu\u00EDdos score=Pontua\u00E7\u00E3o show.rubric=Mostrar descri\u00E7\u00E3o diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_pt_BR.properties index f5644ca97006ea57d08866375c09264fdaf1bcee..8522a75963688a56dfdf989b5ff91e2a46915dfe 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Tue May 26 16:08:00 CEST 2020 +#Thu Sep 24 14:32:31 CEST 2020 MULTIPLE=M\u00FAltipla escolha SINGLE=Escolha \u00FAnica add=Adicionar @@ -45,6 +45,7 @@ error.cardinality.answer="Escolha \u00FAnica" permite apenas uma resposta corret error.double=$org.olat.ims.qti21.ui\:error.double error.import.question=Houve um erro inesperado durante a importa\u00E7\u00E3o de uma pergunta error.integer=$org.olat.ims.qti21.ui\:error.integer +error.integer.positive=Ele precisa de um n\u00FAmero entre 0 e 2147483647. error.lock=Este teste / question\u00E1rio est\u00E1 sendo editado pelo usu\u00E1rio {0} no momento e, portanto, est\u00E1 bloqueado. error.lock.same.user=$\:error.lock $org.olat.core\:lock.same.user.different.window error.lock.title=Teste bloqueado @@ -86,8 +87,11 @@ fib.tolerance.mode.exact=Exato fib.tolerance.mode.exact.help=A solu\u00E7\u00E3o correlaciona-se exatamente com a solu\u00E7\u00E3o inserida em "Solu\u00E7\u00E3o" fib.tolerance.mode.relative=Relativo fib.tolerance.mode.relative.help=A solu\u00E7\u00E3o \u00E9 aceita at\u00E9 um limite inferior e um limite superior. O limite \u00E9 um n\u00FAmero relativo em porcentagem. Exemplo\: Solu\u00E7\u00E3o 20, limite inferior 10, limite superior 10 & rarr; Todas as solu\u00E7\u00F5es entre 18 e 22 s\u00E3o corretas, j\u00E1 que o limite inferior significa menos 10% (20-2) e o limite superior mais 10% (20 + 2). +fib.tolerance.mode.relative.low.example=Toler\u00E2ncia inferior em porcentagem, exemplo 15 +fib.tolerance.mode.relative.up.example=Toler\u00E2ncia superior em porcentagem, exemplo 15 fib.tolerance.up=Limite superior file=Arquivo +force.inherited.max.attempts=Herdar o n\u00FAmero de tentativas para todos os subelementos (se\u00E7\u00F5es, perguntas) form.choice=Escolha form.drawing=Desenho form.essay=Reda\u00E7\u00E3o @@ -298,6 +302,10 @@ warning.custom.operator=Esta quest\u00E3o cont\u00E9m uma extens\u00E3o espec\u0 warning.feedback.cutvalue=O feedback \u00E9 baseado no valor de corte. Voc\u00EA precisa defini-lo primeiro. warning.in.use=O recurso j\u00E1 \u00E9 usado para fins de avalia\u00E7\u00E3o. A edi\u00E7\u00E3o \u00E9 limitada. warning.item.session.control.attempts=Esta limita\u00E7\u00E3o pode ter um impacto no n\u00FAmero de tentativas por perguntas. <br/>Verifique as configura\u00E7\u00F5es para as perguntas novamente. +warning.item.session.control.attempts.all.items.defined=Todas as quest\u00F5es j\u00E1 definiram o n\u00FAmero de tentativas e anulam este valor. +warning.item.session.control.attempts.all.sections.defined=Todas as se\u00E7\u00F5es j\u00E1 definiram o n\u00FAmero de tentativas e anulam este valor. +warning.item.session.control.attempts.items.defined=Algumas perguntas definiram o n\u00FAmero de tentativas e substitu\u00EDram este valor. +warning.item.session.control.attempts.sections.defined=Certas se\u00E7\u00F5es definiram o n\u00FAmero de tentativas e substitu\u00EDram este valor. warning.templates=Esta quest\u00E3o cont\u00E9m alguns modelos que n\u00E3o s\u00E3o compat\u00EDveis com o editor OpenOlat. warning.text.after.interaction=Esta quest\u00E3o tem texto ap\u00F3s o elemento de intera\u00E7\u00E3o. Isso n\u00E3o \u00E9 compat\u00EDvel com o editor OpenOlat e o texto ser\u00E1 perdido ap\u00F3s a convers\u00E3o. warning.unsupported.feedbacks=Esta quest\u00E3o cont\u00E9m coment\u00E1rios que n\u00E3o s\u00E3o compat\u00EDveis com o editor OpenOlat. Eles podem ser perdidos ap\u00F3s a convers\u00E3o. diff --git a/src/main/java/org/olat/ims/qti21/ui/report/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/ims/qti21/ui/report/_i18n/LocalStrings_pt_BR.properties new file mode 100644 index 0000000000000000000000000000000000000000..144970981a86764323b01105b6490c1eecb78dd1 --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/ui/report/_i18n/LocalStrings_pt_BR.properties @@ -0,0 +1,31 @@ +#Thu Sep 24 14:58:24 CEST 2020 +admin.menu.report.question.title=Perguntas para testes +admin.menu.report.question.title.alt=Perguntas para testes +report.course.displayname=T\u00EDtulo do curso +report.course.externalref=Refer\u00EAncia do curso +report.course.id=ID do curso +report.explain=Relat\u00F3rio\: testes selecionados incluindo todas as quest\u00F5es contidas +report.question.author=Criador da pergunta (propriet\u00E1rio) +report.question.context=N\u00EDvel +report.question.correction.time=$org.olat.modules.qpool.ui\:question.correctionTime +report.question.identifier=ID da quest\u00E3o +report.question.keywords=Palavras-chave +report.question.license=$org.olat.modules.qpool.ui\:rights.license +report.question.master.author=Criador (ID mestre do propriet\u00E1rio) +report.question.master.identifier=ID mestre da pergunta +report.question.master.keywords=Palavras-chave (ID mestre da pergunta) +report.question.taxonomy.level=Assunto +report.question.taxonomy.path=Caminho do assunto +report.question.title=T\u00EDtulo da pergunta +report.question.to.course=Reportar quest\u00F5es +report.question.topic=T\u00F3pico +report.question.type=Tipo +report.test.author=Criador do teste (propriet\u00E1rio) +report.test.displayname=T\u00EDtulo do teste do recurso did\u00E1tico +report.test.externalref=Refer\u00EAncia do teste +report.test.id=ID de teste (recurso did\u00E1tico) +search=Busca +search.author=Autor / propriet\u00E1rio +search.empty=N\u00E3o foram encontrados testes que atendessem aos seus crit\u00E9rios. +search.text=T\u00EDtulo / Ref. Ext / ID +warning.at.least.one.test=Voc\u00EA deve escolher pelo menos um teste. diff --git a/src/main/java/org/olat/modules/appointments/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/modules/appointments/ui/_i18n/LocalStrings_pt_BR.properties new file mode 100644 index 0000000000000000000000000000000000000000..3e43939685e3373357ebb88996b5b1e4692b66a0 --- /dev/null +++ b/src/main/java/org/olat/modules/appointments/ui/_i18n/LocalStrings_pt_BR.properties @@ -0,0 +1,166 @@ +#Thu Sep 24 20:01:49 CEST 2020 +add.appointment=Adicionar compromisso +add.appointment.button=Adicionar +add.appointment.recurring=Adicionar compromissos recorrentes +add.appointment.single=Adicionar compromissos \u00FAnico +add.appointment.title=Adicionar compromisso +add.topic=Adicionar compromissos +add.topic.title=$\:add.topic +add.user=Adicionar usu\u00E1rio +add.user.title=$\:add.user +appointment.delete.participations={0} participantes selecionaram este compromisso. Esses participantes devem ser remarcados? +appointment.details=Detalhes +appointment.end=Fim +appointment.free.participations=Participantes dispon\u00EDveis +appointment.id=ID +appointment.init.value=Este valor inicial \u00E9 definido para todos os compromissos. Ele pode ser editado separadamente em cada compromisso posteriormente. +appointment.last=\u00DAltima consulta +appointment.location=Localiza\u00E7\u00E3o +appointment.max.participations=N\u00FAmero m\u00E1ximo de participantes +appointment.next=Pr\u00F3ximo compromisso +appointment.number.of.participations=No. participantes +appointment.select=Selecione o compromisso +appointment.selected=Compromisso selecionado +appointment.start=Iniciar +appointment.status=Status +appointment.status.confirmed=Confirmado +appointment.status.planned=N\u00E3o confirmado +appointments=Compromissos +appointments.confirmable={0} compromissos precisam ser confirmados. +appointments.confirmable.none=Nenhum compromisso precisa ser confirmado. +appointments.confirmable.one=Um compromisso deve ser confirmado. +appointments.finding.confirmed=Um encontro foi confirmado. Voc\u00EA n\u00E3o est\u00E1 neste compromisso. +appointments.free=Restam {0} compromissos. +appointments.free.no=N\u00E3o h\u00E1 marca\u00E7\u00F5es gratuitas. +appointments.free.one=Resta um compromisso. +appointments.open=Mostrar compromissos +appointments.recurring=Compromissos recorrentes +appointments.recurring.days.of.week=Dias da semana +appointments.recurring.first=Primeiro compromisso +appointments.recurring.last=\u00DAltimo compromisso +appointments.select=Selecione os compromissos +appointments.select.multi.message=Selecione os compromissos desejados. +appointments.select.one.message=Selecione o compromisso desejado. +appointments.selected=Voc\u00EA tem {0} compromissos selecionados. +appointments.selected.not.confirmed=Nenhum compromisso foi confirmado ainda. +appointments.total=Existem {0} compromissos dispon\u00EDveis. +appointments.total.one=H\u00E1 um compromisso dispon\u00EDvel. +condition.accessibility.title=Acesso +config.confirmation=Confirma\u00E7\u00E3o pelo treinador +config.multi.participation=Sele\u00E7\u00E3o de v\u00E1rios compromissos +confirm=Confirmar +confirm.appointment.delete=Tem certeza de que deseja excluir este compromisso? +confirm.appointment.delete.title=Excluir compromisso +confirm.participation.self=Tem certeza de que deseja se inscrever para este compromisso ({0})? Nenhum outro compromisso pode ser escolhido posteriormente. +confirm.participation.self.multi=Tem certeza de que deseja se inscrever para este compromisso ({0})? A nomea\u00E7\u00E3o n\u00E3o pode ser recusada posteriormente. +confirm.participation.self.title=Selecione o compromisso +confirm.topic.delete=Tem certeza de que deseja excluir todos os compromissos? +confirm.topic.delete.title=Excluir compromissos +delete=Excluir +delete.topic=Excluir +edit.appointment.button=Salvar +edit.appointment.title=Editar compromisso +edit.groups=Restri\u00E7\u00F5es de participa\u00E7\u00E3o +edit.topic=Editar t\u00F3pico +edit.topic.title=Editar t\u00F3pico +email.organizer.recipients=Organizadores +email.organizer.subject=Compromisso "{0}" +email.title=Nova mensagem +error.config.not.changeable=A configura\u00E7\u00E3o n\u00E3o pode mais ser alterada. Ele foi redefinido para os valores originais. +error.first.after.start=A \u00FAltima consulta n\u00E3o deve ser antes da primeira. +error.not.as.many.participations.left=Nem tantos usu\u00E1rios podem ser adicionados a este compromisso. +error.positiv.number=Precisa ser um n\u00FAmero inteiro positivo. +error.rebook=A remarca\u00E7\u00E3o dos participantes falhou. +error.select.appointment=Voc\u00EA tem que selecionar um compromisso. +error.select.participant=Voc\u00EA tem que selecionar um participante. +error.start.after.end=A data de t\u00E9rmino n\u00E3o deve ser anterior \u00E0 data de in\u00EDcio. +error.too.much.participations=J\u00E1 existem {0} participa\u00E7\u00F5es. +error.user.remove.atleastone=Voc\u00EA deve selecionar pelo menos um usu\u00E1rio. +filter.all=Mostrar tudo +filter.future=Futuro +filter.participated=Selecionados +finding.confirmation.empty.table=Nenhum participante p\u00F4de selecionar este compromisso. +finding.confirmation.info=Deseja realmente confirmar este compromisso?<br><br>Na lista abaixo voc\u00EA pode ver quais participantes escolheram este compromisso. Voc\u00EA pode adicionar mais participantes ao compromisso ou remover participantes do compromisso. +full.day=Dia inteiro +full.day.lower=dia inteiro +groups.business.groups=Participantes do grupo +groups.course=Participantes do curso +groups.curriculum=Participantes do curr\u00EDculo +groups.info=Aqui voc\u00EA pode restringir o acesso aos compromissos para grupos ou usu\u00E1rios individuais. Se voc\u00EA n\u00E3o selecionar nada, todos os usu\u00E1rios ter\u00E3o acesso aos compromissos. +groups.title=Restri\u00E7\u00F5es de grupo +groups.users.add=Adicionar +groups.users.add.title=Adicionar usu\u00E1rio +groups.users.empty.table=Nenhum usu\u00E1rio foi selecionado. +groups.users.remove=Remover +groups.users.remove.confirm.text=Tem certeza de que deseja remover os usu\u00E1rios selecionados? +groups.users.remove.confirm.title=Remover usu\u00E1rio +groups.users.title=Restri\u00E7\u00F5es de usu\u00E1rios +groups.users.username=Nome do usu\u00E1rio +mail.appointments.deleted.body=Caro {0} <br><br>Os seguintes compromissos foram exclu\u00EDdos.<br><br>{1} +mail.appointments.deleted.subject=Compromissos exclu\u00EDdos +mail.confirmed.body=Caro {0} <br><br>O seguinte compromisso foi confirmado.<br><br>{1} +mail.confirmed.subject=Compromisso "{0}" confirmado +mail.day=Data\: {0} (dia inteiro) +mail.deleted.body=Caro {0} <br><br>O seguinte compromisso foi recusado.<br><br>{1} +mail.deleted.subject=Compromisso "{0}" recusado +mail.end=Fim\: {0} +mail.location=Localiza\u00E7\u00E3o\: {0} +mail.participation.created.body=Caro {0} <br><br>Voc\u00EA foi adicionado ao seguinte compromisso.<br><br>{1} +mail.participation.created.subject=Adicionado ao compromisso "{0}" +mail.participation.deleted.body=Caro {0} <br><br>Voc\u00EA foi removido do seguinte compromisso.<br><br>{1} +mail.participation.deleted.subject=Removido do compromisso "{0}" +mail.rebooked.body=Caro {0} <br><br>O seguinte compromisso foi marcado novamente.<br><br><b>Compromisso anterior</b><br>{1}<br><b>Novo compromisso</b><br> {2} +mail.rebooked.subject=Compromisso remarcado +mail.start=In\u00EDcio\: {0} +mail.topic=T\u00F3pico\: {0} +mail.unconfirmed.body=Caro {0} <br><br>O seguinte compromisso foi reaberto.<br><br>{1} +mail.unconfirmed.subject=Compromisso "{0}" reaberto +no.appointments=Sem compromissos dispon\u00EDveis. +no.topics=Sem compromissos dispon\u00EDveis. +notification.new.participation={1} inscrito em "{0}". +notifications.header=Compromissos no curso "{0}" +notifications.title=Agendamento de consulta no curso "{0}" +organizer=Organizador +organizer.separator=, +organizer.with=com +participants=Participantes +participation.created.by=<i>Voc\u00EA foi adicionado a este compromisso por {0}.</i> +participation.not.created=Voc\u00EA n\u00E3o foi adicionado ao compromisso. +participations.free=Restam {0} lugares. +participations.free.one=Resta um lugar. +participations.not.created=Os usu\u00E1rios n\u00E3o foram adicionados ao compromisso. +participations.number.of={0} participantes +participations.number.of.one={0} participante +participations.selected.many.many={0} participantes selecionaram {1} compromissos. +participations.selected.many.one={0} participantes selecionaram um compromisso. +participations.selected.one.many=Um participante selecionou {0} compromissos. +participations.selected.one.one=Um participante selecionou um compromisso. +rebook=Reagendar +remove.user=Remover usu\u00E1rio +remove.user.appointments=Compromisso +remove.user.change=Remover +remove.user.delete=Excluir +remove.user.no.appointments=$\:remove.user.appointments +remove.user.no.appointments.text=<i>N\u00E3o h\u00E1 compromissos com vagas livres suficientes.</i> +remove.user.participation=Participantes +remove.user.rebook=Reagendar +remove.user.title=Remover usu\u00E1rio +save.back=Salvar e voltar +select=Selecionar +table.empty.appointments=N\u00E3o h\u00E1 compromissos dispon\u00EDveis. +table.header.delete=<i class\='o_icon o_icon-lg o_icon_delete'> </i> +table.header.id=ID +table.header.organizer=Organizador +table.header.participation=Compromisso +topic.coach.confirmation=Confirma\u00E7\u00E3o pelo treinador +topic.configuration=Configura\u00E7\u00E3o +topic.description=Descri\u00E7\u00E3o +topic.description.closed=Mostrar descri\u00E7\u00E3o dos compromissos +topic.description.opened=Esconder a descri\u00E7\u00E3o dos compromissos +topic.multi.participation=Sele\u00E7\u00E3o de v\u00E1rios compromissos +topic.title=T\u00EDtulo +topic.type=Tipo +topic.type.enrollment=Inscri\u00E7\u00E3o +topic.type.finding=Encontrar compromisso +unconfirm=Reabrir +unconfirmed=n\u00E3o confirmado diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_pt_BR.properties index 81876d1ffdc6ed9a153416cbb003732add42b320..8e9f0c25f5c8ca6188e9392f08fece988829f642 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Tue May 26 17:54:06 CEST 2020 +#Thu Sep 24 20:15:52 CEST 2020 account.configuration=Configura\u00E7\u00E3o add.daily.meeting=Adicionar reuni\u00E3o recorrente di\u00E1ria add.meeting=Adicionar reuni\u00E3o @@ -22,16 +22,23 @@ bigbluebutton.module.enabled=M\u00F3dulo "BigBlueButton" bigbluebutton.module.enabled.for=Ativar para bigbluebutton.module.enabled.for.courses=Cursos bigbluebutton.module.enabled.for.groups=Grupos +bigbluebutton.recording.handler=Manipulador de grava\u00E7\u00E3o bigbluebutton.servers=Servidores bigbluebutton.servers.empty=Voc\u00EA n\u00E3o configurou um servidor. bigbluebutton.title=Configura\u00E7\u00E3o do servi\u00E7o BigBlueButton Web Conferencing calendar.open=Mostrar reservas de salas calendar.title=Calend\u00E1rio check=Verifique a conex\u00E3o +collaboration.access=Gerenciar reuni\u00F5es BigBlueButton +collaboration.access.all=Todos os membros +collaboration.access.owners.coaches=Propriet\u00E1rios resp. treinadores +collaboration.access.title=Configure o gerenciamento do BigBlueButton confirm.delete.meeting=Voc\u00EA realmente deseja excluir a reuni\u00E3o "{0}"? confirm.delete.meeting.title=Excluir reuni\u00E3o "{0}" confirm.delete.meetings=Deseja realmente excluir as {0} reuni\u00F5es online ({1})? confirm.delete.meetings.title=Excluir {0} reuni\u00F5es online +confirm.delete.recording=Tem certeza de que deseja excluir a grava\u00E7\u00E3o "{0}"? A grava\u00E7\u00E3o exclu\u00EDda n\u00E3o pode ser recuperada. +confirm.delete.recording.title=Excluir grava\u00E7\u00E3o "{0}" confirm.delete.server=Deseja realmente excluir o servidor "{0}"? <strong>Todas as reuni\u00F5es e grava\u00E7\u00F5es tamb\u00E9m ser\u00E3o exclu\u00EDdas.</strong> confirm.delete.server.title=Excluir servidor "{0}" confirm.delete.template=Deseja realmente excluir o modelo de sala "{0}"? @@ -58,6 +65,8 @@ error.duration=A dura\u00E7\u00E3o da reuni\u00E3o \u00E9 muito longa. Dura\u00E error.end.past=A reuni\u00E3o online n\u00E3o pode ser planejada no passado. error.first.date.in.past=A data da primeira reuni\u00E3o n\u00E3o pode estar no passado. error.formatError=O formato de "{0}" n\u00E3o \u00E9 v\u00E1lido. +error.identifier.in.use=O nome j\u00E1 est\u00E1 em uso. Por favor escolha outro. +error.identifier.url.not.valid=O URL n\u00E3o ser\u00E1 v\u00E1lido. Remova caracteres especiais como $,? e espa\u00E7os. error.illegalOperation=Opera\u00E7\u00E3o n\u00E3o \u00E9 permitida. error.invalid.meeting=A reuni\u00E3o foi criada com outra configura\u00E7\u00E3o e n\u00E3o pode mais ser aberta. error.invalidField=O valor de "{0}" n\u00E3o \u00E9 v\u00E1lido. @@ -77,23 +86,39 @@ error.unkown=Erro desconhecido error.url.invalid=URL de servidor inv\u00E1lido filter.all.instances=Todos os OpenOlats filter.this.instance=Este OpenOlat +layout.standard=Padr\u00E3o +layout.webcam=Reuni\u00E3o de webcam meeting.configure.button=V\u00E1 e configure a sala meeting.create.button=Abrir a reuni\u00E3o meeting.create.intro=A reuni\u00E3o ainda n\u00E3o foi aberta. Os participantes n\u00E3o podem entrar na sala de aula para uma reuni\u00E3o. +meeting.creator=Criador meeting.day=Data da reuni\u00E3o meeting.deleted=Reuni\u00E3o exclu\u00EDda com sucesso. meeting.description=Descri\u00E7\u00E3o meeting.disclaimer.privacy=<strong>Datenschutzhinweis</strong><p>Im Rahmen der Online-Lehre ist es unumg\u00E4nglich personenbezogene Daten \u00FCber Sie zu verarbeiten. N\u00E4here Informationen \u00FCber die Verarbeitung und die M\u00F6glichkeit der Nutzung von Aliasnamen zum Schutz Ihrer Daten finden Sie unter\: <a href="https\://www.uibk.ac.at/datenschutz/besucherinnen-von-lv/">https\://www.uibk.ac.at/datenschutz/besucherinnen-von-lv/</a></p><strong>Hinweise für Studierende</strong><p>Jegliche \u00FCber ein Ansehen hinausgehende Verwendung der zur Verf\u00FCgung gestellten Aufnahmen (herunterladen, kopieren, ver\u00F6ffentlichen, etc.) f\u00FCr den eigenen Gebrauch, kann ohne Einwilligung der Rechteinhaber rechtliche Folgen nach sich ziehen.</p> meeting.end=Data final meeting.ended=A reuni\u00E3o j\u00E1 terminou. +meeting.external.users=Acessar usu\u00E1rios externos +meeting.external.users.empty=O acesso ao URL para usu\u00E1rios externos est\u00E1 desativado +meeting.external.users.help=Para permitir que usu\u00E1rios externos acessem a reuni\u00E3o por meio de um URL, voc\u00EA pode definir uma refer\u00EAncia de reuni\u00E3o aqui. Voc\u00EA pode ent\u00E3o compartilhar o URL gerado, por exemplo via email. A refer\u00EAncia deve ser uma palavra \u00FAnica sem caracteres especiais. meeting.followupTime=Acompanhamento (min.) meeting.go.button=V\u00E1 para a sala de reuni\u00E3o +meeting.guest=Convidados +meeting.guest.join.button=Junte-se \u00E0 reuni\u00E3o online +meeting.guest.on=permitidos +meeting.guest.pseudo=Seu nome +meeting.guest.pseudo.explain=Por favor, digite seu nome e pressione o bot\u00E3o para entrar na reuni\u00E3o online. meeting.join.button=Junte-se \u00E0 reuni\u00E3o +meeting.layout=Layout meeting.leadTime=Tempo de prepara\u00E7\u00E3o (min.) meeting.leadTime.explain=O tempo de prepara\u00E7\u00E3o \u00E9 relevante apenas para moderadores. +meeting.main.presenter=Apresentador principal meeting.name=Nome meeting.permanent=Tipo meeting.permanent.on=Permanente +meeting.publishing=Publicar grava\u00E7\u00E3o +meeting.publishing.auto=Autom\u00E1tico +meeting.publishing.manual=Manual meeting.recurring.end=Data final recorrente meeting.recurring.start=Iniciar data recorrente meeting.register.button=Registro @@ -105,6 +130,7 @@ meeting.start.button=Iniciar a reuni\u00E3o meeting.successfully.registered=Registrado com sucesso. meeting.template=Modelo de sala meeting.templates=Modelo +meeting.url.external.users=Link para usu\u00E1rios externos meeting.welcome=Mensagem de boas-vindas meetings.admin.title=Configura\u00E7\u00E3o meetings.content=Conte\u00FAdo @@ -112,6 +138,7 @@ meetings.past=Reuni\u00F5es antigas meetings.title=Reuni\u00F5es meetings.upcoming=Pr\u00F3ximas reuni\u00F5es minutes={0} min. +native.recording.handler=Nativo no.contents=Esta reuni\u00E3o n\u00E3o tem nenhum conte\u00FAdo no.meeting.configured=Nenhuma reuni\u00E3o foi configurada ainda. no.recordings=N\u00E3o h\u00E1 grava\u00E7\u00E3o dispon\u00EDvel para esta reuni\u00E3o on-line no momento. @@ -119,6 +146,7 @@ no.shared.contents=Nenhuma reuni\u00E3o futura agendada. no.template=Sem modelo no.template.configured=N\u00E3o h\u00E1 modelos de sala ativos dispon\u00EDveis. no.upcoming.meetings=Voc\u00EA n\u00E3o tem nenhuma reuni\u00E3o futura. +opencast.recording.handler=Opencast option.accountid=ID da conta option.accountid.explain=O ID da conta \u00E9 opcional. Se o ID da conta n\u00E3o for especificado, a conta do usu\u00E1rio acima ser\u00E1 usada. option.adminlogin=Usu\u00E1rio @@ -139,6 +167,13 @@ option.recordingurl=URL de grava\u00E7\u00E3o option.single.meeting=Reuni\u00F5es compartilhadas option.single.meeting.perdate=Criar uma sala de reuni\u00E3o por data option.single.meeting.single=Criar apenas uma sala de reuni\u00E3o por elemento ou grupo do curso +publish.recording=Publicar +publish.to=Publicar +publish.to.all=Todos os participantes da reuni\u00E3o (sem convidados) +publish.to.coach=Propriet\u00E1rios e treinadores +publish.to.guest=Convidados +publish.to.list=publicar em\: +publish.to.participant=Participantes do curso / grupo recording.browser.infos=As grava\u00E7\u00F5es s\u00F3 podem ser visualizadas no Google Chrome ou Firefox. recording.type.podcast=Podcast recording.type.presentation=Apresenta\u00E7\u00E3o @@ -159,6 +194,7 @@ table.header.breakout.recording.meetings=\# Breakout Grava\u00E7\u00E3o table.header.capacity.factor=Capacidade table.header.day.week=Dia table.header.enabled=Ativo +table.header.external.users=Usu\u00E1rios externos table.header.listener.count=\# Ouvintes table.header.load=Carregar table.header.max.concurrent.meetings=Salas @@ -169,6 +205,7 @@ table.header.moderator.count=\# Moderador table.header.number.meetings=\# Encontros table.header.participant.count=\# Participantes table.header.permanent=Permanente +table.header.publish=Publicar table.header.recording.end=Fim table.header.recording.meetings=\# Grava\u00E7\u00F5es table.header.recording.name=Nome @@ -193,6 +230,7 @@ template.description=Descri\u00E7\u00E3o template.enabled=Ativar modelo de sala template.explain.max.participants=M\u00E1x. n\u00FAmero de participantes\: {0} ({1} salas dispon\u00EDveis template.explain.max.participants.with.webcams.mod=M\u00E1x. n\u00FAmero de participantes\: {0}, apenas moderador com webcam ({1} salas dispon\u00EDveis) +template.external.enabled=Aberto para usu\u00E1rios externos template.lock=Para participantes bloqueados... template.lockSettingsDisableCam=desativar webcam template.lockSettingsDisableMic=desativar microfone @@ -216,10 +254,12 @@ undelete=Reativar view=Mostrar view.template=Modelo de sala "{0}" warning.at.least.one.meeting=Voc\u00EA deve selecionar pelo menos uma reuni\u00E3o. +warning.meeting.permission.denied=Voc\u00EA n\u00E3o tem permiss\u00E3o para acessar a reuni\u00E3o online. Por favor, tente novamente mais tarde. warning.meeting.started=Voc\u00EA n\u00E3o pode mais editar uma reuni\u00E3o iniciada. warning.no.access=Voc\u00EA n\u00E3o pode acessar a reuni\u00E3o ainda. warning.no.meeting=A reuni\u00E3o foi exclu\u00EDda. warning.not.registered.shared.documents=Somente as pessoas que participaram da reuni\u00E3o podem abrir os documentos compartilhados. +warning.recording.not.found=A grava\u00E7\u00E3o n\u00E3o pode ser encontrada. warning.template.in.use=O modelo de sala n\u00E3o pode ser exclu\u00EDdo porque \u00E9 usado por reuni\u00F5es online. Exclua a reuni\u00E3o online correspondente ou desative o modelo da sala. wizard.dates.title=Datas wizard.meeting.title=Configura\u00E7\u00E3o diff --git a/src/main/java/org/olat/modules/cp/CPOfflineReadableManager.java b/src/main/java/org/olat/modules/cp/CPOfflineReadableManager.java index e4f453e01521341068a8beaa1e463472d9bad68d..a9b1e4a05849d9c144a9611c1538b47cd7bcaeb5 100644 --- a/src/main/java/org/olat/modules/cp/CPOfflineReadableManager.java +++ b/src/main/java/org/olat/modules/cp/CPOfflineReadableManager.java @@ -53,6 +53,7 @@ import org.olat.core.util.StringHelper; import org.olat.core.util.WebappHelper; import org.olat.core.util.ZipUtil; import org.olat.core.util.vfs.LocalFileImpl; +import org.olat.core.util.vfs.filters.VFSAllItemsFilter; import org.olat.fileresource.FileResourceManager; import org.olat.modules.cp.CPManifestTreeModel.UserObject; @@ -306,10 +307,9 @@ public class CPOfflineReadableManager { for (int i = 0; i < cpFiles.length; i++) { allFilesInUnzippedDir.add(cpFiles[i]); } - boolean zipResult = ZipUtil.zip(allFilesInUnzippedDir, unzippedDir, targetZip, true); - - if(!targetZip.exists()){ - log.warn("targetZip does not exists after zipping. zip-result is: "+ zipResult); + boolean zipResult = ZipUtil.zip(allFilesInUnzippedDir, unzippedDir, targetZip, VFSAllItemsFilter.ACCEPT_ALL, false); + if(!targetZip.exists()) { + log.warn("targetZip does not exists after zipping. zip-result is: {}", zipResult); } } diff --git a/src/main/java/org/olat/modules/edusharing/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/modules/edusharing/ui/_i18n/LocalStrings_pt_BR.properties index 5c77e9b21dc6df5de2c1b6e7e3048dc97b6cd301..9419316c71134ed45c6e63f25f84e20f1cb9cde0 100644 --- a/src/main/java/org/olat/modules/edusharing/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/modules/edusharing/ui/_i18n/LocalStrings_pt_BR.properties @@ -1,6 +1,7 @@ -#Mon Feb 04 18:28:41 CET 2019 +#Thu Sep 24 20:05:24 CEST 2020 admin.app.id=ID do aplicativo admin.client.test=Teste +admin.course.node.enabled=Elemento de curso admin.desc=O Edu-sharing \u00E9 um software para plataformas de aprendizagem em rede, trocando conte\u00FAdo de aprendizagem, metadados e ferramentas e tornando-as pesquis\u00E1veis em uma nuvem educacional e utiliz\u00E1veis em todos os sistemas conectados. Mais informa\u00E7\u00F5es podem ser encontradas no <a href\="https\://edu-sharing.com/" target\=_blank>site</a> de edu-sharing. <br/><br/> A configura\u00E7\u00E3o acontece em quatro etapas\:<br/>1. Insira e salve os valores de configura\u00E7\u00E3o.<br/>2. Gere e salve as chaves.<br/>3. Importe e salve a chave p\u00FAblica de compartilhamento de compartilhamento de edu.<br/>4. No compartilhamento de edu\: Conecte o OpenOlat como um aplicativo. URL com metadados\: {0} <br/> admin.enable.confirm.message=Voc\u00EA realmente deseja ativar o m\u00F3dulo "edu-sharing"? Por favor, note que os dados pessoais do usu\u00E1rio, como nome de usu\u00E1rio, primeiro nome, sobrenome e endere\u00E7o de e-mail podem ser transferidos para o "edu-sharing" admin.enable.confirm.title=Ativar m\u00F3dulo diff --git a/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_pt_BR.properties index d6bb0d7a1f5b8353e18655f032c1d3829bab622f..9b942b46b0756a6f01a8026d14da568bc63341e5 100644 --- a/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Tue May 26 20:11:03 CEST 2020 +#Thu Sep 24 20:15:53 CEST 2020 add.formcontainer=Recipiente add.formdisclaimer=Termos de uso add.formfileupload=Enviar arquivo diff --git a/src/main/java/org/olat/modules/glossary/GlossaryManagerImpl.java b/src/main/java/org/olat/modules/glossary/GlossaryManagerImpl.java index c4ec7fb5b3d3f673695ae6b359e1e72507b2fa13..e3d967d0fddf41a0c9609661999060addc7eeb51 100644 --- a/src/main/java/org/olat/modules/glossary/GlossaryManagerImpl.java +++ b/src/main/java/org/olat/modules/glossary/GlossaryManagerImpl.java @@ -172,7 +172,7 @@ public class GlossaryManagerImpl implements GlossaryManager { String exportFileName = repoEntry.getDisplayname(); exportFileName = StringHelper.transformDisplayNameToFileSystemName(exportFileName); VFSContainer glossaryRoot = getGlossaryRootFolder(res); - return new ZippedContainerMediaResource(exportFileName, glossaryRoot); + return new ZippedContainerMediaResource(exportFileName, glossaryRoot, false); } diff --git a/src/main/java/org/olat/modules/grading/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/modules/grading/ui/_i18n/LocalStrings_pt_BR.properties index 80fa93bb10233e62bf9c54e698cc05378ee8fdf4..3c8875a4bf651466b373616e324d349fc22b2eb9 100644 --- a/src/main/java/org/olat/modules/grading/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/modules/grading/ui/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Tue May 26 20:11:14 CEST 2020 +#Thu Sep 24 20:06:34 CEST 2020 absence.grader.title=Adicione uma licen\u00E7a de aus\u00EAncia para "{0}" add.grader=Adicionar revisor admin.menu.title=Revisor @@ -71,11 +71,18 @@ grading.enabled=Ativar fluxo de trabalho de revis\u00E3o grading.infos.configuration=Configura\u00E7\u00E3o grading.infos.graders=Revisores grading.my.assignments.title=Minhas tarefas de revis\u00E3o +grading.real.correction.time.administrator=$org.olat.admin.user\:role.administrator +grading.real.correction.time.author=$org.olat.admin.user\:role.author +grading.real.correction.time.grader=Avaliador +grading.real.correction.time.learnresourcemanager=$org.olat.admin.user\:role.learnresourcemanager +grading.real.correction.time.visibility=Visibilidade dos minutos reais de corre\u00E7\u00E3o grading.repo.enabled=Ativar revis\u00E3o info.grader.activated=O revisor "{0}" foi ativado com sucesso. mail.grader.to.entry.body=Voc\u00EA \u00E9 um revisor agora mail.grader.to.entry.subject=Como revisor mail.notification.body=Nova atribui\u00E7\u00E3o de revis\u00E3o para $coursetitle +mail.notification.participant.body=Seus \u00FAltimos resultados est\u00E3o vis\u00EDveis em\: $courseurl +mail.notification.participant.subject=Novos resultados mail.notification.subject=Nova tarefa de revis\u00E3o mail.reminder1.body=Primeiro lembrete para a atribui\u00E7\u00E3o de $coursetitle mail.reminder1.subject=Primeiro lembrete @@ -84,6 +91,8 @@ mail.reminder2.subject=Segundo lembrete e \u00FAltimo mail.to.grader.body=Texto para revisor mail.to.grader.subject=Assunto para revisor notification.body=Texto para notifica\u00E7\u00E3o +notification.participant.body=Texto para notifica\u00E7\u00E3o ao participante +notification.participant.subject=Assunto para notifica\u00E7\u00E3o ao participante notification.subject=Assunto para notifica\u00E7\u00E3o passed.false=$org.olat.course.assessment\:passed.false passed.false.label=N\u00E3o passou diff --git a/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_pt_BR.properties new file mode 100644 index 0000000000000000000000000000000000000000..cb941db3b23473b5cefbea8bc285c411003ac337 --- /dev/null +++ b/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_pt_BR.properties @@ -0,0 +1,18 @@ +#Thu Sep 24 20:16:37 CEST 2020 +admin.api.password=Senha API +admin.api.url=URL API +admin.api.url.example=https\://admin.opencast.example.com/api +admin.api.username=Usu\u00E1rio da API +admin.auth.delegate.roles=Fun\u00E7\u00F5es de autoriza\u00E7\u00E3o +admin.auth.delegate.type=Autoriza\u00E7\u00E3o do administrador +admin.auth.delegate.type.none=Nenhum +admin.auth.delegate.type.roles=Fun\u00E7\u00F5es +admin.auth.delegate.type.user=Usu\u00E1rio +admin.bbb.enabled=Grava\u00E7\u00F5es BigBlueButton +admin.check.api.connection=Verifique a conex\u00E3o API +admin.course.node.enabled=Elemento do curso +admin.enabled=M\u00F3dulo "Opencast" +admin.lti.key=Chave LTI +admin.lti.secret=Segredo LTI +admin.lti.sign.url=URL de assinatura LTI +admin.lti.sign.url.example=http\://localhost\:8080/lti diff --git a/src/main/java/org/olat/modules/sharedfolder/SharedFolderManager.java b/src/main/java/org/olat/modules/sharedfolder/SharedFolderManager.java index 241435b4cb6dec8bc64109f443a76432172ab21b..e2191d6e3802428542346c95b023c1bd523ea151 100644 --- a/src/main/java/org/olat/modules/sharedfolder/SharedFolderManager.java +++ b/src/main/java/org/olat/modules/sharedfolder/SharedFolderManager.java @@ -93,7 +93,7 @@ public class SharedFolderManager { VFSContainer sharedFolder = getSharedFolder(res); // do intermediate commit to avoid transaction timeout DBFactory.getInstance().intermediateCommit(); - return new ZippedContainerMediaResource(exportFileName, sharedFolder); + return new ZippedContainerMediaResource(exportFileName, sharedFolder, true); } public boolean exportSharedFolder(String sharedFolderSoftkey, File exportedDataDir) { diff --git a/src/main/java/org/olat/modules/webFeed/dispatching/FeedMediaDispatcher.java b/src/main/java/org/olat/modules/webFeed/dispatching/FeedMediaDispatcher.java index f45c717b478b869cd958c55d4636dde65df030b6..2519d1985759b267bfeb6d409e08ba0d64e19c46 100644 --- a/src/main/java/org/olat/modules/webFeed/dispatching/FeedMediaDispatcher.java +++ b/src/main/java/org/olat/modules/webFeed/dispatching/FeedMediaDispatcher.java @@ -20,6 +20,7 @@ package org.olat.modules.webFeed.dispatching; import java.io.IOException; +import java.util.HashMap; import java.util.List; import javax.servlet.http.HttpServletRequest; @@ -411,6 +412,7 @@ public class FeedMediaDispatcher implements Dispatcher, GenericEventListener { hasAccess = reSecurity.canLaunch(); } else { IdentityEnvironment ienv = new IdentityEnvironment(identity, roles); + ienv.setAttributes(new HashMap<>()); UserCourseEnvironment userCourseEnv = new UserCourseEnvironmentImpl(ienv, course.getCourseEnvironment(), null, null, null, null, reSecurity.isCourseCoach() || reSecurity.isGroupCoach(), reSecurity.isEntryAdmin(), reSecurity.isCourseParticipant() || reSecurity.isGroupParticipant(), false); @@ -422,6 +424,8 @@ public class FeedMediaDispatcher implements Dispatcher, GenericEventListener { .getNodeById(pathNodeId); if (treeNode != null && treeNode.isAccessible()) { hasAccess = true; + } else { + log.info("Course element not found or access denied. Path::{}", path); } } } diff --git a/src/main/java/org/olat/modules/webFeed/manager/FeedManagerImpl.java b/src/main/java/org/olat/modules/webFeed/manager/FeedManagerImpl.java index 4df75d6162c9d19633067669af88a895b4797f02..8f70ca9aa10442da7dce75fb53b05d4bcf1c488b 100644 --- a/src/main/java/org/olat/modules/webFeed/manager/FeedManagerImpl.java +++ b/src/main/java/org/olat/modules/webFeed/manager/FeedManagerImpl.java @@ -64,6 +64,7 @@ import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; import org.olat.core.util.vfs.VFSLeaf; import org.olat.core.util.vfs.VFSMediaResource; +import org.olat.core.util.vfs.filters.VFSSystemItemFilter; import org.olat.fileresource.FileResourceManager; import org.olat.fileresource.types.BlogFileResource; import org.olat.fileresource.types.FeedFileResource; @@ -832,7 +833,7 @@ public class FeedManagerImpl extends FeedManager { if (oldArchive != null) { oldArchive.delete(); } - ZipUtil.zip(feedContainer.getItems(), rootContainer.createChildLeaf(zipFileName), false); + ZipUtil.zip(feedContainer.getItems(), rootContainer.createChildLeaf(zipFileName), new VFSSystemItemFilter(), false); return (VFSLeaf) rootContainer.resolve(zipFileName); }); diff --git a/src/main/java/org/olat/modules/wiki/WikiToCPResource.java b/src/main/java/org/olat/modules/wiki/WikiToCPResource.java index 7e3d92e6eeeea858460fee61e4a1aadf196cf1be..5614cd6ce86fb3f71f50b3dabe61744ea8862d77 100644 --- a/src/main/java/org/olat/modules/wiki/WikiToCPResource.java +++ b/src/main/java/org/olat/modules/wiki/WikiToCPResource.java @@ -21,6 +21,7 @@ package org.olat.modules.wiki; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -39,6 +40,7 @@ import org.olat.core.util.StringHelper; import org.olat.core.util.ZipUtil; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; +import org.olat.core.util.vfs.filters.VFSAllItemsFilter; import org.olat.modules.cp.CPOfflineReadableManager; /** @@ -127,19 +129,19 @@ public class WikiToCPResource implements MediaResource { // create the ims manifest String manifest = export.createIMSManifest(wiki, identity); zout.putNextEntry(new ZipEntry("imsmanifest.xml")); - IOUtils.write(manifest, zout, "UTF-8"); + IOUtils.write(manifest, zout, StandardCharsets.UTF_8); zout.closeEntry(); VFSContainer mediaContainer = WikiManager.getInstance().getMediaFolder(ores); List<VFSItem> images = mediaContainer.getItems(); for (VFSItem image:images) { - ZipUtil.addToZip(image, "", zout); + ZipUtil.addToZip(image, "", zout, VFSAllItemsFilter.ACCEPT_ALL, false); } // create the javascript mapping file String jsContent = export.createJsMappingContent(wiki); zout.putNextEntry(new ZipEntry("mapping.js")); - IOUtils.write(jsContent, zout, "UTF-8"); + IOUtils.write(jsContent, zout, StandardCharsets.UTF_8); zout.closeEntry(); @@ -147,7 +149,7 @@ public class WikiToCPResource implements MediaResource { for (WikiPage page: pages) { String htmlPage = export.wikiPageToHtml(page); zout.putNextEntry(new ZipEntry(page.getPageId() + ".html")); - IOUtils.write(htmlPage, zout, "UTF-8"); + IOUtils.write(htmlPage, zout, StandardCharsets.UTF_8); zout.closeEntry(); } diff --git a/src/main/java/org/olat/modules/wiki/WikiToZipUtils.java b/src/main/java/org/olat/modules/wiki/WikiToZipUtils.java index d451ed34cb16969b09b19d79be8837c58b59d8af..8e2ef3063bf86602e0d152673916c611893dd64f 100644 --- a/src/main/java/org/olat/modules/wiki/WikiToZipUtils.java +++ b/src/main/java/org/olat/modules/wiki/WikiToZipUtils.java @@ -42,6 +42,7 @@ import org.olat.core.util.ZipUtil; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; import org.olat.core.util.vfs.VFSLeaf; +import org.olat.core.util.vfs.filters.VFSAllItemsFilter; import org.olat.core.util.vfs.filters.VFSSystemItemFilter; /** @@ -116,7 +117,7 @@ public class WikiToZipUtils { } VFSLeaf zipFile = (VFSLeaf)rootContainer.resolve("wiki.zip"); if(rootContainer.resolve("wiki.zip") != null) zipFile.delete(); - ZipUtil.zip(filesTozip, rootContainer.createChildLeaf("wiki.zip"), true); + ZipUtil.zip(filesTozip, rootContainer.createChildLeaf("wiki.zip"), VFSAllItemsFilter.ACCEPT_ALL, false); return (VFSLeaf)rootContainer.resolve("wiki.zip"); } @@ -135,7 +136,7 @@ public class WikiToZipUtils { exportStream.closeEntry(); } for(VFSItem wikiItem:items) { - ZipUtil.addToZip(wikiItem, currentPath, exportStream); + ZipUtil.addToZip(wikiItem, currentPath, exportStream, VFSAllItemsFilter.ACCEPT_ALL, false); } } } diff --git a/src/main/java/org/olat/user/UserLifecycleManager.java b/src/main/java/org/olat/user/UserLifecycleManager.java index 690c52ed6dad00b6df407151e1b85317c049eeeb..e498a15eb70266660929903cbfed502285269b6b 100644 --- a/src/main/java/org/olat/user/UserLifecycleManager.java +++ b/src/main/java/org/olat/user/UserLifecycleManager.java @@ -19,9 +19,11 @@ */ package org.olat.user; +import java.util.Date; import java.util.Set; import org.olat.core.id.Identity; +import org.olat.core.id.IdentityLifecycle; /** * @@ -32,7 +34,9 @@ import org.olat.core.id.Identity; public interface UserLifecycleManager { - + public long getDaysUntilDeactivation(IdentityLifecycle identity, Date referenceDate); + + public long getDaysUntilDeletion(IdentityLifecycle identity, Date referenceDate); /** * Check if there are identities to deactivate. diff --git a/src/main/java/org/olat/user/UserModule.java b/src/main/java/org/olat/user/UserModule.java index a091d0f12c6ac1d8045fe067ee415d32a3d320ae..7047134033d116172626767c5ace5cb467fcbfd9 100644 --- a/src/main/java/org/olat/user/UserModule.java +++ b/src/main/java/org/olat/user/UserModule.java @@ -128,6 +128,8 @@ public class UserModule extends AbstractSpringModule { private boolean mailAfterDeactivation; @Value("${user.days.before.mail.automatic.deactivation:30}") private int numberOfDayBeforeDeactivationMail; + @Value("${user.days.reactivation.period:30}") + private int numberOfDayReactivationPeriod; @Value("${user.automatic.deletion:false}") private boolean userAutomaticDeletion; @@ -479,6 +481,14 @@ public class UserModule extends AbstractSpringModule { setIntProperty(USER_NUM_OF_DAYS_BEFORE_MAIL_AUTOMATIC_DEACTIVATION, days, true); } + public int getNumberOfDayReactivationPeriod() { + return numberOfDayReactivationPeriod; + } + + public void setNumberOfDayReactivationPeriod(int numberOfDayReactivationPeriod) { + this.numberOfDayReactivationPeriod = numberOfDayReactivationPeriod; + } + public boolean isUserAutomaticDeletion() { return userAutomaticDeletion; } diff --git a/src/main/java/org/olat/user/manager/UserDataExportServiceImpl.java b/src/main/java/org/olat/user/manager/UserDataExportServiceImpl.java index ed56d25f2f9d854d50b05d26f366d5d4b8c28df0..6af91f93bd8092b9f2d37d206c3c561a6a1c0aed 100644 --- a/src/main/java/org/olat/user/manager/UserDataExportServiceImpl.java +++ b/src/main/java/org/olat/user/manager/UserDataExportServiceImpl.java @@ -184,7 +184,7 @@ public class UserDataExportServiceImpl implements UserDataExportService { // make zip File[] files = archiveDirectory.listFiles(SystemFileFilter.DIRECTORY_FILES); Set<String> filenames = Arrays.stream(files).map(File::getName).collect(Collectors.toSet()); - ZipUtil.zip(filenames, archiveDirectory, archive); + ZipUtil.zip(filenames, archiveDirectory, archive, false); // delete the temporary files for(File file:files) { FileUtils.deleteDirsAndFiles(file, true, true); diff --git a/src/main/java/org/olat/user/manager/lifecycle/UserLifecycleManagerImpl.java b/src/main/java/org/olat/user/manager/lifecycle/UserLifecycleManagerImpl.java index a980694995ca9d34c35cf86d43e6187de61ce8b0..3a31677b883f02cac2764d1d7ff72624b7722101 100644 --- a/src/main/java/org/olat/user/manager/lifecycle/UserLifecycleManagerImpl.java +++ b/src/main/java/org/olat/user/manager/lifecycle/UserLifecycleManagerImpl.java @@ -45,6 +45,7 @@ import org.olat.core.CoreSpringFactory; import org.olat.core.commons.persistence.DB; import org.olat.core.gui.translator.Translator; import org.olat.core.id.Identity; +import org.olat.core.id.IdentityLifecycle; import org.olat.core.id.User; import org.olat.core.id.UserConstants; import org.olat.core.logging.Tracing; @@ -95,7 +96,31 @@ public class UserLifecycleManagerImpl implements UserLifecycleManager { @Autowired private RepositoryDeletionModule repositoryDeletionModule; + @Override + public long getDaysUntilDeactivation(IdentityLifecycle identity, Date referenceDate) { + long days; + Date reactivationDate = identity.getReactivationDate(); + if(reactivationDate != null ) { + days = userModule.getNumberOfDayReactivationPeriod() - CalendarUtils.numOfDays(referenceDate, reactivationDate); + } else { + Date lastLogin = identity.getLastLogin(); + if(lastLogin == null) { + lastLogin = identity.getCreationDate(); + } + days = userModule.getNumberOfInactiveDayBeforeDeactivation() - CalendarUtils.numOfDays(referenceDate, lastLogin); + } + return days > 0l ? days : 1l; + } + @Override + public long getDaysUntilDeletion(IdentityLifecycle identity, Date referenceDate) { + if(identity == null || identity.getInactivationDate() == null) return -1; + + Date inactivationDate = identity.getInactivationDate(); + long days = userModule.getNumberOfInactiveDayBeforeDeletion() - CalendarUtils.numOfDays(referenceDate, inactivationDate); + return days > 0l ? days : 1l; + } + public List<Identity> getReadyToInactivateIdentities(Date loginDate, Date reactivationDateLimit) { StringBuilder sb = new StringBuilder(512); sb.append("select ident from ").append(IdentityImpl.class.getName()).append(" as ident") @@ -185,7 +210,8 @@ public class UserLifecycleManagerImpl implements UserLifecycleManager { public void inactivateIdentities(Set<Identity> vetoed) { int numOfDaysBeforeDeactivation = userModule.getNumberOfInactiveDayBeforeDeactivation(); int numOfDaysBeforeEmail = userModule.getNumberOfDayBeforeDeactivationMail(); - Date reactivationDatebefore = getDate(30); + int numOfDaysReactivation = userModule.getNumberOfDayReactivationPeriod(); + Date reactivationDatebefore = getDate(numOfDaysReactivation); boolean sendMailBeforeDeactivation = userModule.isMailBeforeDeactivation() && numOfDaysBeforeEmail > 0; if(sendMailBeforeDeactivation) { int days = numOfDaysBeforeDeactivation - numOfDaysBeforeEmail; diff --git a/src/main/java/org/olat/user/ui/admin/UserSearchTableController.java b/src/main/java/org/olat/user/ui/admin/UserSearchTableController.java index cc5d0c143ad03fc0d7eb7e325f2254723684bbd2..c79a83f3c6ac79c7cc9bd0228549aebc3315ddfd 100644 --- a/src/main/java/org/olat/user/ui/admin/UserSearchTableController.java +++ b/src/main/java/org/olat/user/ui/admin/UserSearchTableController.java @@ -50,6 +50,7 @@ import org.olat.core.gui.components.form.flexible.elements.FlexiTableFilter; import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; +import org.olat.core.gui.components.form.flexible.impl.elements.table.DateFlexiCellRenderer; import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColumnModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; @@ -83,6 +84,7 @@ import org.olat.core.util.mail.ContactList; import org.olat.core.util.mail.ContactMessage; import org.olat.core.util.resource.OresHelper; import org.olat.modules.co.ContactFormController; +import org.olat.user.UserLifecycleManager; import org.olat.user.UserManager; import org.olat.user.UserModule; import org.olat.user.propertyhandlers.UserPropertyHandler; @@ -146,6 +148,8 @@ public class UserSearchTableController extends FormBasicController implements Ac @Autowired private OrganisationService organisationService; @Autowired + private UserLifecycleManager userLifecycleManager; + @Autowired private UserBulkChangeManager userBulkChangesManager; public UserSearchTableController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel, @@ -172,13 +176,12 @@ public class UserSearchTableController extends FormBasicController implements Ac previousLink.setTitle(translate("command.previous")); nextLink = LinkFactory.createToolLink("nextelement","", this, "o_icon_next_toolbar"); nextLink.setTitle(translate("command.next")); - - + FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(UserCols.status, new IdentityStatusCellRenderer(getTranslator()))); if(isAdministrativeUser) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, UserCols.id)); } - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(UserCols.status, new IdentityStatusCellRenderer(getTranslator()))); int colPos = USER_PROPS_OFFSET; for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) { @@ -191,20 +194,20 @@ public class UserSearchTableController extends FormBasicController implements Ac colPos++; } columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(UserCols.creationDate)); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, UserCols.lastLogin)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(settings.isLifecycleColumnsDefault(), UserCols.lastLogin)); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, UserCols.inactivationDate)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(settings.isLifecycleColumnsDefault(), UserCols.inactivationDate, new DateFlexiCellRenderer(getLocale()))); if(userModule.isUserAutomaticDeactivation()) { - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, UserCols.daysToInactivation)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(settings.isLifecycleColumnsDefault(), UserCols.daysToInactivation)); } if(userModule.isUserAutomaticDeletion()) { - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, UserCols.daysToDeletion)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(settings.isLifecycleColumnsDefault(), UserCols.daysToDeletion)); } if(settings.isVCard()) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.vcard", translate("table.identity.vcard"), "vcard")); } - tableModel = new UserSearchTableModel(new EmptyDataSource(), columnsModel, userModule); + tableModel = new UserSearchTableModel(new EmptyDataSource(), columnsModel, userModule, userLifecycleManager); tableEl = uifactory.addTableElement(getWindowControl(), "table", tableModel, 25, false, getTranslator(), formLayout); tableEl.setCustomizeColumns(true); tableEl.setEmtpyTableMessageKey("error.no.user.found"); diff --git a/src/main/java/org/olat/user/ui/admin/UserSearchTableModel.java b/src/main/java/org/olat/user/ui/admin/UserSearchTableModel.java index a4a5cc2adc9b0133a3987022fae64bf42b644224..2bea35d5d0916921d8c158cb4ce8a8074edb8af5 100644 --- a/src/main/java/org/olat/user/ui/admin/UserSearchTableModel.java +++ b/src/main/java/org/olat/user/ui/admin/UserSearchTableModel.java @@ -29,6 +29,7 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataSourceDelegate; import org.olat.core.id.Identity; import org.olat.modules.lecture.ui.TeacherRollCallController; +import org.olat.user.UserLifecycleManager; import org.olat.user.UserModule; /** @@ -41,11 +42,13 @@ public class UserSearchTableModel extends DefaultFlexiTableDataSourceModel<Ident private final Date now; private final UserModule userModule; + private final UserLifecycleManager lifecycleManager; public UserSearchTableModel(FlexiTableDataSourceDelegate<IdentityPropertiesRow> source, - FlexiTableColumnModel columnModel, UserModule userModule) { + FlexiTableColumnModel columnModel, UserModule userModule, UserLifecycleManager lifecycleManager) { super(source, columnModel); this.userModule = userModule; + this.lifecycleManager = lifecycleManager; now = CalendarUtils.startOfDay(new Date()); } @@ -75,28 +78,21 @@ public class UserSearchTableModel extends DefaultFlexiTableDataSourceModel<Ident && (userRow.getStatus().equals(Identity.STATUS_ACTIV) || userRow.getStatus().equals(Identity.STATUS_PENDING) || userRow.getStatus().equals(Identity.STATUS_LOGIN_DENIED))) { - Date lastLogin = userRow.getLastLogin(); - if(lastLogin == null) { - lastLogin = userRow.getCreationDate(); - } - long days = userModule.getNumberOfInactiveDayBeforeDeactivation() - CalendarUtils.numOfDays(now, lastLogin); - return days > 0l ? days : 1l; + return lifecycleManager.getDaysUntilDeactivation(userRow, now); } return null; } private Long getDaysToDeletion(IdentityPropertiesRow userRow) { if(userModule.isUserAutomaticDeletion() && userRow.getInactivationDate() != null) { - Date inactivationDate = userRow.getInactivationDate(); - long days = userModule.getNumberOfInactiveDayBeforeDeletion() - CalendarUtils.numOfDays(now, inactivationDate); - return days > 0l ? days : 1l; + return lifecycleManager.getDaysUntilDeletion(userRow, now); } return null; } @Override public DefaultFlexiTableDataSourceModel<IdentityPropertiesRow> createCopyWithEmptyList() { - return new UserSearchTableModel(null, getTableColumnModel(), userModule); + return new UserSearchTableModel(null, getTableColumnModel(), userModule, lifecycleManager); } public enum UserCols implements FlexiSortableColumnDef { diff --git a/src/main/java/org/olat/user/ui/admin/UserSearchTableSettings.java b/src/main/java/org/olat/user/ui/admin/UserSearchTableSettings.java index 7d0833683ccc01f9e3e649943ef790fcd17decee..555d2f2ea3297857d8b2a968a14256016a153614 100644 --- a/src/main/java/org/olat/user/ui/admin/UserSearchTableSettings.java +++ b/src/main/java/org/olat/user/ui/admin/UserSearchTableSettings.java @@ -33,31 +33,37 @@ public class UserSearchTableSettings { private final boolean bulkOrganisationMove; private final boolean statusFilter; private final boolean tableSearch; + private final boolean lifecycleColumns; - private UserSearchTableSettings(boolean vCard, boolean bulkMail, boolean bulkOrganisationMove, boolean bulkDelete, boolean statusFilter, boolean tableSearch) { + private UserSearchTableSettings(boolean vCard, boolean lifecycleColumns, boolean bulkMail, boolean bulkOrganisationMove, boolean bulkDelete, boolean statusFilter, boolean tableSearch) { this.vCard = vCard; this.bulkMail = bulkMail; this.bulkDelete = bulkDelete; this.bulkOrganisationMove = bulkOrganisationMove; this.statusFilter = statusFilter; this.tableSearch = tableSearch; + this.lifecycleColumns = lifecycleColumns; } /** * @return The table seetings with only the search enabled */ public static UserSearchTableSettings minimal() { - return new UserSearchTableSettings(false, false, false, false, false, true); + return new UserSearchTableSettings(false, false, false, false, false, false, true); } public static UserSearchTableSettings withVCard(boolean bulkMail, boolean bulkOrganisationMove, boolean bulkDelete, boolean statusFilter, boolean tableSearch) { - return new UserSearchTableSettings(false, bulkMail, bulkOrganisationMove, bulkDelete, statusFilter, tableSearch); + return new UserSearchTableSettings(false, false, bulkMail, bulkOrganisationMove, bulkDelete, statusFilter, tableSearch); } public boolean isVCard() { return vCard; } + public boolean isLifecycleColumnsDefault() { + return lifecycleColumns; + } + public boolean isTableSearch() { return tableSearch; } diff --git a/src/main/java/org/olat/user/ui/admin/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/user/ui/admin/_i18n/LocalStrings_de.properties index 7f3a49c6227445b6a4cfd49a3e3e1d27a5b675e7..7d8bda2c7466dadbd7ea70f7bd67ee3fedfc2fde 100644 --- a/src/main/java/org/olat/user/ui/admin/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/user/ui/admin/_i18n/LocalStrings_de.properties @@ -137,4 +137,4 @@ table.identity.creationdate=Erstellt table.identity.days.deletion=Tage bis l\u00F6schen table.identity.days.inactivation=Tage bis inaktivieren table.identity.inactivation.date=Inaktivierungsdatum -table.identity.lastlogin=letzter Login +table.identity.lastlogin=Letzter Login diff --git a/src/test/java/org/olat/core/commons/services/vfs/manager/VFSVersioningTest.java b/src/test/java/org/olat/core/commons/services/vfs/manager/VFSVersioningTest.java index 79cd6d193f0ce6988d0e1d56183845db8a6d00b3..f3324dadee171d92873224f69c1123aaf6e1b695 100644 --- a/src/test/java/org/olat/core/commons/services/vfs/manager/VFSVersioningTest.java +++ b/src/test/java/org/olat/core/commons/services/vfs/manager/VFSVersioningTest.java @@ -171,6 +171,48 @@ public class VFSVersioningTest extends OlatTestCase { Assert.assertEquals(id2, revisions.get(2).getAuthor()); } + @Test + public void addVersionsDeleteRename() throws IOException { + versionsModule.setMaxNumberOfVersions(3); + waitForCondition(new SetMaxNumberOfVersions(versionsModule, 3l), 2000); + + Identity id2 = JunitTestHelper.createAndPersistIdentityAsRndUser("vers-2"); + + //create a file + VFSContainer rootTest = VFSManager.olatRootContainer("/test_" + UUID.randomUUID(), null); + String filename = "orig_" + UUID.randomUUID().toString() + ".txt"; + VFSLeaf file = rootTest.createChildLeaf(filename); + int byteCopied = copyTestTxt(file); + Assert.assertFalse(byteCopied == 0); + + //save a first version + for(int i=0; i<2; i++) { + InputStream inv = new ByteArrayInputStream(("Hello version " + i).getBytes()); + vfsRepositoryService.addVersion(file, id2, "Version " + (1 +i), inv); + inv.close(); + } + + VFSItem retrievedFile = rootTest.resolve(filename); + VFSMetadata metadata = vfsRepositoryService.getMetadataFor(retrievedFile); + List<VFSRevision> revisions = vfsRepositoryService.getRevisions(metadata); + Assert.assertNotNull(revisions); + Assert.assertEquals(2, revisions.size()); + + // delete the file + retrievedFile.delete(); + + // new file + String newFilename = "new_" + UUID.randomUUID().toString() + ".txt"; + VFSLeaf newFile = rootTest.createChildLeaf(newFilename); + int newByteCopied = copyTestTxt(newFile); + Assert.assertFalse(newByteCopied == 0); + + // rename new file to old name + newFile.rename(filename); + dbInstance.commit(); + + } + @Test public void addVersions_overflow_lowLevel_deactivated() throws IOException { versionsModule.setMaxNumberOfVersions(0); diff --git a/src/test/java/org/olat/selenium/page/LoginPage.java b/src/test/java/org/olat/selenium/page/LoginPage.java index 960059dbb66d78037de12a26123371cf9fcfe9e5..b600dd7859db266991490a84e79855dc55a51f6a 100644 --- a/src/test/java/org/olat/selenium/page/LoginPage.java +++ b/src/test/java/org/olat/selenium/page/LoginPage.java @@ -170,8 +170,6 @@ public class LoginPage { try { OOGraphene.waitElementDisappears(disclaimerXPath, 10, browser); } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); OOGraphene.takeScreenshot("Login disclaimer", browser); throw e; } diff --git a/src/test/java/org/olat/selenium/page/course/CourseEditorPageFragment.java b/src/test/java/org/olat/selenium/page/course/CourseEditorPageFragment.java index 73e66f0fba97a202a48e03feb5df3776d31f6d89..4098a610d10781293f92c7fb75a2a22b2d7784c7 100644 --- a/src/test/java/org/olat/selenium/page/course/CourseEditorPageFragment.java +++ b/src/test/java/org/olat/selenium/page/course/CourseEditorPageFragment.java @@ -403,31 +403,20 @@ public class CourseEditorPageFragment { OOGraphene.waitBusy(browser); //popup By referenceableEntriesBy = By.className("o_sel_search_referenceable_entries"); - OOGraphene.waitElement(referenceableEntriesBy, 1, browser); + OOGraphene.waitElement(referenceableEntriesBy, browser); WebElement popup = browser.findElement(referenceableEntriesBy); popup.findElement(By.cssSelector("a.o_sel_repo_popup_my_resources")).click(); OOGraphene.waitBusy(browser); //find the row - WebElement selectRow = null; - List<WebElement> rows = popup.findElements(By.cssSelector("div.o_segments_content table.o_table tr")); - for(WebElement row:rows) { - String text = row.getText(); - if(text.contains(resourceTitle)) { - selectRow = row; - break; - } - } - Assert.assertNotNull(selectRow); - - //find the select in the row - selectRow.findElement(By.xpath("//a[contains(@onclick,'rtbSelectLink')]")).click(); + By rowBy = By.xpath("//div[contains(@class,'')]//div[contains(@class,'o_segments_content')]//table[contains(@class,'o_table')]//tr/td/a[text()[contains(.,'" + resourceTitle + "')]]"); + OOGraphene.waitElement(rowBy, browser); + browser.findElement(rowBy).click(); OOGraphene.waitBusy(browser); //double check that the resource is selected (search the preview link) By previewLink = By.xpath("//a/span[text()[contains(.,'" + resourceTitle + "')]]"); - browser.findElement(previewLink); - + OOGraphene.waitElement(previewLink, browser); return this; } diff --git a/src/test/java/org/olat/selenium/page/qpool/QuestionMetadataPage.java b/src/test/java/org/olat/selenium/page/qpool/QuestionMetadataPage.java index 9ab8225d65c34cd11cea8f712222eda05e0c1b62..d4a5b034e98f31be1b0865eaef2b3823a706af6d 100644 --- a/src/test/java/org/olat/selenium/page/qpool/QuestionMetadataPage.java +++ b/src/test/java/org/olat/selenium/page/qpool/QuestionMetadataPage.java @@ -80,6 +80,7 @@ public class QuestionMetadataPage { if(taxonomy != null) { By taxonomyBy = By.cssSelector("div.o_sel_qpool_metadata_taxonomy select"); new Select(browser.findElement(taxonomyBy)).selectByVisibleText(taxonomy); + OOGraphene.waitBusy(browser); } if(level != null) { diff --git a/src/test/resources/arquillian.xml b/src/test/resources/arquillian.xml index f656a58437d8e95cd593cd1915c1e90663339a3b..ab4a692ae8e99e13cdcf23e1c7a04ca3eab14732 100644 --- a/src/test/resources/arquillian.xml +++ b/src/test/resources/arquillian.xml @@ -30,7 +30,7 @@ --> <property name="firefoxDriverVersion">${webdriver.firefox.version:v0.27.0}</property> <property name="firefoxUserPreferences">src/test/profile/firefox/prefs.js</property> - <property name="chromeDriverVersion">${webdriver.chrome.version:84.0.4147.30}</property> + <property name="chromeDriverVersion">${webdriver.chrome.version:85.0.4183.87}</property> <property name="chromeArguments">${webdriver.chrome.arguments}</property> <property name="chromeExperimentalOption">{ "prefs":{"credentials_enable_service": false, "profile.password_manager_enabled": false }