diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 000000000..38c09eaf3 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,154 @@ + +% Copilot instructions for the `oss` workspace + +Purpose +------- +This file describes the default, workspace-specific instructions that an automated coding assistant (Copilot) should follow when making suggestions or applying edits in this repository. Follow these guidelines whenever you open, modify, or create files in this workspace. + +Project overview +---------------- +- Multi-module Java/Gradle project located at the repository root. Main Gradle wrapper files: `gradlew`, `gradlew.bat`, `build.gradle`, `settings.gradle`. +- Submodules live under `modules/`. +- Themes live under `themes/`. These are frontend assets (a `package.json`). + +High-level goals for edits +------------------------- +1. Preserve build stability: avoid changes that break a full `./gradlew build` (on Windows: `gradlew.bat build`). +2. Make the minimal change necessary to implement a fix or feature. +3. Run and prefer project-provided build/test/format tooling before proposing changes as final. +4. When in doubt, add tests and keep public APIs backwards compatible. + +How to build locally (Windows) +------------------------------- +Use the Gradle wrapper to build the whole project from the repository root: + +``` +gradlew.bat build +``` + +To run tests for a single module (example): + +``` +cd modules/registration-service +..\..\gradlew.bat :modules:registration-service:test +``` + +If you need a clean build: + +``` +gradlew.bat clean build +``` + +Frontend (node) tasks +---------------------- +If you need to run Node/NPM tasks for the repo root frontend: + +``` +npm install +npm test +``` + +Adjust the working directory if you operate within a module with its own `package.json`. + +Docker / local Liferay environment +---------------------------------- +This repository includes a Docker-based Liferay development environment that can be started from the repository root. On Windows use the Gradle wrapper batch file; on Unix-like systems use the shell wrapper. + +Start Docker/Liferay (Windows - cmd.exe): + +``` +gradlew.bat startLiferay +``` + +Start Docker/Liferay (Unix/macOS): + +``` +./gradlew startLiferay +``` + +Notes: +- Wait for the containers to finish starting before deploying modules. You can check container status with `docker ps` and inspect logs with `docker-compose logs` if needed. +- Once Docker/Liferay is up you can deploy modules from the repository root using Gradle. On Windows: + +``` +gradlew.bat deploy +``` + +Or on Unix/macOS: + +``` +./gradlew deploy +``` + +You can also deploy a single module by running the module's deploy task, for example: + +``` +cd modules/registration-service +..\..\gradlew.bat :modules:registration-service:deploy +``` + +Adjust paths and task names as needed for specific modules. + +Formatting / linting +-------------------- +- Keep existing formatting conventions. If the repo has a formatting tool configured, prefer using that (e.g. `./gradlew fmt` if present) before changing formatting manually. +- Add or update lint fixes conservatively and run the associated checks locally. + +Testing requirements +-------------------- +- For any non-trivial code change, add or update automated tests (unit tests or integration tests) that demonstrate the fix/feature. +- Run `gradlew.bat test` (or module-specific tasks) and ensure tests pass locally before finalizing changes. + +Dependency management +--------------------- +- When adding/updating dependencies update only the smallest set of build files necessary. +- Run `gradlew.bat build` after dependency changes to verify nothing else broke. +- Prefer using existing BOMs and aligned versions used across modules when possible. + +Commit and PR guidelines +------------------------ +- Keep commits small and focused: one logical change per commit. +- Commit messages should have a short summary and a short body when necessary. Example: + + "Fix NPE in UserRegistrationService when email is null\n\n Add a null-check and a unit test that covers the edge case." + +- When proposing changes as a patch in this workspace, include the commands you ran to validate (build/test) and a brief summary of results. + +Files and directories to avoid / sensitive files +--------------------------------------------- +- Do not open or modify secrets or local credential files unless the user explicitly asks and permits it. Examples in this repository include but may not be limited to: + - `gradle-local-with-pw.properties` + - `gradle-local.properties` + - `example-gradle-local.properties` (read-only example ok) + - any `*.keystore`, `*.p12`, or other credential artifacts + +- Avoid leaking values from these files into diffs or suggestions. + +When making automated edits +-------------------------- +- Create minimal, well-scoped patches. Use the repository coding style and preserve formatting of surrounding code. +- Add missing imports and adjust related build files only when required. +- If a refactor touches many modules, prefer splitting into multiple PRs and run a full build after each stage. + +If tests or build fail after an edit +---------------------------------- +1. Re-run with `--stacktrace` and capture the failing task output. +2. Try to localize failure to a single module and create a failing unit test if one does not already exist. +3. Propose a fix with the minimal change and include the failing output and the verification steps in the patch description. + +Additional helpful repository hints +---------------------------------- +- The repository contains many frontend dependencies in `node_modules_cache/` (cached tarballs) — prefer using the provided `package.json` scripts rather than manual changes to `node_modules_cache`. + +Contact / follow-up +------------------- +If you want me to open or modify specific files, list them and I will: + - read their current contents, + - propose the precise minimal patch(s), and + - run / describe the verification steps I used (build/test commands and results). + +If you want stricter or different instructions (for example: prefer Kotlin DSL for Gradle, or use a specific Java style guide), update this file to reflect those preferences. + +-- End of copilot-instructions.md + + diff --git a/build.gradle b/build.gradle index ff9c12ec9..be0b31e0f 100755 --- a/build.gradle +++ b/build.gradle @@ -56,8 +56,13 @@ task startContainers( System.out.println('dockerComposeFilePath: ' + dockerComposeFilePath) System.out.println('bundleDir: ' + bundleDir) exec { - executable 'podman' - args('compose', '-p', dockerContainerPrefix, '-f', dockerComposeFilePath, 'up', '--build', '--force-recreate', '-d') +// Docker compose + executable 'docker-compose' + args('-p', dockerContainerPrefix, '-f', dockerComposeFilePath, 'up', '--build', '--force-recreate', '-d') + +// Podman +// executable 'podman' +// args('compose', '-p', dockerContainerPrefix, '-f', dockerComposeFilePath, 'up', '--build', '--force-recreate', '-d') environment('LIFERAY_BUNDLE_DIR', bundleDir) standardOutput = System.out errorOutput = System.err @@ -141,8 +146,13 @@ task stopLiferay( ) { doLast { exec { - executable 'podman' - args('compose', '-p', dockerContainerPrefix, '-f', dockerComposeFilePath, 'down', '--rmi', 'local') +// Docker Compose + executable 'docker-compose' + args('-p', dockerContainerPrefix, '-f', dockerComposeFilePath, 'down', '--rmi', 'local') + +// Podman +// executable 'podman' +// args('compose', '-p', dockerContainerPrefix, '-f', dockerComposeFilePath, 'down', '--rmi', 'local') standardOutput = System.out errorOutput = System.err } @@ -156,7 +166,7 @@ task dumpDB( ) { doLast { exec { - executable 'podman' + executable 'docker-compose' args('exec', '-t', "${dockerContainerPrefix}-mariadb-74", 'mysqldump', "-u${dbUser}", "-p${dbPassword}", '--extended-insert=FALSE', '--no-autocommit', '--opt', "${dbName}") standardOutput new FileOutputStream("${projectDir}/docker/resources/dump-${dbName}.sql") diff --git a/configs/artifacts-release.json b/configs/artifacts-release.json index 7bc120874..c979b1b0a 100644 --- a/configs/artifacts-release.json +++ b/configs/artifacts-release.json @@ -2,25 +2,25 @@ { "groupId" : "nl.deltares", "artifactId" : "nl.deltares.dsd.registration.api", - "version" : "1.1.0", + "version" : "1.1.1", "extension" : "jar" }, { "groupId" : "nl.deltares", "artifactId" : "nl.deltares.dsd.registration.service", - "version" : "1.1.0", + "version" : "1.1.1", "extension" : "jar" }, { "groupId" : "nl.deltares", "artifactId" : "nl.deltares.oss.download.api", - "version" : "1.1.2", + "version" : "1.1.3", "extension" : "jar" }, { "groupId" : "nl.deltares", "artifactId" : "nl.deltares.oss.download.service", - "version" : "1.1.2", + "version" : "1.1.3", "extension" : "jar" }, { @@ -38,7 +38,7 @@ { "groupId" : "nl.deltares", "artifactId" : "nl.deltares.portal.common-utils", - "version" : "1.1.41", + "version" : "1.1.43", "extension" : "jar" }, { @@ -50,7 +50,7 @@ { "groupId" : "nl.deltares", "artifactId" : "nl.worth.portal.context.contributor", - "version" : "1.1.3", + "version" : "1.1.4", "extension" : "jar" }, { @@ -93,7 +93,7 @@ { "groupId" : "nl.deltares", "artifactId" : "nl.deltares.tableview.portlet", - "version" : "1.1.7", + "version" : "1.1.11", "extension" : "jar" }, { @@ -117,7 +117,7 @@ { "groupId" : "nl.deltares", "artifactId" : "deltares-fews-theme", - "version" : "1.1.5", + "version" : "1.1.6", "extension" : "war" } ] \ No newline at end of file diff --git a/modules/common-utils/bnd.bnd b/modules/common-utils/bnd.bnd index 5bd3c31b9..0abe793fa 100644 --- a/modules/common-utils/bnd.bnd +++ b/modules/common-utils/bnd.bnd @@ -1,6 +1,6 @@ Bundle-Name: common-utils Bundle-SymbolicName: nl.deltares.portal.common-utils -Bundle-Version: 1.1.41 +Bundle-Version: 1.1.43 Export-Package: \ nl.deltares.portal.constants, \ nl.deltares.portal.utils, \ diff --git a/modules/common-utils/src/main/java/nl/deltares/portal/model/listeners/AccountEntryModelListener.java b/modules/common-utils/src/main/java/nl/deltares/portal/model/listeners/AccountEntryModelListener.java deleted file mode 100644 index fead96c82..000000000 --- a/modules/common-utils/src/main/java/nl/deltares/portal/model/listeners/AccountEntryModelListener.java +++ /dev/null @@ -1,21 +0,0 @@ -package nl.deltares.portal.model.listeners; - -import com.liferay.account.model.AccountEntry; -import com.liferay.portal.kernel.exception.ModelListenerException; -import com.liferay.portal.kernel.model.BaseModelListener; -import com.liferay.portal.kernel.model.ModelListener; -import org.osgi.service.component.annotations.Component; - -@Component(service = ModelListener.class) -public class AccountEntryModelListener extends BaseModelListener { - - @Override - public void onBeforeUpdate(AccountEntry originalModel, AccountEntry model) throws ModelListenerException { - - String domains = originalModel.getDomains(); - model.setDomains(domains); - - super.onBeforeUpdate(originalModel, model); - } - -} diff --git a/modules/common-utils/src/main/java/nl/deltares/portal/model/listeners/UserModelListener.java b/modules/common-utils/src/main/java/nl/deltares/portal/model/listeners/UserModelListener.java new file mode 100644 index 000000000..23802704f --- /dev/null +++ b/modules/common-utils/src/main/java/nl/deltares/portal/model/listeners/UserModelListener.java @@ -0,0 +1,51 @@ +package nl.deltares.portal.model.listeners; + +import com.liferay.portal.kernel.exception.ModelListenerException; +import com.liferay.portal.kernel.log.Log; +import com.liferay.portal.kernel.log.LogFactoryUtil; +import com.liferay.portal.kernel.model.BaseModelListener; +import com.liferay.portal.kernel.model.ModelListener; +import com.liferay.portal.kernel.model.User; +import nl.deltares.dsd.registration.service.RegistrationLocalService; +import nl.deltares.oss.download.service.DownloadLocalService; + +import nl.deltares.portal.utils.AccountUtils; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +@Component(service = ModelListener.class) +public class UserModelListener extends BaseModelListener { + + private static final Log LOGGER = LogFactoryUtil.getLog(UserModelListener.class); + + @Reference + private AccountUtils accountUtils; + + @Reference + RegistrationLocalService registrationLocalService; + + @Reference + DownloadLocalService downloadLocalService; + + @Override + public void onAfterRemove(User model) throws ModelListenerException { + try { + int count = registrationLocalService.deleteAllUserRegistrations(model.getUserId()); + if (count > 0) { + LOGGER.info(String.format("Deleting %d Registration references for user %d with email %s", count, model.getUserId(), model.getEmailAddress())); + } + + count = downloadLocalService.deleteAllUserDownloads(model.getUserId()); + if (count > 0) { + LOGGER.info(String.format("Deleting %d Download references for user %d with email %s", count, model.getUserId(), model.getEmailAddress())); + } + + count = accountUtils.deleteUserPersonalAccount(model.getScreenName()); + if (count > 0) { + LOGGER.info(String.format("Deleting personal account for user %d with email %s", model.getUserId(), model.getEmailAddress())); + } + } finally { + super.onAfterRemove(model); + } + } +} diff --git a/modules/common-utils/src/main/java/nl/deltares/portal/utils/AccountUtils.java b/modules/common-utils/src/main/java/nl/deltares/portal/utils/AccountUtils.java index 21175b684..b4efe4a50 100644 --- a/modules/common-utils/src/main/java/nl/deltares/portal/utils/AccountUtils.java +++ b/modules/common-utils/src/main/java/nl/deltares/portal/utils/AccountUtils.java @@ -38,4 +38,6 @@ static String[] getSplitDomains(String domains) { return new String[]{domains}; } } + + int deleteUserPersonalAccount(String screenName); } diff --git a/modules/common-utils/src/main/java/nl/deltares/portal/utils/impl/AccountUtilsImpl.java b/modules/common-utils/src/main/java/nl/deltares/portal/utils/impl/AccountUtilsImpl.java index ce14026bb..65364ffa5 100644 --- a/modules/common-utils/src/main/java/nl/deltares/portal/utils/impl/AccountUtilsImpl.java +++ b/modules/common-utils/src/main/java/nl/deltares/portal/utils/impl/AccountUtilsImpl.java @@ -13,7 +13,10 @@ import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.model.*; +import com.liferay.portal.kernel.module.configuration.ConfigurationException; +import com.liferay.portal.kernel.module.configuration.ConfigurationProvider; import com.liferay.portal.kernel.service.*; +import nl.deltares.portal.configuration.SiteMapConfiguration; import nl.deltares.portal.model.AccountInfo; import nl.deltares.portal.model.AddressInfo; import nl.deltares.portal.utils.AccountUtils; @@ -229,6 +232,28 @@ public Address createOrUpdateAddress(AddressInfo addressInfo, long companyId, lo return address; } + @Override + public int deleteUserPersonalAccount(String screenName) { + + String externalReferenceCode = PERSONAL_ACCOUNT_PREFIX + screenName; + long companyId = 101331; + try { + SiteMapConfiguration _configuration = _configurationProvider.getSystemConfiguration(SiteMapConfiguration.class); + companyId = _configuration.accountsCompanyId(); + } catch (ConfigurationException e) { + // + } + AccountEntry accountEntry = _accountEntryLocalService.fetchAccountEntryByExternalReferenceCode(externalReferenceCode, companyId); + if (accountEntry == null) return 0; + + try { + _accountEntryLocalService.deleteAccountEntry(accountEntry.getAccountEntryId()); + } catch (PortalException e) { + return 0; + } + return 1; + } + @Reference private AccountEntryLocalService _accountEntryLocalService; @@ -249,5 +274,8 @@ public Address createOrUpdateAddress(AddressInfo addressInfo, long companyId, lo @Reference private UserLocalService _userLocalService; + + @Reference + private ConfigurationProvider _configurationProvider; } diff --git a/modules/context-contributors/bnd.bnd b/modules/context-contributors/bnd.bnd index e81288137..93a387f0c 100644 --- a/modules/context-contributors/bnd.bnd +++ b/modules/context-contributors/bnd.bnd @@ -1,4 +1,4 @@ Bundle-Name: context-contributors Bundle-SymbolicName: nl.worth.portal.context.contributor -Bundle-Version: 1.1.3 +Bundle-Version: 1.1.4 -noee: true diff --git a/modules/context-contributors/src/main/java/nl/worth/portal/context/contributor/UtilsTemplateContextContributor.java b/modules/context-contributors/src/main/java/nl/worth/portal/context/contributor/UtilsTemplateContextContributor.java index 912dffe1e..9c7a6a189 100644 --- a/modules/context-contributors/src/main/java/nl/worth/portal/context/contributor/UtilsTemplateContextContributor.java +++ b/modules/context-contributors/src/main/java/nl/worth/portal/context/contributor/UtilsTemplateContextContributor.java @@ -72,7 +72,6 @@ public void prepare(Map contextObjects, HttpServletRequest reque } contextObjects.put("is_site_admin", isAdmin); contextObjects.put("user_signout_url", themeDisplay.getURLSignOut()); - contextObjects.put("user_mailing_url", "/subscriptions"); contextObjects.put("user_account_url", "/account"); contextObjects.put("user_announcements_url", "/announcements"); diff --git a/modules/download/download-api/bnd.bnd b/modules/download/download-api/bnd.bnd index e0dbb820b..454f3209d 100644 --- a/modules/download/download-api/bnd.bnd +++ b/modules/download/download-api/bnd.bnd @@ -1,6 +1,6 @@ Bundle-Name: download-api Bundle-SymbolicName: nl.deltares.oss.download.api -Bundle-Version: 1.1.2 +Bundle-Version: 1.1.3 Export-Package:\ nl.deltares.oss.download.exception,\ nl.deltares.oss.download.model,\ diff --git a/modules/download/download-api/src/main/java/nl/deltares/oss/download/service/DownloadLocalService.java b/modules/download/download-api/src/main/java/nl/deltares/oss/download/service/DownloadLocalService.java index 06b14c5d9..4d666d1c0 100644 --- a/modules/download/download-api/src/main/java/nl/deltares/oss/download/service/DownloadLocalService.java +++ b/modules/download/download-api/src/main/java/nl/deltares/oss/download/service/DownloadLocalService.java @@ -90,6 +90,8 @@ public interface DownloadLocalService public PersistedModel createPersistedModel(Serializable primaryKeyObj) throws PortalException; + public int deleteAllUserDownloads(long userId); + /** * Deletes the download from the database. Also notifies the appropriate model listeners. * diff --git a/modules/download/download-api/src/main/java/nl/deltares/oss/download/service/DownloadLocalServiceUtil.java b/modules/download/download-api/src/main/java/nl/deltares/oss/download/service/DownloadLocalServiceUtil.java index d9ad1775c..5b35718e6 100644 --- a/modules/download/download-api/src/main/java/nl/deltares/oss/download/service/DownloadLocalServiceUtil.java +++ b/modules/download/download-api/src/main/java/nl/deltares/oss/download/service/DownloadLocalServiceUtil.java @@ -87,6 +87,10 @@ public static PersistedModel createPersistedModel( return getService().createPersistedModel(primaryKeyObj); } + public static int deleteAllUserDownloads(long userId) { + return getService().deleteAllUserDownloads(userId); + } + /** * Deletes the download from the database. Also notifies the appropriate model listeners. * diff --git a/modules/download/download-api/src/main/java/nl/deltares/oss/download/service/DownloadLocalServiceWrapper.java b/modules/download/download-api/src/main/java/nl/deltares/oss/download/service/DownloadLocalServiceWrapper.java index 70cc42beb..51ef82ac5 100644 --- a/modules/download/download-api/src/main/java/nl/deltares/oss/download/service/DownloadLocalServiceWrapper.java +++ b/modules/download/download-api/src/main/java/nl/deltares/oss/download/service/DownloadLocalServiceWrapper.java @@ -89,6 +89,11 @@ public com.liferay.portal.kernel.model.PersistedModel createPersistedModel( return _downloadLocalService.createPersistedModel(primaryKeyObj); } + @Override + public int deleteAllUserDownloads(long userId) { + return _downloadLocalService.deleteAllUserDownloads(userId); + } + /** * Deletes the download from the database. Also notifies the appropriate model listeners. * diff --git a/modules/download/download-service/bnd.bnd b/modules/download/download-service/bnd.bnd index bbc7578db..404ba635f 100644 --- a/modules/download/download-service/bnd.bnd +++ b/modules/download/download-service/bnd.bnd @@ -1,6 +1,6 @@ Bundle-Name: download-service Bundle-SymbolicName: nl.deltares.oss.download.service -Bundle-Version: 1.1.2 +Bundle-Version: 1.1.3 Liferay-Require-SchemaVersion: 1.3.0 Liferay-Service: true -dsannotations-options: inherit \ No newline at end of file diff --git a/modules/download/download-service/src/main/java/nl/deltares/oss/download/service/impl/DownloadLocalServiceImpl.java b/modules/download/download-service/src/main/java/nl/deltares/oss/download/service/impl/DownloadLocalServiceImpl.java index 0ed4ed37a..992164077 100644 --- a/modules/download/download-service/src/main/java/nl/deltares/oss/download/service/impl/DownloadLocalServiceImpl.java +++ b/modules/download/download-service/src/main/java/nl/deltares/oss/download/service/impl/DownloadLocalServiceImpl.java @@ -158,5 +158,14 @@ private DynamicQuery getGeoLocationQuery(long locationId) { return dynamicQuery; } + public int deleteAllUserDownloads(long userId){ + DynamicQuery dynamicQuery = dynamicQuery(); + dynamicQuery.add(RestrictionsFactoryUtil.eq("userId", userId)); + List withDynamicQuery = DownloadUtil.findWithDynamicQuery(dynamicQuery); + for (Download download : withDynamicQuery) { + DownloadUtil.removeByDownloads(download.getGroupId(), download.getDownloadId()); + } + return withDynamicQuery.size(); + } -} \ No newline at end of file + } \ No newline at end of file diff --git a/modules/download/download-service/src/main/resources/service.properties b/modules/download/download-service/src/main/resources/service.properties index 7a4c6d148..06465cfd5 100644 --- a/modules/download/download-service/src/main/resources/service.properties +++ b/modules/download/download-service/src/main/resources/service.properties @@ -13,5 +13,5 @@ ## build.namespace=nl.deltares.oss.download.service - build.number=74 - build.date=1775224821174 \ No newline at end of file + build.number=78 + build.date=1787741990331 \ No newline at end of file diff --git a/modules/registration-service/registration-service-api/bnd.bnd b/modules/registration-service/registration-service-api/bnd.bnd index e30f2c75a..ba44deb15 100644 --- a/modules/registration-service/registration-service-api/bnd.bnd +++ b/modules/registration-service/registration-service-api/bnd.bnd @@ -1,6 +1,6 @@ Bundle-Name: registration-service-api Bundle-SymbolicName: nl.deltares.dsd.registration.api -Bundle-Version: 1.1.0 +Bundle-Version: 1.1.1 Export-Package:\ nl.deltares.dsd.registration.exception, \ nl.deltares.dsd.registration.model, \ diff --git a/modules/registration-service/registration-service-api/src/main/java/nl/deltares/dsd/registration/service/RegistrationLocalService.java b/modules/registration-service/registration-service-api/src/main/java/nl/deltares/dsd/registration/service/RegistrationLocalService.java index 7c23ee294..b93c27fce 100644 --- a/modules/registration-service/registration-service-api/src/main/java/nl/deltares/dsd/registration/service/RegistrationLocalService.java +++ b/modules/registration-service/registration-service-api/src/main/java/nl/deltares/dsd/registration/service/RegistrationLocalService.java @@ -104,6 +104,16 @@ public PersistedModel createPersistedModel(Serializable primaryKeyObj) */ public void deleteAllEventRegistrations(long groupId, long eventResourceId); + /** + * Delete all registrations related to 'resourceId'. This includes all registration with a parentArticleId + * that matches 'resourceId'. + * + * @param groupId Site Identifier + * @param registrationResourceId Article Identifier of Event being removed. + */ + public void deleteAllRegistrations( + long groupId, long registrationResourceId); + /** * Delete all registrations related to 'resourceId'. This includes all registration with a parentArticleId * that matches 'resourceId'. @@ -125,6 +135,14 @@ public void deleteAllRegistrationsAndChildRegistrations( public void deleteAllUserEventRegistrations( long groupId, long userId, long eventResourceId); + /** + * Delete all registrations related to 'resourceId'. This includes all registration with a parentArticleId + * that matches 'resourceId'. + * + * @param userId Article Identifier of Event being removed. + */ + public int deleteAllUserRegistrations(long userId); + /** * @throws PortalException */ @@ -270,6 +288,13 @@ public List getArticleRegistrations( public List getArticleRegistrations( long groupId, long articleResourceId, int start, int end); + @Transactional(propagation = Propagation.SUPPORTS, readOnly = true) + public List getDistinctEventResourceIds(long companyId, long groupId); + + @Transactional(propagation = Propagation.SUPPORTS, readOnly = true) + public List getDistinctRegistrationResourceIds( + long companyId, long groupId, long eventResourceId, long userId); + @Transactional(propagation = Propagation.SUPPORTS, readOnly = true) public List getEventRegistrations( long groupId, long eventResourceId); diff --git a/modules/registration-service/registration-service-api/src/main/java/nl/deltares/dsd/registration/service/RegistrationLocalServiceUtil.java b/modules/registration-service/registration-service-api/src/main/java/nl/deltares/dsd/registration/service/RegistrationLocalServiceUtil.java index f1ee45d69..6f8de0fa1 100644 --- a/modules/registration-service/registration-service-api/src/main/java/nl/deltares/dsd/registration/service/RegistrationLocalServiceUtil.java +++ b/modules/registration-service/registration-service-api/src/main/java/nl/deltares/dsd/registration/service/RegistrationLocalServiceUtil.java @@ -104,6 +104,19 @@ public static void deleteAllEventRegistrations( getService().deleteAllEventRegistrations(groupId, eventResourceId); } + /** + * Delete all registrations related to 'resourceId'. This includes all registration with a parentArticleId + * that matches 'resourceId'. + * + * @param groupId Site Identifier + * @param registrationResourceId Article Identifier of Event being removed. + */ + public static void deleteAllRegistrations( + long groupId, long registrationResourceId) { + + getService().deleteAllRegistrations(groupId, registrationResourceId); + } + /** * Delete all registrations related to 'resourceId'. This includes all registration with a parentArticleId * that matches 'resourceId'. @@ -133,6 +146,16 @@ public static void deleteAllUserEventRegistrations( groupId, userId, eventResourceId); } + /** + * Delete all registrations related to 'resourceId'. This includes all registration with a parentArticleId + * that matches 'resourceId'. + * + * @param userId Article Identifier of Event being removed. + */ + public static int deleteAllUserRegistrations(long userId) { + return getService().deleteAllUserRegistrations(userId); + } + /** * @throws PortalException */ @@ -316,6 +339,19 @@ public static List getArticleRegistrations( groupId, articleResourceId, start, end); } + public static List getDistinctEventResourceIds( + long companyId, long groupId) { + + return getService().getDistinctEventResourceIds(companyId, groupId); + } + + public static List getDistinctRegistrationResourceIds( + long companyId, long groupId, long eventResourceId, long userId) { + + return getService().getDistinctRegistrationResourceIds( + companyId, groupId, eventResourceId, userId); + } + public static List getEventRegistrations( long groupId, long eventResourceId) { diff --git a/modules/registration-service/registration-service-api/src/main/java/nl/deltares/dsd/registration/service/RegistrationLocalServiceWrapper.java b/modules/registration-service/registration-service-api/src/main/java/nl/deltares/dsd/registration/service/RegistrationLocalServiceWrapper.java index 101b24b42..4900c37b5 100644 --- a/modules/registration-service/registration-service-api/src/main/java/nl/deltares/dsd/registration/service/RegistrationLocalServiceWrapper.java +++ b/modules/registration-service/registration-service-api/src/main/java/nl/deltares/dsd/registration/service/RegistrationLocalServiceWrapper.java @@ -107,6 +107,21 @@ public void deleteAllEventRegistrations( groupId, eventResourceId); } + /** + * Delete all registrations related to 'resourceId'. This includes all registration with a parentArticleId + * that matches 'resourceId'. + * + * @param groupId Site Identifier + * @param registrationResourceId Article Identifier of Event being removed. + */ + @Override + public void deleteAllRegistrations( + long groupId, long registrationResourceId) { + + _registrationLocalService.deleteAllRegistrations( + groupId, registrationResourceId); + } + /** * Delete all registrations related to 'resourceId'. This includes all registration with a parentArticleId * that matches 'resourceId'. @@ -138,6 +153,17 @@ public void deleteAllUserEventRegistrations( groupId, userId, eventResourceId); } + /** + * Delete all registrations related to 'resourceId'. This includes all registration with a parentArticleId + * that matches 'resourceId'. + * + * @param userId Article Identifier of Event being removed. + */ + @Override + public int deleteAllUserRegistrations(long userId) { + return _registrationLocalService.deleteAllUserRegistrations(userId); + } + /** * @throws PortalException */ @@ -354,6 +380,22 @@ public nl.deltares.dsd.registration.model.Registration fetchRegistration( groupId, articleResourceId, start, end); } + @Override + public java.util.List getDistinctEventResourceIds( + long companyId, long groupId) { + + return _registrationLocalService.getDistinctEventResourceIds( + companyId, groupId); + } + + @Override + public java.util.List getDistinctRegistrationResourceIds( + long companyId, long groupId, long eventResourceId, long userId) { + + return _registrationLocalService.getDistinctRegistrationResourceIds( + companyId, groupId, eventResourceId, userId); + } + @Override public java.util.List getEventRegistrations(long groupId, long eventResourceId) { diff --git a/modules/registration-service/registration-service-service/bnd.bnd b/modules/registration-service/registration-service-service/bnd.bnd index 4cbf65d51..90f0bbaf8 100644 --- a/modules/registration-service/registration-service-service/bnd.bnd +++ b/modules/registration-service/registration-service-service/bnd.bnd @@ -1,6 +1,6 @@ Bundle-Name: registration-service-service Bundle-SymbolicName: nl.deltares.dsd.registration.service -Bundle-Version: 1.1.0 +Bundle-Version: 1.1.1 Liferay-Require-SchemaVersion: 1.2.0 Liferay-Service: true -dsannotations-options: inherit diff --git a/modules/registration-service/registration-service-service/src/main/java/nl/deltares/dsd/registration/service/impl/RegistrationLocalServiceImpl.java b/modules/registration-service/registration-service-service/src/main/java/nl/deltares/dsd/registration/service/impl/RegistrationLocalServiceImpl.java index a1f7edc9c..e916ac48b 100644 --- a/modules/registration-service/registration-service-service/src/main/java/nl/deltares/dsd/registration/service/impl/RegistrationLocalServiceImpl.java +++ b/modules/registration-service/registration-service-service/src/main/java/nl/deltares/dsd/registration/service/impl/RegistrationLocalServiceImpl.java @@ -108,6 +108,24 @@ public void deleteAllRegistrationsAndChildRegistrations(long groupId, long resou } + /** + * Delete all registrations related to 'resourceId'. This includes all registration with a parentArticleId + * that matches 'resourceId'. + * + * @param userId Article Identifier of Event being removed. + */ + public int deleteAllUserRegistrations(long userId) { + + //Remove all registrations with a parentArticleId equal to resourceId + DynamicQuery dynamicQuery = dynamicQuery(); + dynamicQuery.add(RestrictionsFactoryUtil.eq("userId", userId)); + List withDynamicQuery = RegistrationUtil.findWithDynamicQuery(dynamicQuery); + for (Registration registration : withDynamicQuery) { + RegistrationUtil.removeByUserRegistrations(registration.getGroupId(), registration.getUserId()); + } + return withDynamicQuery.size(); + } + /** * Delete all registrations related to 'resourceId'. This includes all registration with a parentArticleId * that matches 'resourceId'. @@ -121,6 +139,18 @@ public void deleteAllEventRegistrations(long groupId, long eventResourceId) { RegistrationUtil.removeByEventRegistrations(groupId, eventResourceId); } + /** + * Delete all registrations related to 'resourceId'. This includes all registration with a parentArticleId + * that matches 'resourceId'. + * + * @param groupId Site Identifier + * @param registrationResourceId Article Identifier of Event being removed. + */ + public void deleteAllRegistrations(long groupId, long registrationResourceId) { + + //Remove all registrations with a parentArticleId equal to resourceId + RegistrationUtil.removeByArticleRegistrations(groupId, registrationResourceId); + } /** * Delete all registrations related to 'resourceId'. This includes all registration with a parentArticleId * that matches 'resourceId'. @@ -173,6 +203,41 @@ public void deleteUserRegistration(long groupId, long resourceId, long userId, D } + public List getDistinctEventResourceIds(long companyId, long groupId) { + + Criterion checkCompanyId = PropertyFactoryUtil.forName("companyId").eq(companyId); + Criterion checkGroupId = PropertyFactoryUtil.forName("groupId").eq(groupId); + + DynamicQuery query = DynamicQueryFactoryUtil.forClass(Registration.class, getClass().getClassLoader()) + .add(checkCompanyId).add(checkGroupId); + + Projection distinct = ProjectionFactoryUtil.distinct(PropertyFactoryUtil.forName("eventResourcePrimaryKey")); + query.setProjection(distinct); + + return RegistrationUtil.getPersistence().findWithDynamicQuery(query); + } + + public List getDistinctRegistrationResourceIds(long companyId, long groupId, long eventResourceId, long userId) { + + Criterion checkCompanyId = PropertyFactoryUtil.forName("companyId").eq(companyId); + Criterion checkGroupId = PropertyFactoryUtil.forName("groupId").eq(groupId); + + DynamicQuery query = DynamicQueryFactoryUtil.forClass(Registration.class, getClass().getClassLoader()) + .add(checkCompanyId).add(checkGroupId); + if (eventResourceId > 0L) { + Criterion checkEventResourceId = PropertyFactoryUtil.forName("eventResourcePrimaryKey").eq(eventResourceId); + query.add(checkEventResourceId); + } + if (userId > 0L) { + Criterion checkUserId = PropertyFactoryUtil.forName("userId").eq(userId); + query.add(checkUserId); + } + Projection distinct = ProjectionFactoryUtil.distinct(PropertyFactoryUtil.forName("resourcePrimaryKey")); + query.setProjection(distinct); + + return RegistrationUtil.getPersistence().findWithDynamicQuery(query); + } + private DynamicQuery getDynamicQuery(long groupId, long resourceId, long userId, Date startDate) { Criterion checkUserId = PropertyFactoryUtil.forName("userId").eq(userId); Criterion checkGroupId = PropertyFactoryUtil.forName("groupId").eq(groupId); @@ -240,7 +305,6 @@ public List getRegistrationDates(long groupId, long userId, long resourceI public List getUserEventRegistrations(long groupId, long userId, long eventResourceId) { return RegistrationUtil.findByUserEventRegistrations(groupId, userId, eventResourceId); - } public List getEventRegistrations(long groupId, long eventResourceId) { diff --git a/modules/registration-service/registration-service-service/src/main/resources/service.properties b/modules/registration-service/registration-service-service/src/main/resources/service.properties index 681e1d063..502f32979 100644 --- a/modules/registration-service/registration-service-service/src/main/resources/service.properties +++ b/modules/registration-service/registration-service-service/src/main/resources/service.properties @@ -13,5 +13,5 @@ ## build.namespace=nl.deltares.dsd.registration.service - build.number=68 - build.date=1758619542436 \ No newline at end of file + build.number=88 + build.date=1787742420799 \ No newline at end of file diff --git a/modules/tableviews/bnd.bnd b/modules/tableviews/bnd.bnd index 70336081a..e5b18ee62 100644 --- a/modules/tableviews/bnd.bnd +++ b/modules/tableviews/bnd.bnd @@ -1,6 +1,6 @@ Bundle-Name: tableviews Bundle-SymbolicName: nl.deltares.tableview.portlet -Bundle-Version: 1.1.7 +Bundle-Version: 1.1.11 Export-Package: nl.deltares.tableview.portlet.constants Import-Package: \ nl.deltares.tasks.*, \ diff --git a/modules/tableviews/src/main/java/nl/deltares/tableview/portlet/portlet/DownloadTablePortlet.java b/modules/tableviews/src/main/java/nl/deltares/tableview/portlet/portlet/DownloadTablePortlet.java index d82cbc8fd..e8b334711 100644 --- a/modules/tableviews/src/main/java/nl/deltares/tableview/portlet/portlet/DownloadTablePortlet.java +++ b/modules/tableviews/src/main/java/nl/deltares/tableview/portlet/portlet/DownloadTablePortlet.java @@ -12,17 +12,17 @@ import com.liferay.portal.kernel.theme.ThemeDisplay; import com.liferay.portal.kernel.util.ParamUtil; import com.liferay.portal.kernel.util.PortalUtil; +import com.liferay.portal.kernel.util.Validator; import com.liferay.portal.kernel.util.WebKeys; import nl.deltares.oss.download.model.Download; import nl.deltares.oss.download.service.DownloadLocalServiceUtil; import nl.deltares.oss.geolocation.model.GeoLocation; import nl.deltares.oss.geolocation.service.GeoLocationLocalServiceUtil; import nl.deltares.portal.utils.KeycloakUtils; -import nl.deltares.tableview.comparator.DownloadComparator; import nl.deltares.tableview.model.DisplayDownload; import nl.deltares.tableview.portlet.constants.TablePortletKeys; import nl.deltares.tableview.tasks.impl.DeletedSelectedDownloadsRequest; -import nl.deltares.tableview.tasks.impl.ExportDownloadsTableRequest; +import nl.deltares.tableview.tasks.impl.ExportSelectedDownloadsTableRequest; import nl.deltares.tasks.DataRequest; import nl.deltares.tasks.DataRequestManager; import org.osgi.service.component.annotations.Component; @@ -45,7 +45,7 @@ "javax.portlet.version=3.0", "com.liferay.portlet.display-category=OSS-table", "com.liferay.portlet.header-portlet-css=/css/main.css", - "com.liferay.portlet.header-portlet-javascript=/lib/downloadtableview.js", + "com.liferay.portlet.header-portlet-javascript=/lib/tableview.js", "com.liferay.portlet.header-portlet-javascript=/lib/common.js", "com.liferay.portlet.instanceable=true", "javax.portlet.display-name=DownloadTable", @@ -75,57 +75,60 @@ public void render(RenderRequest renderRequest, RenderResponse renderResponse) t final int curPage = ParamUtil.getInteger(renderRequest, "cur", 1); final int deltas = ParamUtil.getInteger(renderRequest, "delta", 25); - final String filterValue = ParamUtil.getString(renderRequest, "filterValue", null); - final String filterSelection = ParamUtil.getString(renderRequest, "filterSelection", null); + final String filterValue = ParamUtil.getString(renderRequest, "filterValue", ""); final String orderByCol = ParamUtil.getString(renderRequest, "orderByCol", "modifiedDate"); final String orderByType = ParamUtil.getString(renderRequest, "orderByType", "desc"); - doFilterValues(filterValue, filterSelection, curPage, deltas, orderByCol, orderByType, renderRequest); + doFilterValues(filterValue, curPage, deltas, orderByCol, orderByType, renderRequest); + + renderRequest.setAttribute("filterValue", filterValue); super.render(renderRequest, renderResponse); } - private void doFilterValues(String filterValue, String filterSelection, int curPage, int deltas, + private void doFilterValues(String filterValue, int curPage, int deltas, String orderByCol, String orderByType, RenderRequest renderRequest) { ThemeDisplay themeDisplay = (ThemeDisplay) renderRequest .getAttribute(WebKeys.THEME_DISPLAY); + long userId = 0; + String fileNameFilter = null; + if (Validator.isEmailAddress(filterValue)) { + User user = UserLocalServiceUtil.fetchUserByEmailAddress(themeDisplay.getCompanyId(), filterValue); + userId = user != null ? user.getUserId() : 0; + } else if (filterValue != null && !filterValue.trim().isEmpty()) { + fileNameFilter = filterValue.trim(); + } + final long siteGroupId = themeDisplay.getSiteGroupId(); List downloads = null; int downloadsCount = 0; final int start = (curPage - 1) * deltas; final int end = curPage * deltas; try { - if (filterValue != null && !filterValue.trim().isEmpty()) { - switch (filterSelection) { - case "email": - User user = UserLocalServiceUtil.getUserByEmailAddress(themeDisplay.getCompanyId(), filterValue); - downloads = DownloadLocalServiceUtil.findDownloadsByUserId(siteGroupId, user.getUserId(), start, end, orderByCol, orderByType); - downloadsCount = DownloadLocalServiceUtil.countDownloadsByUserId(siteGroupId, user.getUserId()); - break; - case "fileName": - downloads = DownloadLocalServiceUtil.findDownloadsByFileName(siteGroupId, filterValue, start, end, orderByCol, orderByType); - downloadsCount = DownloadLocalServiceUtil.countDownloadsByFileName(siteGroupId, filterValue); - break; - } + if (userId > 0) { + downloads = DownloadLocalServiceUtil.findDownloadsByUserId(siteGroupId, userId, start, end, orderByCol, orderByType); + downloadsCount = DownloadLocalServiceUtil.countDownloadsByUserId(siteGroupId, userId); + } else if (fileNameFilter != null) { + downloads = DownloadLocalServiceUtil.findDownloadsByFileName(siteGroupId, fileNameFilter, start, end, orderByCol, orderByType); + downloadsCount = DownloadLocalServiceUtil.countDownloadsByFileName(siteGroupId, fileNameFilter); } if (downloads == null) { - downloads = DownloadLocalServiceUtil.findDownloads(siteGroupId, start, end, orderByCol, orderByType); - downloadsCount = DownloadLocalServiceUtil.countDownloads(siteGroupId); + renderRequest.setAttribute("records", Collections.emptyList()); + renderRequest.setAttribute("total", 0); + } else { + final List displays = convertToDisplayDownloads(downloads); + renderRequest.setAttribute("records", displays); + renderRequest.setAttribute("total", downloadsCount); } - - final List displays = convertToDisplayDownloads(downloads); - - renderRequest.setAttribute("records", displays); - renderRequest.setAttribute("total", downloadsCount); renderRequest.setAttribute("filterValue", filterValue); - renderRequest.setAttribute("filterSelection", filterSelection); } catch (Exception e) { SessionErrors.add(renderRequest, "filter-failed", e.getMessage()); renderRequest.setAttribute("records", Collections.emptyList()); renderRequest.setAttribute("total", 0); } } + private List convertToDisplayDownloads(List downloads) { final ArrayList displays = new ArrayList<>(downloads.size()); @@ -134,41 +137,44 @@ private List convertToDisplayDownloads(List downloads final DisplayDownload displayDownload = new DisplayDownload(download); displays.add(displayDownload); - if (download.getGeoLocationId() == 0){ - final long userId = download.getUserId(); - Map attributes = userAttributeCache.get(userId); - if (attributes == null){ - final User user = UserLocalServiceUtil.fetchUser(userId); - if (user != null && keycloakUtils.isActive()) { - try { - attributes = keycloakUtils.getUserAttributes(user.getEmailAddress()); - userAttributeCache.put(userId, attributes); - } catch (Exception e) { - logger.warn(String.format("Error getting user attributes for %s: %s", user.getEmailAddress(), e.getMessage())); - attributes = Collections.emptyMap(); - userAttributeCache.put(userId, attributes); - } - } else { - attributes = Collections.emptyMap(); - } - } + if (download.getGeoLocationId() == 0) { + Map attributes = getUserAttributes(download.getUserId(), userAttributeCache); displayDownload.setCity(attributes.get(KeycloakUtils.ATTRIBUTES.org_city.name())); final Country country = CountryLocalServiceUtil.fetchCountryByName(download.getCompanyId(), attributes.get(KeycloakUtils.ATTRIBUTES.org_country.name())); if (country != null) displayDownload.setCountryCode(country.getA2()); - } else { + } else if (download.getGeoLocationId() > 0) { final long geoLocationId = download.getGeoLocationId(); final GeoLocation geoLocation = GeoLocationLocalServiceUtil.fetchGeoLocation(geoLocationId); - if (geoLocation != null){ + if (geoLocation != null) { displayDownload.setCity(geoLocation.getCityName()); Country country = CountryServiceUtil.fetchCountry(geoLocation.getCountryId()); displayDownload.setCountryCode(country.getA2()); } } - }); return displays; } + private Map getUserAttributes(long userId, HashMap> userAttributeCache) { + Map attributes = userAttributeCache.get(userId); + if (attributes == null) { + final User user = UserLocalServiceUtil.fetchUser(userId); + if (user != null && keycloakUtils.isActive()) { + try { + attributes = keycloakUtils.getUserAttributes(user.getEmailAddress()); + userAttributeCache.put(userId, attributes); + } catch (Exception e) { + logger.warn(String.format("Error getting user attributes for %s: %s", user.getEmailAddress(), e.getMessage())); + attributes = Collections.emptyMap(); + userAttributeCache.put(userId, attributes); + } + } else { + attributes = Collections.emptyMap(); + } + } + return attributes; + } + /** * Pass the selected filter options to the render request * @@ -176,12 +182,10 @@ private List convertToDisplayDownloads(List downloads * @param actionResponse Filter response */ @SuppressWarnings("unused") - public void filter(ActionRequest actionRequest, ActionResponse actionResponse) { + public void filterDownloads(ActionRequest actionRequest, ActionResponse actionResponse) { final String filter = ParamUtil.getString(actionRequest, "filterValue", "none"); actionResponse.getRenderParameters().setValue("filterValue", filter); - final String filterSelection = ParamUtil.getString(actionRequest, "filterSelection", "none"); - actionResponse.getRenderParameters().setValue("filterSelection", filterSelection); } @Override @@ -197,13 +201,12 @@ public void serveResource(ResourceRequest request, ResourceResponse response) th String action = ParamUtil.getString(request, "action"); String id = ParamUtil.getString(request, "id", null); String filterValue = ParamUtil.getString(request, "filterValue", null); - String filterSelection = ParamUtil.getString(request, "filterSelection", null); if ("export".equals(action)) { if (id == null) { id = DownloadTablePortlet.class.getName() + themeDisplay.getUserId(); } - exportTable(id, filterValue, filterSelection, response, themeDisplay); + exportTable(id, filterValue, response, themeDisplay); } else if ("delete-selected".equals(action)) { if (id == null) { id = DownloadTablePortlet.class.getName() + themeDisplay.getUserId(); @@ -248,12 +251,12 @@ private void deletedSelected(String dataRequestId, ResourceRequest request, Reso } - private void exportTable(String dataRequestId, String filterValue, String filterSelection, ResourceResponse response, ThemeDisplay themeDisplay) throws IOException { + private void exportTable(String dataRequestId, String filterValue, ResourceResponse response, ThemeDisplay themeDisplay) throws IOException { response.setContentType("text/csv"); DataRequestManager instance = DataRequestManager.getInstance(); DataRequest dataRequest = instance.getDataRequest(dataRequestId); if (dataRequest == null) { - dataRequest = new ExportDownloadsTableRequest(dataRequestId, filterValue, filterSelection, themeDisplay.getUserId(), themeDisplay.getSiteGroup(), keycloakUtils); + dataRequest = new ExportSelectedDownloadsTableRequest(dataRequestId, filterValue, themeDisplay.getUserId(), themeDisplay.getSiteGroup(), keycloakUtils); instance.addToQueue(dataRequest); } else if (dataRequest.getStatus() == DataRequest.STATUS.TERMINATED || dataRequest.getStatus() == DataRequest.STATUS.NODATA) { instance.removeDataRequest(dataRequest); @@ -266,11 +269,4 @@ private void exportTable(String dataRequestId, String filterValue, String filter } - private void sortDownloads(List displays, String orderByCol, String orderByType) { - - final DownloadComparator comparator = new DownloadComparator(orderByCol, orderByType.equals("asc")); - displays.sort(comparator); - - } - } \ No newline at end of file diff --git a/modules/tableviews/src/main/java/nl/deltares/tableview/portlet/portlet/RegistrationTablePortlet.java b/modules/tableviews/src/main/java/nl/deltares/tableview/portlet/portlet/RegistrationTablePortlet.java index 71cc00267..291d37d43 100644 --- a/modules/tableviews/src/main/java/nl/deltares/tableview/portlet/portlet/RegistrationTablePortlet.java +++ b/modules/tableviews/src/main/java/nl/deltares/tableview/portlet/portlet/RegistrationTablePortlet.java @@ -3,8 +3,6 @@ import com.liferay.journal.model.JournalArticle; import com.liferay.portal.kernel.exception.PortalException; import com.liferay.portal.kernel.json.JSONException; -import com.liferay.portal.kernel.json.JSONFactoryUtil; -import com.liferay.portal.kernel.json.JSONObject; import com.liferay.portal.kernel.model.User; import com.liferay.portal.kernel.portlet.bridges.mvc.MVCPortlet; import com.liferay.portal.kernel.service.UserLocalServiceUtil; @@ -18,14 +16,21 @@ import nl.deltares.dsd.registration.service.RegistrationLocalServiceUtil; import nl.deltares.portal.utils.DsdJournalArticleUtils; import nl.deltares.portal.utils.JsonContentUtils; -import nl.deltares.tableview.comparator.RegistrationComparator; import nl.deltares.tableview.model.DisplayRegistration; import nl.deltares.tableview.portlet.constants.TablePortletKeys; +import nl.deltares.tableview.tasks.impl.DeletedSelectedRegistrationsRequest; +import nl.deltares.tableview.tasks.impl.ExportSelectedRegistrationsTableRequest; +import nl.deltares.tableview.utils.RegistrationUtils; +import nl.deltares.tasks.DataRequest; +import nl.deltares.tasks.DataRequestManager; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; import javax.portlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.io.PrintWriter; import java.util.*; /** @@ -37,6 +42,8 @@ "javax.portlet.version=3.0", "com.liferay.portlet.display-category=OSS-table", "com.liferay.portlet.header-portlet-css=/css/main.css", + "com.liferay.portlet.header-portlet-javascript=/lib/tableview.js", + "com.liferay.portlet.header-portlet-javascript=/lib/common.js", "com.liferay.portlet.instanceable=true", "javax.portlet.display-name=RegistrationTable", "javax.portlet.init-param.template-path=/", @@ -58,15 +65,27 @@ public void render(RenderRequest renderRequest, RenderResponse renderResponse) t final int curPage = ParamUtil.getInteger(renderRequest, "cur", 1); final int deltas = ParamUtil.getInteger(renderRequest, "delta", 25); - final String filterValue = ParamUtil.getString(renderRequest, "filterValue", null); - final String filterSelection = ParamUtil.getString(renderRequest, "filterSelection", null); - + final String filterEmailValue = ParamUtil.getString(renderRequest, "filterEmailValue", ""); + final long filterEventValue = Long.parseLong(ParamUtil.getString(renderRequest, "filterEventValue", "0")); + final long filterRegistrationValue = Long.parseLong(ParamUtil.getString(renderRequest, "filterRegistrationValue", "0")); final String path = ParamUtil.getString(renderRequest, "mvcPath", null); + if (path != null && path.endsWith("editRegistration.jsp")) { doLoadRegistration(renderRequest); } else { - doFilterValues(filterValue, filterSelection, curPage, deltas, renderRequest); + doFilterValues(filterEmailValue, filterEventValue, filterRegistrationValue, curPage, deltas, renderRequest); + } + + if (filterEmailValue.isEmpty()) { + renderRequest.setAttribute("filterEmailValue", ""); + renderRequest.setAttribute("filterRegistrationValue", String.valueOf(filterRegistrationValue)); + renderRequest.setAttribute("filterEventValue", String.valueOf(filterEventValue)); + } else { + renderRequest.setAttribute("filterEmailValue", filterEmailValue); + renderRequest.setAttribute("filterRegistrationValue", "0"); + renderRequest.setAttribute("filterEventValue", "0"); } + super.render(renderRequest, renderResponse); } @@ -87,87 +106,69 @@ private void doLoadRegistration(RenderRequest renderRequest) { return; } - String eventName; - long eventResourceId; - final JournalArticle eventArticle = getArticleByResourcePrimaryKey(registration.getEventResourcePrimaryKey(), new HashMap<>()); - if (eventArticle != null) { - eventName = eventArticle.getTitle(); - eventResourceId = registration.getEventResourcePrimaryKey(); - } else { - eventName = ""; - eventResourceId = registration.getEventResourcePrimaryKey(); - } - String sessionName; - try { - final JournalArticle registrationArticle = dsdJournalArticleUtils.getLatestArticle(registration.getResourcePrimaryKey()); - sessionName = registrationArticle.getTitle(); - } catch (PortalException e) { - sessionName = String.valueOf(registration.getResourcePrimaryKey()); - } - final String email = ParamUtil.getString(renderRequest, "filterEmail", null); + long eventResourceId = registration.getEventResourcePrimaryKey(); + String eventName = RegistrationUtils.getArticleTitleByResourcePrimaryKey( + registration.getEventResourcePrimaryKey(), new HashMap<>(), dsdJournalArticleUtils, String.valueOf(eventResourceId)); + + String sessionName = RegistrationUtils.getArticleTitleByResourcePrimaryKey( + registration.getResourcePrimaryKey(), new HashMap<>(), dsdJournalArticleUtils, String.valueOf(registration.getResourcePrimaryKey())); + final String email = ParamUtil.getString(renderRequest, "editEmailValue", null); renderRequest.setAttribute("record", - new DisplayRegistration(id, registration.getResourcePrimaryKey(), eventResourceId, email, eventName, sessionName, formatJson(registration.getUserPreferences()), + new DisplayRegistration(id, registration.getResourcePrimaryKey(), eventResourceId, email, eventName, sessionName, + RegistrationUtils.formatJson(registration.getUserPreferences()), registration.getStartTime(), registration.getEndTime())); } - private String formatJson(String json) { + private void doFilterValues(String filterEmailValue, long filterEventValue, long filterRegistrationValue, int curPage, int deltas, RenderRequest renderRequest) { + ThemeDisplay themeDisplay = (ThemeDisplay) renderRequest + .getAttribute(WebKeys.THEME_DISPLAY); - try { - final JSONObject jsonObject = JSONFactoryUtil.createJSONObject(json); - return jsonObject.toString(4); - } catch (JSONException e) { - return json; + Map articleCache = new HashMap<>(); + Map eventTitles = RegistrationUtils.doLoadEventTitles(themeDisplay.getCompanyId(), themeDisplay.getSiteGroupId(), + articleCache, dsdJournalArticleUtils); + renderRequest.setAttribute("eventTitles", eventTitles); + + long userId = 0; + if (filterEmailValue != null && !filterEmailValue.trim().isEmpty()) { + User user = UserLocalServiceUtil.fetchUserByEmailAddress(themeDisplay.getCompanyId(), filterEmailValue); + userId = user != null ? user.getUserId() : 0; } - } - - private void doFilterValues(String filterValue, String filterSelection, int curPage, int deltas, RenderRequest renderRequest) { - ThemeDisplay themeDisplay = (ThemeDisplay) renderRequest - .getAttribute(WebKeys.THEME_DISPLAY); + Map registrationTitles = RegistrationUtils.doLoadRegistrationTitles(themeDisplay.getCompanyId(), + themeDisplay.getSiteGroupId(), filterEventValue, userId, articleCache, dsdJournalArticleUtils); + renderRequest.setAttribute("registrationTitles", registrationTitles); final long siteGroupId = themeDisplay.getSiteGroupId(); - - List registrations = null; - int recordCount = 0; + List registrations; + int recordCount; final int start = (curPage - 1) * deltas; final int end = curPage * deltas; try { - if (filterValue != null && !filterValue.trim().isEmpty()) { - switch (filterSelection) { - case "email": - User user = UserLocalServiceUtil.getUserByEmailAddress(themeDisplay.getCompanyId(), filterValue); - registrations = RegistrationLocalServiceUtil.getUserRegistrations(siteGroupId, user.getUserId(), start, end); - recordCount = RegistrationLocalServiceUtil.getUserRegistrationsCount(siteGroupId, user.getUserId()); - break; - case "resourceid": { - final long articleResourceId = Long.parseLong(filterValue); - registrations = RegistrationLocalServiceUtil.getArticleRegistrations(siteGroupId, articleResourceId, start, end); - recordCount = RegistrationLocalServiceUtil.getRegistrationsCount(siteGroupId, articleResourceId); - break; - } - case "eventid": { - final long eventResourceId = Long.parseLong(filterValue); - registrations = RegistrationLocalServiceUtil.getEventRegistrations(siteGroupId, eventResourceId, start, end); - recordCount = RegistrationLocalServiceUtil.getEventRegistrationsCount(siteGroupId, eventResourceId); - break; - } - } - } - if (registrations == null) { - registrations = RegistrationLocalServiceUtil.getRegistrations(start, end); - recordCount = RegistrationLocalServiceUtil.getRegistrationsCount(); + if (userId > 0) { + registrations = RegistrationLocalServiceUtil.getUserRegistrations(siteGroupId, userId, start, end); + recordCount = RegistrationLocalServiceUtil.getUserRegistrationsCount(siteGroupId, userId); + } else if (filterRegistrationValue > 0) { + registrations = RegistrationLocalServiceUtil.getArticleRegistrations(siteGroupId, filterRegistrationValue, start, end); + recordCount = RegistrationLocalServiceUtil.getRegistrationsCount(siteGroupId, filterRegistrationValue); + } else if (filterEventValue > 0) { + registrations = RegistrationLocalServiceUtil.getEventRegistrations(siteGroupId, filterEventValue, start, end); + recordCount = RegistrationLocalServiceUtil.getEventRegistrationsCount(siteGroupId, filterEventValue); + } else { + registrations = Collections.emptyList(); + recordCount = 0; } + List displays = RegistrationUtils.convertToDisplayValues(registrations, articleCache + , dsdJournalArticleUtils); + String orderByCol = ParamUtil.getString(renderRequest, "orderByCol"); String orderByType = ParamUtil.getString(renderRequest, "orderByType"); - final List displays = convertToDisplayRegistrations(registrations); - sortDownloads(displays, orderByCol, orderByType); + RegistrationUtils.sortDownloads(displays, orderByCol, orderByType); + renderRequest.setAttribute("records", displays); renderRequest.setAttribute("total", recordCount); - renderRequest.setAttribute("filterValue", filterValue); - renderRequest.setAttribute("filterSelection", filterSelection); } catch (Exception e) { SessionErrors.add(renderRequest, "filter-failed", e.getMessage()); @@ -175,41 +176,90 @@ private void doFilterValues(String filterValue, String filterSelection, int curP } - private JournalArticle getArticleByResourcePrimaryKey(long resourceId, Map cache) { + @Override + public void serveResource(ResourceRequest request, ResourceResponse response) throws IOException, PortletException { - JournalArticle journalArticle = cache.get(resourceId); - if (journalArticle != null) return journalArticle; - try { - journalArticle = dsdJournalArticleUtils.getLatestArticle(resourceId); - if (journalArticle != null) cache.put(resourceId, journalArticle); - return journalArticle; - } catch (PortalException e) { - return null; + ThemeDisplay themeDisplay = (ThemeDisplay) request + .getAttribute(WebKeys.THEME_DISPLAY); + if (!themeDisplay.isSignedIn() || !request.isUserInRole("administrator")) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.getWriter().println("Unauthorized request!"); + return; } + String action = ParamUtil.getString(request, "action"); + String id = ParamUtil.getString(request, "id", null); + final String filterEmailValue = ParamUtil.getString(request, "filterEmailValue", ""); + final long filterEventValue = Long.parseLong(ParamUtil.getString(request, "filterEventValue", "0")); + final long filterRegistrationValue = Long.parseLong(ParamUtil.getString(request, "filterRegistrationValue", "0")); + + if ("export".equals(action)) { + if (id == null) { + id = RegistrationTablePortlet.class.getName() + themeDisplay.getUserId(); + } + exportTable(id, filterEmailValue, filterEventValue, filterRegistrationValue, response, themeDisplay); + } else if ("delete-selected".equals(action)) { + if (id == null) { + id = RegistrationTablePortlet.class.getName() + themeDisplay.getUserId(); + } + deletedSelected(id, request, response, themeDisplay); + + } else if ("updateStatus".equals(action)) { + DataRequestManager.getInstance().updateStatus(id, response); + } else if ("downloadLog".equals(action)) { + DataRequestManager.getInstance().downloadDataFile(id, response); + } else { + DataRequestManager.getInstance().writeError("Unsupported Action error: " + action, response); + } + super.serveResource(request, response); + } - private List convertToDisplayRegistrations(List registrations) { + private void deletedSelected(String dataRequestId, ResourceRequest request, ResourceResponse response, ThemeDisplay themeDisplay) throws IOException { + + final HttpServletRequest httpReq = PortalUtil.getOriginalServletRequest(PortalUtil.getHttpServletRequest(request)); + final String[] selectedIds = httpReq.getParameterValues("selection"); + + if (selectedIds.length == 0) { + response.setContentType("text/plain"); + response.setStatus(HttpServletResponse.SC_NO_CONTENT); + } else { + response.setContentType("text/csv"); + DataRequestManager instance = DataRequestManager.getInstance(); + DataRequest dataRequest = instance.getDataRequest(dataRequestId); + if (dataRequest == null) { + dataRequest = new DeletedSelectedRegistrationsRequest(dataRequestId, Arrays.asList(selectedIds), themeDisplay.getUserId(), dsdJournalArticleUtils); + instance.addToQueue(dataRequest); + } else if (dataRequest.getStatus() == DataRequest.STATUS.TERMINATED || dataRequest.getStatus() == DataRequest.STATUS.NODATA) { + instance.removeDataRequest(dataRequest); + } + response.setStatus(HttpServletResponse.SC_OK); + String statusMessage = dataRequest.getStatusMessage(); + response.setContentLength(statusMessage.length()); + PrintWriter writer = response.getWriter(); + writer.println(statusMessage); + + } + } + + + private void exportTable(String dataRequestId, String filterEmailValue, long filterEventValue, long filterRegistrationValue, + ResourceResponse response, ThemeDisplay themeDisplay) throws IOException { + response.setContentType("text/csv"); + DataRequestManager instance = DataRequestManager.getInstance(); + DataRequest dataRequest = instance.getDataRequest(dataRequestId); + if (dataRequest == null) { + dataRequest = new ExportSelectedRegistrationsTableRequest(dataRequestId, filterEmailValue, filterEventValue, + filterRegistrationValue, themeDisplay, dsdJournalArticleUtils); + instance.addToQueue(dataRequest); + } else if (dataRequest.getStatus() == DataRequest.STATUS.TERMINATED || dataRequest.getStatus() == DataRequest.STATUS.NODATA) { + instance.removeDataRequest(dataRequest); + } + response.setStatus(HttpServletResponse.SC_OK); + String statusMessage = dataRequest.getStatusMessage(); + response.setContentLength(statusMessage.length()); + PrintWriter writer = response.getWriter(); + writer.println(statusMessage); - final ArrayList displays = new ArrayList<>(registrations.size()); - Map articleCache = new HashMap<>(); - registrations.forEach(registration -> { - String registrationTitle; - String eventTitle; - - final long registrationPrimaryKey = registration.getResourcePrimaryKey(); - JournalArticle registrationArticle = getArticleByResourcePrimaryKey(registrationPrimaryKey, articleCache); - registrationTitle = registrationArticle != null ? registrationArticle.getTitle() : ""; - final long eventResourcePrimaryKey = registration.getEventResourcePrimaryKey(); - JournalArticle eventArticle = getArticleByResourcePrimaryKey(eventResourcePrimaryKey, articleCache); - eventTitle = eventArticle != null ? eventArticle.getTitle() : ""; - final User user = UserLocalServiceUtil.fetchUser(registration.getUserId()); - final String email = user != null ? user.getEmailAddress() : ""; - displays.add(new DisplayRegistration(registration.getRegistrationId(), registrationPrimaryKey, eventResourcePrimaryKey, - email, eventTitle, registrationTitle, null, registration.getStartTime(), registration.getEndTime())); - }); - - displays.sort(DisplayRegistration::compareTo); - return displays; } /** @@ -219,31 +269,48 @@ private List convertToDisplayRegistrations(List displays, String orderByCol, String orderByType) { - - final RegistrationComparator comparator = new RegistrationComparator(orderByCol, orderByType.equals("asc")); - displays.sort(comparator); - } } \ No newline at end of file diff --git a/modules/tableviews/src/main/java/nl/deltares/tableview/tasks/impl/DeletedSelectedDownloadsRequest.java b/modules/tableviews/src/main/java/nl/deltares/tableview/tasks/impl/DeletedSelectedDownloadsRequest.java index ac73cb3f9..7757423cb 100644 --- a/modules/tableviews/src/main/java/nl/deltares/tableview/tasks/impl/DeletedSelectedDownloadsRequest.java +++ b/modules/tableviews/src/main/java/nl/deltares/tableview/tasks/impl/DeletedSelectedDownloadsRequest.java @@ -83,7 +83,9 @@ private void deleteSelectedRecords(PrintWriter writer) { final Download download = DownloadLocalServiceUtil.deleteDownload(Long.parseLong(id)); final User user = UserLocalServiceUtil.fetchUser(download.getUserId()); String email = ""; - if (user != null){ + if (user == null){ + email = String.valueOf(download.getUserId()); + } else { email = user.getEmailAddress(); } final Date modifiedDate = download.getModifiedDate(); diff --git a/modules/tableviews/src/main/java/nl/deltares/tableview/tasks/impl/DeletedSelectedRegistrationsRequest.java b/modules/tableviews/src/main/java/nl/deltares/tableview/tasks/impl/DeletedSelectedRegistrationsRequest.java new file mode 100644 index 000000000..2562f8116 --- /dev/null +++ b/modules/tableviews/src/main/java/nl/deltares/tableview/tasks/impl/DeletedSelectedRegistrationsRequest.java @@ -0,0 +1,114 @@ +package nl.deltares.tableview.tasks.impl; + +import com.liferay.journal.model.JournalArticle; +import com.liferay.portal.kernel.exception.PortalException; +import com.liferay.portal.kernel.log.Log; +import com.liferay.portal.kernel.log.LogFactoryUtil; +import com.liferay.portal.kernel.model.User; +import com.liferay.portal.kernel.service.UserLocalServiceUtil; +import nl.deltares.dsd.registration.model.Registration; +import nl.deltares.dsd.registration.service.RegistrationLocalServiceUtil; +import nl.deltares.portal.utils.DsdJournalArticleUtils; +import nl.deltares.tableview.utils.RegistrationUtils; +import nl.deltares.tasks.AbstractDataRequest; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.util.Date; +import java.util.HashMap; +import java.util.List; + +import static nl.deltares.tasks.DataRequest.STATUS.*; + +public class DeletedSelectedRegistrationsRequest extends AbstractDataRequest { + + + private static final Log logger = LogFactoryUtil.getLog(DeletedSelectedRegistrationsRequest.class); + + private final List selectedRecords; + private final DsdJournalArticleUtils dsdJournalArticleUtils; + + public DeletedSelectedRegistrationsRequest(String id, List recordIds, long userId, DsdJournalArticleUtils dsdJournalArticleUtils) throws IOException { + super(id, userId); + this.selectedRecords = recordIds; + this.dsdJournalArticleUtils = dsdJournalArticleUtils; + } + + @Override + public STATUS call() { + if (getStatus() == AVAILABLE) return status; + status = RUNNING; + statusMessage = "start deleting..."; + init(); + try { + File tempFile = new File(getExportDir(), id + ".tmp"); + if (tempFile.exists()) Files.deleteIfExists(tempFile.toPath()); + + try (PrintWriter writer = new PrintWriter(new FileWriter(tempFile))) { + deleteSelectedRecords(writer); + if (status != TERMINATED) { + status = AVAILABLE; + } + } catch (Exception e) { + errorMessage = e.getMessage(); + logger.warn("Error serializing csv content: %s", e); + status = TERMINATED; + } + if (status == AVAILABLE) { + this.dataFile = new File(getExportDir(), id + ".csv"); + if (dataFile.exists()) Files.deleteIfExists(dataFile.toPath()); + Files.move(tempFile.toPath(), dataFile.toPath()); + } + + } catch (Exception e) { + errorMessage = e.getMessage(); + status = TERMINATED; + } + fireStateChanged(); + + return status; + } + + private void deleteSelectedRecords(PrintWriter writer) { + + writer.println("event,registration,email,start,end"); + + totalCount = selectedRecords.size(); + + HashMap cachedArticles = new HashMap<>(); + selectedRecords.forEach(id -> { + if (status == TERMINATED) return; + try { + final Registration registration = RegistrationLocalServiceUtil.deleteRegistration(Long.parseLong(id)); + final User user = UserLocalServiceUtil.fetchUser(registration.getUserId()); + String email; + if (user == null) { + email = String.valueOf(registration.getUserId()); + } else { + email = user.getEmailAddress(); + } + JournalArticle eventArticle = RegistrationUtils.getArticleByResourcePrimaryKey(registration.getEventResourcePrimaryKey(), cachedArticles, dsdJournalArticleUtils); + JournalArticle registrationArticle = RegistrationUtils.getArticleByResourcePrimaryKey(registration.getResourcePrimaryKey(), cachedArticles, dsdJournalArticleUtils); + + final Date startDate = registration.getStartTime(); + final Date endDate = registration.getEndTime(); + writer.println(String.format("%s,%s,%s,%s,%s", + eventArticle == null ? registration.getEventResourcePrimaryKey() : eventArticle.getTitle(), + registrationArticle == null ? registration.getResourcePrimaryKey() : registrationArticle.getTitle(), + email, startDate, endDate)); + } catch (PortalException e) { + writer.println(String.format("Failed to delete record %s: %s", id, e.getMessage())); + } finally { + incrementProcessCount(1); + } + if (Thread.interrupted()) { + status = TERMINATED; + errorMessage = String.format("Thread 'DeletedSelectedDownloadsRequest' with id %s is interrupted!", id); + } + }); + } + +} diff --git a/modules/tableviews/src/main/java/nl/deltares/tableview/tasks/impl/ExportDownloadsTableRequest.java b/modules/tableviews/src/main/java/nl/deltares/tableview/tasks/impl/ExportSelectedDownloadsTableRequest.java similarity index 68% rename from modules/tableviews/src/main/java/nl/deltares/tableview/tasks/impl/ExportDownloadsTableRequest.java rename to modules/tableviews/src/main/java/nl/deltares/tableview/tasks/impl/ExportSelectedDownloadsTableRequest.java index 1dc325ec3..aaf92cfe6 100644 --- a/modules/tableviews/src/main/java/nl/deltares/tableview/tasks/impl/ExportDownloadsTableRequest.java +++ b/modules/tableviews/src/main/java/nl/deltares/tableview/tasks/impl/ExportSelectedDownloadsTableRequest.java @@ -6,6 +6,7 @@ import com.liferay.portal.kernel.model.User; import com.liferay.portal.kernel.service.CountryServiceUtil; import com.liferay.portal.kernel.service.UserLocalServiceUtil; +import com.liferay.portal.kernel.util.Validator; import nl.deltares.oss.download.model.Download; import nl.deltares.oss.download.service.DownloadLocalServiceUtil; import nl.deltares.oss.geolocation.model.GeoLocation; @@ -19,48 +20,45 @@ import java.io.PrintWriter; import java.nio.file.Files; import java.text.SimpleDateFormat; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.TimeZone; +import java.util.*; -import static nl.deltares.portal.utils.KeycloakUtils.ATTRIBUTES.org_city; -import static nl.deltares.portal.utils.KeycloakUtils.ATTRIBUTES.org_country; +import static nl.deltares.portal.utils.KeycloakUtils.ATTRIBUTES.*; import static nl.deltares.tasks.DataRequest.STATUS.*; import static nl.deltares.tasks.DataRequest.STATUS.TERMINATED; -public class ExportDownloadsTableRequest extends AbstractDataRequest { +public class ExportSelectedDownloadsTableRequest extends AbstractDataRequest { - private static final Log logger = LogFactoryUtil.getLog(ExportDownloadsTableRequest.class); + private static final Log logger = LogFactoryUtil.getLog(ExportSelectedDownloadsTableRequest.class); private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); static { dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); } - private final Group group; private final String filterValue; - private final String filterSelection; private final boolean findByUser; - private final boolean findByArticleId; protected KeycloakUtils keycloakUtils; - public ExportDownloadsTableRequest(String id, String filterValue, String filterSelection, long currentUserId, Group siteGroup, KeycloakUtils keycloakUtils) throws IOException { + public ExportSelectedDownloadsTableRequest(String id, String filterValue, long currentUserId, Group siteGroup, KeycloakUtils keycloakUtils) throws IOException { super(id, currentUserId); this.group = siteGroup; - this.filterValue = filterValue; - this.filterSelection = filterSelection; - - this.findByUser = "email".equals(filterSelection); - this.findByArticleId = "fileName".equals(filterSelection); - + if (filterValue != null && filterValue.trim().isEmpty()){ + this.filterValue = null; + } else { + this.filterValue = filterValue; + } + this.findByUser = Validator.isEmailAddress(filterValue); this.keycloakUtils = keycloakUtils; } @Override public STATUS call() { if (getStatus() == AVAILABLE) return status; - String filter = filterSelection == null ? "none": filterSelection + " = " + filterValue; - statusMessage = "starting exporting for filter " + filter; + + if (filterValue == null){ + status = NODATA; + return status; + } + statusMessage = "starting exporting for filter " + filterValue; init(); status = RUNNING; try { @@ -102,21 +100,22 @@ private void exportAllRecords(PrintWriter writer) { int start = 0; int end = 100; - final User filterUser; - final String fileName; + HashMap> userAttributesCache = new HashMap<>(); + User filterUser; if (findByUser) { - fileName = null; filterUser = UserLocalServiceUtil.fetchUserByEmailAddress(group.getCompanyId(), filterValue); - if (filterUser != null) totalCount = DownloadLocalServiceUtil.countDownloadsByUserId(group.getGroupId(), filterUser.getUserId()); - } else if (findByArticleId) { - filterUser = null; - fileName = filterValue; - totalCount = DownloadLocalServiceUtil.countDownloadsByFileName(group.getGroupId(), fileName); - } else - { - fileName = null; + if (filterUser == null){ + totalCount = 0; + } else { + totalCount = DownloadLocalServiceUtil.countDownloadsByUserId(group.getGroupId(), filterUser.getUserId()); + } + } else { filterUser = null; - totalCount = DownloadLocalServiceUtil.countDownloads(group.getGroupId()); + if (filterValue != null) { + totalCount = DownloadLocalServiceUtil.countDownloadsByFileName(group.getGroupId(), filterValue); + } else { + totalCount = 0; + } } for (int i = 0; i < totalCount; ) { @@ -124,47 +123,29 @@ private void exportAllRecords(PrintWriter writer) { final List downloads; if (filterUser != null) { downloads = DownloadLocalServiceUtil.findDownloadsByUserId(group.getGroupId(), filterUser.getUserId(), start, end); - } else if (fileName != null ) { - downloads = DownloadLocalServiceUtil.findDownloadsByFileName(group.getGroupId(), fileName, start, end); - } else - { - downloads = DownloadLocalServiceUtil.findDownloads(group.getGroupId(), start, end); + } else { + downloads = DownloadLocalServiceUtil.findDownloadsByFileName(group.getGroupId(), filterValue, start, end); } if (downloads.isEmpty()) { setProcessCount(totalCount); return; } - HashMap> userAttributesCache = new HashMap<>(); downloads.forEach(download -> { if (status == TERMINATED) return; incrementProcessCount(1); - if (group.getGroupId() != download.getGroupId()) return; - String email = ""; - String fullName = ""; - if (filterUser != null){ - email = filterValue; - fullName = filterUser.getFullName(); - } else { - final User user = UserLocalServiceUtil.fetchUser(download.getUserId()); - if (user != null) { - email = user.getEmailAddress(); - fullName = user.getFullName(); - } - } String city = ""; String countryCode = ""; + String fullName; + String email; + User downloadUser = filterUser != null ? filterUser : UserLocalServiceUtil.fetchUser(download.getUserId()); try { if (download.getGeoLocationId() > 0) { final GeoLocation geoLocation = GeoLocationLocalServiceUtil.getGeoLocation(download.getGeoLocationId()); city = geoLocation.getCityName(); countryCode = CountryServiceUtil.getCountry(geoLocation.getCountryId()).getA2(); - } else if (keycloakUtils.isActive()) { - Map attributes = userAttributesCache.get(download.getUserId()); - if (attributes == null){ - attributes = keycloakUtils.getUserAttributes(email); - userAttributesCache.put(download.getUserId(), attributes); - } + } else if (keycloakUtils.isActive() && downloadUser != null) { + Map attributes = getUserAttributes(downloadUser, userAttributesCache); city = attributes.get(org_city.name()); countryCode = attributes.get(org_country.name()); } @@ -178,6 +159,13 @@ private void exportAllRecords(PrintWriter writer) { } else { modifiedDate = ""; } + if (downloadUser != null) { + fullName = downloadUser.getFullName(); + email = downloadUser.getEmailAddress(); + } else { + fullName = String.valueOf(download.getUserId()); + email = ""; + } final String expiryDate; if (download.getExpiryDate() != null) { expiryDate = dateFormat.format(download.getExpiryDate()); @@ -201,4 +189,20 @@ private void exportAllRecords(PrintWriter writer) { } + private Map getUserAttributes(User user, HashMap> userAttributeCache) { + long userId = user.getUserId(); + Map attributes = userAttributeCache.get(userId); + if (attributes == null) { + try { + attributes = keycloakUtils.getUserAttributes(user.getEmailAddress()); + userAttributeCache.put(userId, attributes); + } catch (Exception e) { + logger.warn(String.format("Error getting user attributes for %s: %s", user.getEmailAddress(), e.getMessage())); + attributes = Collections.emptyMap(); + userAttributeCache.put(userId, attributes); + } + } + return attributes; + } + } diff --git a/modules/tableviews/src/main/java/nl/deltares/tableview/tasks/impl/ExportSelectedRegistrationsTableRequest.java b/modules/tableviews/src/main/java/nl/deltares/tableview/tasks/impl/ExportSelectedRegistrationsTableRequest.java new file mode 100644 index 000000000..88103e427 --- /dev/null +++ b/modules/tableviews/src/main/java/nl/deltares/tableview/tasks/impl/ExportSelectedRegistrationsTableRequest.java @@ -0,0 +1,163 @@ +package nl.deltares.tableview.tasks.impl; + +import com.liferay.journal.model.JournalArticle; +import com.liferay.portal.kernel.log.Log; +import com.liferay.portal.kernel.log.LogFactoryUtil; +import com.liferay.portal.kernel.model.Group; +import com.liferay.portal.kernel.model.User; +import com.liferay.portal.kernel.service.UserLocalServiceUtil; +import com.liferay.portal.kernel.theme.ThemeDisplay; +import com.liferay.portal.kernel.util.Validator; +import nl.deltares.dsd.registration.model.Registration; +import nl.deltares.dsd.registration.service.RegistrationLocalServiceUtil; +import nl.deltares.portal.utils.DsdJournalArticleUtils; +import nl.deltares.tableview.model.DisplayRegistration; +import nl.deltares.tableview.utils.RegistrationUtils; +import nl.deltares.tasks.AbstractDataRequest; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static nl.deltares.tasks.DataRequest.STATUS.*; + +public class ExportSelectedRegistrationsTableRequest extends AbstractDataRequest { + + private static final Log logger = LogFactoryUtil.getLog(ExportSelectedRegistrationsTableRequest.class); + + private final Group group; + private final boolean findByUser; + private final String filterEmail; + private final long filterEventId; + private final long filterRegistrationId; + + private final DsdJournalArticleUtils dsdJournalArticleUtils; + + public ExportSelectedRegistrationsTableRequest(String id, String filterEmailValue, long filterEventValue, + long filterRegistrationValue, ThemeDisplay themeDisplay, + DsdJournalArticleUtils dsdJournalArticleUtils) throws IOException { + super(id, themeDisplay.getUserId()); + this.group = themeDisplay.getSiteGroup(); + this.filterEmail = filterEmailValue; + this.filterEventId = filterEventValue; + this.filterRegistrationId = filterRegistrationValue; + this.findByUser = Validator.isEmailAddress(filterEmailValue); + this.dsdJournalArticleUtils = dsdJournalArticleUtils; + } + + @Override + public STATUS call() { + if (getStatus() == AVAILABLE) return status; + + if (!findByUser && filterEventId == 0 && filterRegistrationId == 0) { + status = NODATA; + return status; + } + statusMessage = "starting exporting registrations for filter"; + + status = RUNNING; + try { + File tempFile = new File(getExportDir(), id + ".tmp"); + if (tempFile.exists()) Files.deleteIfExists(tempFile.toPath()); + + try (PrintWriter writer = new PrintWriter(new FileWriter(tempFile))) { + exportSelectedRecords(writer); + if (status != TERMINATED) { + status = AVAILABLE; + } + } catch (Exception e) { + errorMessage = e.getMessage(); + logger.warn("Error serializing csv content: %s", e); + status = TERMINATED; + } + if (status == AVAILABLE) { + this.dataFile = new File(getExportDir(), id + ".csv"); + if (dataFile.exists()) Files.deleteIfExists(dataFile.toPath()); + Files.move(tempFile.toPath(), dataFile.toPath()); + } + + } catch (Exception e) { + errorMessage = e.getMessage(); + status = TERMINATED; + } finally { + if (status == RUNNING || status == PENDING) { + status = TERMINATED; + } + } + fireStateChanged(); + + return status; + } + + private void exportSelectedRecords(PrintWriter writer) { + + long companyId = group.getCompanyId(); + long groupId = group.getGroupId(); + + User filterUser = null; + Map articleCache = new HashMap<>(); + if (findByUser) { + filterUser = UserLocalServiceUtil.fetchUserByEmailAddress(companyId, filterEmail); + if (filterUser == null) { + totalCount = 0; + } else { + totalCount = RegistrationLocalServiceUtil.getUserRegistrationsCount(groupId, filterUser.getUserId()); + } + } else { + totalCount = RegistrationLocalServiceUtil.getEventRegistrationsCount(groupId, filterEventId); + } + + if (totalCount == 0) { + status = NODATA; + setProcessCount(0); + return; + } + + writer.println("event,registration,email,start,end"); + + int start = 0; + int end = 100; + + for (int i = 0; i < totalCount; ) { + if (status == TERMINATED) return; + final List registrations; + + if (filterUser != null) { + registrations = RegistrationLocalServiceUtil.getUserRegistrations(groupId, filterUser.getUserId(), start, end); + } else if (filterRegistrationId > 0) { + registrations = RegistrationLocalServiceUtil.getArticleRegistrations(groupId, filterRegistrationId, start, end); + } else if (filterEventId > 0) { + registrations = RegistrationLocalServiceUtil.getEventRegistrations(groupId, filterEventId, start, end); + } else { + registrations = Collections.emptyList(); + } + List displayRegistrations = RegistrationUtils.convertToDisplayValues(registrations, + articleCache, dsdJournalArticleUtils); + + displayRegistrations.forEach(registration -> { + if (status == TERMINATED) return; + incrementProcessCount(1); + + writer.println(String.format("%s,%s,%s,%s,%s", + registration.getEventName(), registration.getRegistrationName(), registration.getEmail(), + registration.getStartTime(), registration.getEndTime())); + + if (Thread.interrupted()) { + status = TERMINATED; + errorMessage = String.format("Thread 'ExportSelectedRegistrationsRequest' with id %s is interrupted!", id); + } + }); + i += registrations.size(); + start = end; + end += 100; + } + + } + +} diff --git a/modules/tableviews/src/main/java/nl/deltares/tableview/utils/RegistrationUtils.java b/modules/tableviews/src/main/java/nl/deltares/tableview/utils/RegistrationUtils.java new file mode 100644 index 000000000..4aeb196e3 --- /dev/null +++ b/modules/tableviews/src/main/java/nl/deltares/tableview/utils/RegistrationUtils.java @@ -0,0 +1,107 @@ +package nl.deltares.tableview.utils; + +import com.liferay.journal.model.JournalArticle; +import com.liferay.portal.kernel.exception.PortalException; +import com.liferay.portal.kernel.json.JSONException; +import com.liferay.portal.kernel.json.JSONFactoryUtil; +import com.liferay.portal.kernel.json.JSONObject; +import com.liferay.portal.kernel.model.User; +import com.liferay.portal.kernel.service.UserLocalServiceUtil; +import nl.deltares.dsd.registration.model.Registration; +import nl.deltares.dsd.registration.service.RegistrationLocalServiceUtil; +import nl.deltares.portal.utils.DsdJournalArticleUtils; +import nl.deltares.tableview.comparator.RegistrationComparator; +import nl.deltares.tableview.model.DisplayRegistration; + +import java.util.*; + +public class RegistrationUtils { + + public static List convertToDisplayValues(List registrations, Map articleCache, + DsdJournalArticleUtils dsdJournalArticleUtils) { + + final ArrayList displays = new ArrayList<>(registrations.size()); + registrations.forEach(registration -> { + final long registrationPrimaryKey = registration.getResourcePrimaryKey(); + + String registrationTitle = getArticleTitleByResourcePrimaryKey(registrationPrimaryKey, articleCache, dsdJournalArticleUtils, String.valueOf(registrationPrimaryKey)); + + final long eventResourcePrimaryKey = registration.getEventResourcePrimaryKey(); + String eventTitle = getArticleTitleByResourcePrimaryKey(eventResourcePrimaryKey, articleCache, dsdJournalArticleUtils, String.valueOf(eventResourcePrimaryKey)); + + final User user = UserLocalServiceUtil.fetchUser(registration.getUserId()); + final String email = user != null ? user.getEmailAddress() : String.valueOf(registration.getUserId()); + displays.add(new DisplayRegistration(registration.getRegistrationId(), registrationPrimaryKey, eventResourcePrimaryKey, + email, eventTitle, registrationTitle, null, registration.getStartTime(), registration.getEndTime())); + }); + return displays; + } + + public static String getArticleTitleByResourcePrimaryKey(long resourceId, Map cache, DsdJournalArticleUtils dsdJournalArticleUtils, String defaultValue) { + + JournalArticle article = getArticleByResourcePrimaryKey(resourceId, cache, dsdJournalArticleUtils); + if (article != null) {return article.getTitle();} + return defaultValue; + + } + public static JournalArticle getArticleByResourcePrimaryKey(long resourceId, Map cache, DsdJournalArticleUtils dsdJournalArticleUtils) { + + JournalArticle journalArticle = cache.get(resourceId); + if (journalArticle != null) return journalArticle; + try { + journalArticle = dsdJournalArticleUtils.getLatestArticle(resourceId); + if (journalArticle != null) cache.put(resourceId, journalArticle); + return journalArticle; + } catch (PortalException e) { + return null; + } + } + + public static Map doLoadEventTitles(long companyId, long siteGroupId, Map cache, DsdJournalArticleUtils dsdJournalArticleUtils) { + + Map titles = new HashMap<>(); + + List resourceIds = RegistrationLocalServiceUtil.getDistinctEventResourceIds( + companyId, siteGroupId); + for (Long resourceId : resourceIds) { + String title = getArticleTitleByResourcePrimaryKey(resourceId, cache, dsdJournalArticleUtils, String.valueOf(resourceId)); + if (title != null) titles.put(resourceId, title); + } + return titles; + } + + public static Map doLoadRegistrationTitles(long companyId, long groupId, long selectedEventResourceId, + long selectedUserId, Map cache, DsdJournalArticleUtils dsdJournalArticleUtils) { + + if (selectedEventResourceId == 0) { + return Collections.emptyMap(); + } + + Map titles = new HashMap<>(); + List resourceIds = RegistrationLocalServiceUtil.getDistinctRegistrationResourceIds( + companyId, groupId, selectedEventResourceId, selectedUserId); + for (Long resourceId : resourceIds) { + String title = getArticleTitleByResourcePrimaryKey(resourceId, cache, dsdJournalArticleUtils, String.valueOf(resourceId)); + if (title != null) titles.put(resourceId, title); + } + return titles; + } + + public static String formatJson(String json) { + + try { + final JSONObject jsonObject = JSONFactoryUtil.createJSONObject(json); + return jsonObject.toString(4); + } catch (JSONException e) { + return json; + } + + } + + public static void sortDownloads(List displays, String orderByCol, String orderByType) { + + final RegistrationComparator comparator = new RegistrationComparator(orderByCol, orderByType.equals("asc")); + displays.sort(comparator); + + } +} diff --git a/modules/tableviews/src/main/resources/META-INF/resources/css/main.scss b/modules/tableviews/src/main/resources/META-INF/resources/css/main.scss index 762161bee..e382d7f36 100644 --- a/modules/tableviews/src/main/resources/META-INF/resources/css/main.scss +++ b/modules/tableviews/src/main/resources/META-INF/resources/css/main.scss @@ -1,3 +1,7 @@ .table thead th, .table thead td { vertical-align: top; +} + +.float-right { + float: right; } \ No newline at end of file diff --git a/modules/tableviews/src/main/resources/META-INF/resources/downloadCountsTable.jsp b/modules/tableviews/src/main/resources/META-INF/resources/downloadCountsTable.jsp index 4c62f086e..92d4e7009 100644 --- a/modules/tableviews/src/main/resources/META-INF/resources/downloadCountsTable.jsp +++ b/modules/tableviews/src/main/resources/META-INF/resources/downloadCountsTable.jsp @@ -40,7 +40,7 @@ -
+
diff --git a/modules/tableviews/src/main/resources/META-INF/resources/downloadsTable.jsp b/modules/tableviews/src/main/resources/META-INF/resources/downloadsTable.jsp index 1970372f2..27afe55d7 100644 --- a/modules/tableviews/src/main/resources/META-INF/resources/downloadsTable.jsp +++ b/modules/tableviews/src/main/resources/META-INF/resources/downloadsTable.jsp @@ -14,8 +14,6 @@ <% final Integer count = (Integer) request.getAttribute("total"); final String filterValue = (String) request.getAttribute("filterValue"); - final String filterSelection = (String) request.getAttribute("filterSelection"); - %> @@ -25,13 +23,11 @@ - - - + - + - + + -
+
- + - -
-
- -
-
- -
-
-
- - - + + + +
+ + <%-- Don't pass filter values so filter fields will be emptied.--%> + + + + +
@@ -91,19 +76,16 @@ modelVar="entry" keyProperty="id" > - - + - - + + - - @@ -124,14 +106,14 @@ let exportResultsButton = document.getElementById('exportResultsButton'); exportResultsButton.onclick = function(event){ - event.preventDefault(); - TableFormsUtil.exportResults("", "", "export-downloads.csv") + event.preventDefault(); + TableFormsUtil.exportResults("", "", "export-downloads.csv") }; let deleteSelectedButton = document.getElementById('deleteSelectedButton'); deleteSelectedButton.onclick = function(event){ - event.preventDefault(); - TableFormsUtil.deleteSelected("", "", "", "delete-selected-downloads.csv") + event.preventDefault(); + TableFormsUtil.deleteSelected("", "", "", "delete-selected-downloads.csv") }; diff --git a/modules/tableviews/src/main/resources/META-INF/resources/editRegistration.jsp b/modules/tableviews/src/main/resources/META-INF/resources/editRegistration.jsp index b32b3b1cc..2836975a8 100644 --- a/modules/tableviews/src/main/resources/META-INF/resources/editRegistration.jsp +++ b/modules/tableviews/src/main/resources/META-INF/resources/editRegistration.jsp @@ -15,6 +15,7 @@ final DisplayRegistration displayRegistration = (DisplayRegistration) request.getAttribute("record"); String recordId = ""; String registrationId = ""; + String eventRegistrationId = ""; String registrationName = ""; String eventName = ""; String email = ""; @@ -24,6 +25,8 @@ registrationName = displayRegistration.getRegistrationName(); eventName = displayRegistration.getEventName(); email = displayRegistration.getEmail(); + registrationId = String.valueOf(displayRegistration.getResourceId()); + eventRegistrationId = String.valueOf(displayRegistration.getEventResourceId()); preferences = displayRegistration.getPreferences(); } @@ -34,11 +37,16 @@ - + + + + - + + + diff --git a/modules/tableviews/src/main/resources/META-INF/resources/lib/downloadtableview.js b/modules/tableviews/src/main/resources/META-INF/resources/lib/tableview.js similarity index 97% rename from modules/tableviews/src/main/resources/META-INF/resources/lib/downloadtableview.js rename to modules/tableviews/src/main/resources/META-INF/resources/lib/tableview.js index 540f4c221..a88b8d57d 100644 --- a/modules/tableviews/src/main/resources/META-INF/resources/lib/downloadtableview.js +++ b/modules/tableviews/src/main/resources/META-INF/resources/lib/tableview.js @@ -14,7 +14,7 @@ var TableFormsUtil = { let selected = []; this.loadSelection(namespace, selected); if (selected.length === 0){ - alert("Please select one or more downloads before continuing."); + alert("Please select one or more records before continuing."); } else { this.callResourceUrl(resourceUrl, namespace, filename, "delete-selected", selected, renderUrl); } diff --git a/modules/tableviews/src/main/resources/META-INF/resources/registrationTable.jsp b/modules/tableviews/src/main/resources/META-INF/resources/registrationTable.jsp index 042f75afd..35a7ce805 100644 --- a/modules/tableviews/src/main/resources/META-INF/resources/registrationTable.jsp +++ b/modules/tableviews/src/main/resources/META-INF/resources/registrationTable.jsp @@ -4,34 +4,36 @@ <%@ taglib uri="http://liferay.com/tld/portlet" prefix="liferay-portlet" %> <%@ taglib uri="http://liferay.com/tld/theme" prefix="liferay-theme" %> <%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %> +<%@ page import="com.liferay.portal.kernel.dao.search.RowChecker" %> <%@ page import="com.liferay.portal.kernel.language.LanguageUtil" %> <%@ page import="com.liferay.portal.kernel.servlet.SessionErrors" %> <%@ page import="com.liferay.portal.kernel.servlet.SessionMessages" %> -<%@ page import="com.liferay.portal.kernel.dao.search.RowChecker" %> +<%@ page import="java.util.Map" %> <% final Integer count = (Integer) request.getAttribute("total"); - final String filterValue = (String) request.getAttribute("filterValue"); - final String filterSelection = (String) request.getAttribute("filterSelection"); + final String filterEmailValue = (String) request.getAttribute("filterEmailValue"); + final String filterEventValue = (String) request.getAttribute("filterEventValue"); + final String filterRegistrationValue = (String) request.getAttribute("filterRegistrationValue"); + final Map eventTitles = (Map) request.getAttribute("eventTitles"); + final Map registrationTitles = (Map) request.getAttribute("registrationTitles"); %> - - - - - - + + + - + + - + + -
+
- - + + - -
-
- -
-
- -
-
- -
-
+ + + + +
+
+
+ + + + - - +
+
+ + + Select... + <% + for (Map.Entry eventInfo : eventTitles.entrySet()) { + %> + + <% + } + %> + + + + + Select... + <% + for (Map.Entry registrationInfo : registrationTitles.entrySet()) { + %> + + <% + } + %> +
+
+ + <%-- Don't pass filter values so filter fields will be emptied.--%> + + + + +
- + - - + + - - - - - - - - <%-- --%> + + + + + - + - + + + + - + + + + - - +<%-- +<%-- href="<%=deleteRegistrationURL%>"/>--%> + + + + +
@@ -137,16 +170,20 @@
- - - let deleteButtons = document.getElementsByClassName("deleteButton"); - Array.from(deleteButtons).forEach(function (button) { - button.addEventListener('click', function (event){ - if (confirm("You are about to delete this registration.\nDo you want to continue?") === false) { - event.preventDefault(); - } - }); - }); + + + + let exportResultsButton = document.getElementById('exportResultsButton'); + exportResultsButton.onclick = function(event){ + event.preventDefault(); + TableFormsUtil.exportResults("", "", "export-registrations.csv") + }; + + let deleteSelectedButton = document.getElementById('deleteSelectedButton'); + deleteSelectedButton.onclick = function(event){ + event.preventDefault(); + TableFormsUtil.deleteSelected("", "", "", "delete-selected-registrations.csv") + }; diff --git a/modules/tableviews/src/main/resources/content/Language.properties b/modules/tableviews/src/main/resources/content/Language.properties index a4429d455..07423171b 100644 --- a/modules/tableviews/src/main/resources/content/Language.properties +++ b/modules/tableviews/src/main/resources/content/Language.properties @@ -4,8 +4,8 @@ table.download.title=Downloads table table.registration.title=Registrations table table.registration.edit.title=Edit Registration table.downloads.count.title=Downloads count -table.filter.label=Select filter -table.filter.email.label=Enter search e-mail +table.filter.email.label=Search e-mail +table.filter.selection.label=Search table.filter.button=Filter table.filter.clear=Clear filter table.update.label=Update share info diff --git a/platform.bndrun b/platform.bndrun deleted file mode 100644 index 2ba4438e4..000000000 --- a/platform.bndrun +++ /dev/null @@ -1,29 +0,0 @@ -## Check GETTING_STARTED.markdown#platform.bndrun for more information. - --distro: ${targetPlatformDistro};x-whitelist=osgi.wiring.host --resolve.effective: active --runprovidedcapabilities:\ - osgi.service;objectClass:List='com.liferay.asset.kernel.service.persistence.AssetCategoryPersistence',\ - osgi.service;objectClass:List='com.liferay.frontend.js.loader.modules.extender.npm.NPMResolver',\ - osgi.service;objectClass:List='com.liferay.portal.kernel.configuration.Configuration',\ - osgi.service;objectClass:List='com.liferay.portal.kernel.dao.orm.SessionFactory',\ - osgi.service;objectClass:List='com.liferay.portal.kernel.json.JSONFactory',\ - osgi.service;objectClass:List='com.liferay.portal.kernel.language.Language',\ - osgi.service;objectClass:List='com.liferay.portal.kernel.model.Portlet',\ - osgi.service;objectClass:List='com.liferay.portal.kernel.module.framework.ModuleServiceLifecycle',\ - osgi.service;objectClass:List='com.liferay.portal.kernel.portlet.PortletPreferencesFactory',\ - osgi.service;objectClass:List='com.liferay.portal.kernel.portlet.PortletURLFactory',\ - osgi.service;objectClass:List='com.liferay.portal.kernel.service.persistence.LayoutSetPersistence',\ - osgi.service;objectClass:List='com.liferay.portal.kernel.util.File',\ - osgi.service;objectClass:List='com.liferay.portal.kernel.util.Html',\ - osgi.service;objectClass:List='com.liferay.portal.kernel.util.Http',\ - osgi.service;objectClass:List='com.liferay.portal.kernel.util.MimeTypes',\ - osgi.service;objectClass:List='com.liferay.portal.kernel.util.Portal',\ - osgi.service;objectClass:List='com.liferay.portal.kernel.util.PrefsProps',\ - osgi.service;objectClass:List='com.liferay.portal.kernel.util.Props',\ - osgi.service;objectClass:List='com.liferay.portal.kernel.xml.SAXReader',\ - osgi.service;objectClass:List='com.liferay.portal.kernel.zip.ZipReaderFactory',\ - osgi.service;objectClass:List='javax.servlet.ServletContext',\ - osgi.service;objectClass:List='javax.sql.DataSource',\ - osgi.wiring.package;osgi.wiring.package=com.sun.nio.file --runrequires: osgi.identity;filter:='(osgi.identity=${project.bundle.Bundle-SymbolicName})' \ No newline at end of file diff --git a/themes/deltares-fews-theme/package.json b/themes/deltares-fews-theme/package.json index 1c5667707..45ac69514 100644 --- a/themes/deltares-fews-theme/package.json +++ b/themes/deltares-fews-theme/package.json @@ -1,6 +1,6 @@ { "name": "deltares-fews-theme", - "version": "1.1.5", + "version": "1.1.6", "main": "package.json", "repository": { "type": "git", diff --git a/themes/deltares-fews-theme/src/templates/user_personal.ftl b/themes/deltares-fews-theme/src/templates/user_personal.ftl index b6770c05c..4e2e2eced 100644 --- a/themes/deltares-fews-theme/src/templates/user_personal.ftl +++ b/themes/deltares-fews-theme/src/templates/user_personal.ftl @@ -29,11 +29,6 @@ - <#if user_mailing_url??> - -
  • Logout