diff --git a/.github/workflows/build-and-test-cloud.yml b/.github/workflows/build-and-test-cloud.yml new file mode 100644 index 00000000..1092bd0c --- /dev/null +++ b/.github/workflows/build-and-test-cloud.yml @@ -0,0 +1,28 @@ +name: Build and test for AEM as a Cloud Service + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup JDK + uses: actions/setup-java@v3 + with: + distribution: 'zulu' + java-version: 11 + + - name: Cache local Maven repository + uses: actions/cache@v3 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + + - name: Build & Test with Maven for AEM Cloud SDK + run: mvn --batch-mode --update-snapshots --activate-profiles cloud install diff --git a/.github/workflows/build-and-test-on-prem.yml b/.github/workflows/build-and-test-on-prem.yml new file mode 100644 index 00000000..eaa3bda5 --- /dev/null +++ b/.github/workflows/build-and-test-on-prem.yml @@ -0,0 +1,28 @@ +name: Build and test for AEM 6.5 + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup JDK + uses: actions/setup-java@v3 + with: + distribution: 'zulu' + java-version: 11 + + - name: Cache local Maven repository + uses: actions/cache@v3 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + + - name: Build & Test with Maven for AEM 6.5 + run: mvn --batch-mode --update-snapshots clean install diff --git a/.github/workflows/maven-release-central.yml b/.github/workflows/maven-release-central.yml new file mode 100644 index 00000000..7b92d06e --- /dev/null +++ b/.github/workflows/maven-release-central.yml @@ -0,0 +1,32 @@ +name: Publish package to the Maven Central Repository + +on: + release: + types: [created] + +jobs: + publish: + + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Maven Central Repository + uses: actions/setup-java@v3 + with: + distribution: 'zulu' + java-version: 11 + server-id: ossrh + server-username: MAVEN_USERNAME + server-password: MAVEN_PASSWORD + gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} + gpg-passphrase: MAVEN_GPG_PASSPHRASE + + - name: Publish package + run: mvn --batch-mode deploy + env: + MAVEN_USERNAME: ${{ secrets.SONATYPE_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} diff --git a/.run/Author.run.xml b/.run/Author.run.xml new file mode 100644 index 00000000..e519e64f --- /dev/null +++ b/.run/Author.run.xml @@ -0,0 +1,15 @@ + + + + \ No newline at end of file diff --git a/.run/Publish.run.xml b/.run/Publish.run.xml new file mode 100644 index 00000000..3a6dc185 --- /dev/null +++ b/.run/Publish.run.xml @@ -0,0 +1,15 @@ + + + + \ No newline at end of file diff --git a/.run/[author] aem-groovy-console.run.xml b/.run/[author] aem-groovy-console.run.xml new file mode 100644 index 00000000..33ca3ad4 --- /dev/null +++ b/.run/[author] aem-groovy-console.run.xml @@ -0,0 +1,30 @@ + + + + + + + + \ No newline at end of file diff --git a/.run/[author] all.run.xml b/.run/[author] all.run.xml new file mode 100644 index 00000000..9dcd6716 --- /dev/null +++ b/.run/[author] all.run.xml @@ -0,0 +1,30 @@ + + + + + + + + \ No newline at end of file diff --git a/.run/[author] bundle.run.xml b/.run/[author] bundle.run.xml new file mode 100644 index 00000000..54e7c556 --- /dev/null +++ b/.run/[author] bundle.run.xml @@ -0,0 +1,30 @@ + + + + + + + + \ No newline at end of file diff --git a/.run/[author] ui.apps.run.xml b/.run/[author] ui.apps.run.xml new file mode 100644 index 00000000..8e599507 --- /dev/null +++ b/.run/[author] ui.apps.run.xml @@ -0,0 +1,30 @@ + + + + + + + + \ No newline at end of file diff --git a/.run/[author] ui.config.run.xml b/.run/[author] ui.config.run.xml new file mode 100644 index 00000000..a6f93f33 --- /dev/null +++ b/.run/[author] ui.config.run.xml @@ -0,0 +1,30 @@ + + + + + + + + \ No newline at end of file diff --git a/.run/[author] ui.content.run.xml b/.run/[author] ui.content.run.xml new file mode 100644 index 00000000..572cbbd9 --- /dev/null +++ b/.run/[author] ui.content.run.xml @@ -0,0 +1,30 @@ + + + + + + + + \ No newline at end of file diff --git a/.run/[publish] aem-groovy-console.run.xml b/.run/[publish] aem-groovy-console.run.xml new file mode 100644 index 00000000..2c93f5be --- /dev/null +++ b/.run/[publish] aem-groovy-console.run.xml @@ -0,0 +1,30 @@ + + + + + + + + \ No newline at end of file diff --git a/.run/[publish] all.run.xml b/.run/[publish] all.run.xml new file mode 100644 index 00000000..5b1b1be7 --- /dev/null +++ b/.run/[publish] all.run.xml @@ -0,0 +1,30 @@ + + + + + + + + \ No newline at end of file diff --git a/.run/[publish] bundle.run.xml b/.run/[publish] bundle.run.xml new file mode 100644 index 00000000..6e502c8b --- /dev/null +++ b/.run/[publish] bundle.run.xml @@ -0,0 +1,30 @@ + + + + + + + + \ No newline at end of file diff --git a/.run/[publish] ui.apps.run.xml b/.run/[publish] ui.apps.run.xml new file mode 100644 index 00000000..ea1ebfbb --- /dev/null +++ b/.run/[publish] ui.apps.run.xml @@ -0,0 +1,30 @@ + + + + + + + + \ No newline at end of file diff --git a/.run/[publish] ui.config.run.xml b/.run/[publish] ui.config.run.xml new file mode 100644 index 00000000..85bce355 --- /dev/null +++ b/.run/[publish] ui.config.run.xml @@ -0,0 +1,30 @@ + + + + + + + + \ No newline at end of file diff --git a/.run/[publish] ui.content.run.xml b/.run/[publish] ui.content.run.xml new file mode 100644 index 00000000..5d578c07 --- /dev/null +++ b/.run/[publish] ui.content.run.xml @@ -0,0 +1,30 @@ + + + + + + + + \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..e442e7e7 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,31 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [18.0.0] - 2022-31-01 + +### Added + +- Merged [aem-groovy-extension](https://github.com/icfnext/aem-groovy-extension) into this project: [#10](https://github.com/orbinson/aem-groovy-console/pull/10) +- Execute scripts on all publish instances from author environment: [#1](https://github.com/orbinson/aem-groovy-console/pull/1) +- Add xpathQuery helper method: [#1](https://github.com/orbinson/aem-groovy-console/pull/1) +- Add sql2Query helper method: [#24](https://github.com/orbinson/aem-groovy-console/pull/24) + +### Changed + +- Enhance project structure for cloud readiness: [#1](https://github.com/orbinson/aem-groovy-console/pull/1) +- Minimum supported version AEM 6.5.10: [#11](https://github.com/orbinson/aem-groovy-console/pull/11) +- Update documentation links: [#18](https://github.com/orbinson/aem-groovy-console/pull/18) + +### Fixed + +- Fix datatables error dialog: [#9](https://github.com/orbinson/aem-groovy-console/pull/9) + +## [17.0.0] - 2021-01-12 + +- Last version released by [CID15](https://github.com/CID15/aem-groovy-console) diff --git a/README.md b/README.md index ce04a178..30166583 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,12 @@ # AEM Groovy Console -[CID 15](https://www.cid15.org) - ## Overview -The AEM Groovy Console provides an interface for running [Groovy](http://www.groovy-lang.org/) scripts in Adobe Experience Manager. Scripts can be created to manipulate content in the JCR, call OSGi services, or execute arbitrary code using the AEM, Sling, or JCR APIs. After installing the package in AEM (instructions below), see the [console page](http://localhost:4502/groovyconsole) for documentation on the available bindings and methods. Sample scripts are included in the package for reference. +The AEM Groovy Console provides an interface for running [Groovy](http://www.groovy-lang.org/) scripts in Adobe +Experience Manager. Scripts can be created to manipulate content in the JCR, call OSGi services, or execute arbitrary +code using the AEM, Sling, or JCR APIs. After installing the package in AEM (instructions below), see +the [console page](http://localhost:4502/groovyconsole) for documentation on the available bindings and methods. Sample +scripts are included in the package for reference. ![Screenshot](src/site/screenshot.png) @@ -15,21 +17,13 @@ The AEM Groovy Console provides an interface for running [Groovy](http://www.gro ## Compatibility -Groovy Console Version(s) | AEM Version(s) ------------- | ------------- -17.x.x | AEM Cloud -15.x.x, 14.x.x, 13.x.x | 6.3, 6.4, 6.5 -12.x.x | 6.4 -11.x.x | 6.3 -10.x.x, 9.x.x | 6.2 -8.x.x | 6.1 -7.x.x | 6.0 -6.x.x, 5.x.x | 5.6 (CQ) -3.x.x | 5.5, 5.4 (CQ) +Supported AEM versions are AEM 6.5.10+ and AEM as a Cloud Service latest SDK version. +To install the AEM Groovy Console on older AEM versions check the original project [aem-groovy-console](https://github.com/CID15/aem-groovy-console) ## Installation -1. [Download the console package](https://github.com/cid15/aem-groovy-console/releases/download/17.0.0/aem-groovy-console-all-17.0.0.zip). For previous versions, tags can be checked out from GitHub and built directly from the source (e.g. `mvn install`). +1. [Download the console package](https://github.com/orbinson/aem-groovy-console/releases/download/18.0.0/aem-groovy-console-all-18.0.0.zip). + For previous versions, tags can be checked out from GitHub and built directly from the source (e.g. `mvn install`). 2. [Verify](http://localhost:4502/groovyconsole) the installation. @@ -37,58 +31,75 @@ Additional build profiles may be added in the project's `pom.xml` to support dep ## Building From Source -To build and install the latest development version of the Groovy Console (or if you've made source modifications), run the following Maven command. +To build and install the latest development version of the Groovy Console (or if you've made source modifications), run +the following Maven command. mvn install -P local ## OSGi Configuration -Navigate to the [OSGi console configuration page](http://localhost:4502/system/console/configMgr) and select the **Groovy Console Configuration Service**. +Navigate to the [OSGi console configuration page](http://localhost:4502/system/console/configMgr) and select the * +*Groovy Console Configuration Service**. -Property | Description | Default Value ------------- | ------------- | ---------- -Email Enabled? | Check to enable email notification on completion of script execution. | `false` -Email Recipients | Email addresses to receive notification. | `[]` -Script Execution Allowed Groups | List of group names that are authorized to use the console. By default, only the 'admin' user has permission to execute scripts. | `[]` -Scheduled Jobs Allowed Groups | List of group names that are authorized to schedule jobs. By default, only the 'admin' user has permission to schedule jobs. | `[]` -Audit Disabled? | Disables auditing of script execution history. | `false` -Display All Audit Records? | If enabled, all audit records (including records for other users) will be displayed in the console history. | `false` -Thread Timeout | Time in seconds that scripts are allowed to execute before being interrupted. If 0, no timeout is enforced. | 0 + Property | Description | Default Value +---------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|--------------- + Email Enabled? | Check to enable email notification on completion of script execution. | `false` + Email Recipients | Email addresses to receive notification. | `[]` + Script Execution Allowed Groups | List of group names that are authorized to use the console. By default, only the 'admin' user has permission to execute scripts. | `[]` + Scheduled Jobs Allowed Groups | List of group names that are authorized to schedule jobs. By default, only the 'admin' user has permission to schedule jobs. | `[]` + Audit Disabled? | Disables auditing of script execution history. | `false` + Display All Audit Records? | If enabled, all audit records (including records for other users) will be displayed in the console history. | `false` + Thread Timeout | Time in seconds that scripts are allowed to execute before being interrupted. If 0, no timeout is enforced. | 0 ## Batch Script Execution -Saved scripts can be remotely executed by sending a POST request to the console servlet with either the `scriptPath` or `scriptPaths` query parameter. +Saved scripts can be remotely executed by sending a POST request to the console servlet with either the `scriptPath` +or `scriptPaths` query parameter. ### Single Script - curl -d "scriptPath=/var/groovyconsole/scripts/samples/JcrSearch.groovy" -X POST -u admin:admin http://localhost:4502/bin/groovyconsole/post.json + curl -d "scriptPath=/conf/groovyconsole/scripts/samples/JcrSearch.groovy" -X POST -u admin:admin http://localhost:4502/bin/groovyconsole/post.json ### Multiple Scripts - curl -d "scriptPaths=/var/groovyconsole/scripts/samples/JcrSearch.groovy&scriptPaths=/var/groovyconsole/scripts/samples/FulltextQuery.groovy" -X POST -u admin:admin http://localhost:4502/bin/groovyconsole/post.json + curl -d "scriptPaths=/conf/groovyconsole/scripts/samples/JcrSearch.groovy&scriptPaths=/conf/groovyconsole/scripts/samples/FulltextQuery.groovy" -X POST -u admin:admin http://localhost:4502/bin/groovyconsole/post.json ## Extensions -The Groovy Console provides extension hooks to further customize script execution. The console provides an API containing extension provider interfaces that can be implemented as OSGi services in any bundle deployed to an AEM instance. See the default extension providers in the `org.cid15.aem.groovy.console.extension.impl` package for examples of how a bundle can implement these services to supply additional script bindings, compilation customizers, metaclasses, and star imports. +The Groovy Console provides extension hooks to further customize script execution. The console provides an API +containing extension provider interfaces that can be implemented as OSGi services in any bundle deployed to an AEM +instance. See the default extension providers in the `be.orbinson.aem.groovy.console.extension.impl` package for +examples of how a bundle can implement these services to supply additional script bindings, compilation customizers, +metaclasses, and star imports. -Service Interface | Description ------------- | ------------- -`org.cid15.aem.groovy.console.api.BindingExtensionProvider` | Customize the bindings that are provided for each script execution. -`org.cid15.aem.groovy.console.api.CompilationCustomizerExtensionProvider` | Restrict language features (via blacklist or whitelist) or provide AST transformations within the Groovy script compilation. -`org.cid15.aem.groovy.console.api.ScriptMetaClassExtensionProvider` | Add runtime metaclasses (i.e. new methods) to the underlying script class. -`org.cid15.aem.groovy.console.api.StarImportExtensionProvider` | Supply additional star imports that are added to the compiler configuration for each script execution. + Service Interface | Description +------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------ + `be.orbinson.aem.groovy.console.api.BindingExtensionProvider` | Customize the bindings that are provided for each script execution. + `be.orbinson.aem.groovy.console.api.CompilationCustomizerExtensionProvider` | Restrict language features (via blacklist or whitelist) or provide AST transformations within the Groovy script compilation. + `be.orbinson.aem.groovy.console.api.ScriptMetaClassExtensionProvider` | Add runtime metaclasses (i.e. new methods) to the underlying script class. + `be.orbinson.aem.groovy.console.api.StarImportExtensionProvider` | Supply additional star imports that are added to the compiler configuration for each script execution. ## Notifications -To provide custom notifications for script executions, bundles may implement the `org.cid15.aem.groovy.console.notification.NotificationService` interface (see the `org.cid15.aem.groovy.console.notification.impl.EmailNotificationService` class for an example). These services will be dynamically bound by the Groovy Console service and all registered notification services will be called for each script execution. +To provide custom notifications for script executions, bundles may implement +the `be.orbinson.aem.groovy.console.notification.NotificationService` interface (see +the `be.orbinson.aem.groovy.console.notification.impl.EmailNotificationService` class for an example). These services will +be dynamically bound by the Groovy Console service and all registered notification services will be called for each +script execution. ## Scheduler -The Scheduler allows for immediate (asynchronous) or Cron-based script execution. Scripts are executed as [Sling Jobs](https://sling.apache.org/documentation/bundles/apache-sling-eventing-and-job-handling.html) and are audited in the same manner as scripts executed in the console. +The Scheduler allows for immediate (asynchronous) or Cron-based script execution. Scripts are executed +as [Sling Jobs](https://sling.apache.org/documentation/bundles/apache-sling-eventing-and-job-handling.html) and are +audited in the same manner as scripts executed in the console. ### Scheduled Job Event Handling -Bundles may implement services extending `org.cid15.aem.groovy.console.job.event.AbstractGroovyConsoleScheduledJobEventHandler` to provide additional post-processing or notifications for completed Groovy Console jobs. See `org.cid15.aem.groovy.console.job.event.DefaultGroovyConsoleEmailNotificationEventHandler` for an example of the required annotations to register a custom event handler. +Bundles may implement services +extending `be.orbinson.aem.groovy.console.job.event.AbstractGroovyConsoleScheduledJobEventHandler` to provide +additional post-processing or notifications for completed Groovy Console jobs. +See `be.orbinson.aem.groovy.console.job.event.DefaultGroovyConsoleEmailNotificationEventHandler` for an example of the +required annotations to register a custom event handler. ## Sample Scripts @@ -96,4 +107,10 @@ Sample scripts can be found in the `src/main/scripts` directory. ## Versioning -Follows [Semantic Versioning](http://semver.org/) guidelines. \ No newline at end of file +Follows [Semantic Versioning](http://semver.org/) guidelines. + +## Kudos + +Kudos to [ICF Next](https://github.com/icfnext/aem-groovy-console) +and [CID 15](https://github.com/CID15/aem-groovy-console) for developing this plugin. We forked this plugin because the +maintenance of the plugins seems to have stopped. diff --git a/all/pom.xml b/all/pom.xml index 0a3a32dc..0ba2521e 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -4,9 +4,9 @@ 4.0.0 - org.cid15.aem.groovy.console + be.orbinson.aem aem-groovy-console - 17.0.0 + 18.0.0 aem-groovy-console-all @@ -15,6 +15,18 @@ + + com.adobe.aem + aemanalyser-maven-plugin + + + aem-analyser + + project-analyse + + + + org.apache.jackrabbit filevault-package-maven-plugin @@ -25,8 +37,6 @@ all - - true org.codehaus.groovy @@ -34,29 +44,24 @@ /apps/aem-groovy-console-packages/content/install - com.icfolson.aem.groovy.extension - aem-groovy-extension-bundle - /apps/aem-groovy-console-packages/content/install - - - org.cid15.aem.groovy.console + be.orbinson.aem aem-groovy-console-bundle /apps/aem-groovy-console-packages/application/install - org.cid15.aem.groovy.console + be.orbinson.aem aem-groovy-console-ui.apps zip /apps/aem-groovy-console-packages/application/install - org.cid15.aem.groovy.console + be.orbinson.aem aem-groovy-console-ui.config zip /apps/aem-groovy-console-packages/application/install - org.cid15.aem.groovy.console + be.orbinson.aem aem-groovy-console-ui.content zip /apps/aem-groovy-console-packages/content/install @@ -65,13 +70,9 @@ - com.day.jcr.vault - content-package-maven-plugin + io.wcm.maven.plugins + wcmio-content-package-maven-plugin true - - true - true - maven-clean-plugin @@ -98,8 +99,8 @@ - com.day.jcr.vault - content-package-maven-plugin + io.wcm.maven.plugins + wcmio-content-package-maven-plugin install-package @@ -107,8 +108,7 @@ install - http://${aem.host}:${aem.port}/crx/packmgr/service.jsp - true + http://${aem.host}:${aem.port}/crx/packmgr/service.jsp @@ -124,8 +124,8 @@ - com.day.jcr.vault - content-package-maven-plugin + io.wcm.maven.plugins + wcmio-content-package-maven-plugin install-package @@ -157,8 +157,8 @@ - com.day.jcr.vault - content-package-maven-plugin + io.wcm.maven.plugins + wcmio-content-package-maven-plugin install-package-publish @@ -166,8 +166,7 @@ install - http://${aem.publish.host}:${aem.publish.port}/crx/packmgr/service.jsp - true + http://${aem.publish.host}:${aem.publish.port}/crx/packmgr/service.jsp @@ -187,24 +186,24 @@ aem-groovy-extension-bundle - org.cid15.aem.groovy.console + be.orbinson.aem aem-groovy-console-bundle ${project.version} - org.cid15.aem.groovy.console + be.orbinson.aem aem-groovy-console-ui.apps ${project.version} zip - org.cid15.aem.groovy.console + be.orbinson.aem aem-groovy-console-ui.config ${project.version} zip - org.cid15.aem.groovy.console + be.orbinson.aem aem-groovy-console-ui.content ${project.version} zip diff --git a/bundle/pom.xml b/bundle/pom.xml index 07898a7f..14c950bd 100644 --- a/bundle/pom.xml +++ b/bundle/pom.xml @@ -6,9 +6,9 @@ 4.0.0 - org.cid15.aem.groovy.console + be.orbinson.aem aem-groovy-console - 17.0.0 + 18.0.0 aem-groovy-console-bundle @@ -56,8 +56,8 @@ ${project.artifactId} ${project.name} ${project.organization.name} - !*.impl,org.cid15.aem.groovy.console.* - org.cid15.aem.groovy.console.components + !*.impl,be.orbinson.aem.groovy.console.* + be.orbinson.aem.groovy.console.components * @@ -66,35 +66,38 @@ maven-surefire-plugin - maven-assembly-plugin - 2.3 + org.apache.maven.plugins + maven-source-plugin + 3.2.1 - javadoc - deploy + attach-sources - single + jar-no-fork - - - src/main/assembly/javadoc.xml - - - maven-source-plugin - 2.2.1 + org.apache.maven.plugins + maven-javadoc-plugin + 3.4.1 + + 8 + - deploy + attach-javadocs jar + + org.apache.sling + sling-maven-plugin + @@ -201,14 +204,54 @@ - com.icfolson.aem.prosper - prosper + org.junit.jupiter + junit-jupiter + test - - - com.adobe.aem - aem-sdk-api + io.wcm + io.wcm.testing.aem-mock.junit5 + test + + + org.mockito + mockito-inline + test + + + org.mockito + mockito-junit-jupiter + test + + + org.apache.sling + org.apache.sling.testing.sling-mock-oak + test + + + + on-prem + + true + + + + com.adobe.aem + uber-jar + + + + + + cloud + + + com.adobe.aem + aem-sdk-api + + + + diff --git a/bundle/src/main/assembly/javadoc.xml b/bundle/src/main/assembly/javadoc.xml deleted file mode 100644 index 1404a6a9..00000000 --- a/bundle/src/main/assembly/javadoc.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - javadoc - - jar - - false - - - ${basedir}/src/main/javadoc/README - - - \ No newline at end of file diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/GroovyConsoleService.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/GroovyConsoleService.groovy similarity index 70% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/GroovyConsoleService.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/GroovyConsoleService.groovy index 7717a7e6..4ee96a1b 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/GroovyConsoleService.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/GroovyConsoleService.groovy @@ -1,11 +1,11 @@ -package org.cid15.aem.groovy.console +package be.orbinson.aem.groovy.console -import org.cid15.aem.groovy.console.api.ActiveJob -import org.cid15.aem.groovy.console.api.JobProperties -import org.cid15.aem.groovy.console.api.context.ScriptContext -import org.cid15.aem.groovy.console.api.context.ScriptData -import org.cid15.aem.groovy.console.response.RunScriptResponse -import org.cid15.aem.groovy.console.response.SaveScriptResponse +import be.orbinson.aem.groovy.console.api.ActiveJob +import be.orbinson.aem.groovy.console.api.JobProperties +import be.orbinson.aem.groovy.console.api.context.ScriptContext +import be.orbinson.aem.groovy.console.api.context.ScriptData +import be.orbinson.aem.groovy.console.response.RunScriptResponse +import be.orbinson.aem.groovy.console.response.SaveScriptResponse /** * Service for executing and saving Groovy scripts. diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/ActiveJob.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/ActiveJob.groovy similarity index 78% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/api/ActiveJob.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/ActiveJob.groovy index 445e023b..89dd3892 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/ActiveJob.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/ActiveJob.groovy @@ -1,10 +1,10 @@ -package org.cid15.aem.groovy.console.api +package be.orbinson.aem.groovy.console.api -import org.cid15.aem.groovy.console.utils.GroovyScriptUtils +import be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants +import be.orbinson.aem.groovy.console.utils.GroovyScriptUtils import groovy.transform.Memoized import groovy.transform.TupleConstructor import org.apache.sling.event.jobs.Job -import org.cid15.aem.groovy.console.constants.GroovyConsoleConstants @TupleConstructor class ActiveJob { diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/BindingExtensionProvider.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/BindingExtensionProvider.groovy similarity index 83% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/api/BindingExtensionProvider.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/BindingExtensionProvider.groovy index df553373..b4544d1f 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/BindingExtensionProvider.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/BindingExtensionProvider.groovy @@ -1,6 +1,6 @@ -package org.cid15.aem.groovy.console.api +package be.orbinson.aem.groovy.console.api -import org.cid15.aem.groovy.console.api.context.ScriptContext +import be.orbinson.aem.groovy.console.api.context.ScriptContext /** * Services may implement this interface to supply additional binding values for Groovy script executions. diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/BindingVariable.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/BindingVariable.groovy similarity index 96% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/api/BindingVariable.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/BindingVariable.groovy index 77b03c53..5b5e5e77 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/BindingVariable.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/BindingVariable.groovy @@ -1,4 +1,4 @@ -package org.cid15.aem.groovy.console.api +package be.orbinson.aem.groovy.console.api import groovy.transform.ToString diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/CompilationCustomizerExtensionProvider.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/CompilationCustomizerExtensionProvider.groovy similarity index 91% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/api/CompilationCustomizerExtensionProvider.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/CompilationCustomizerExtensionProvider.groovy index d1e73ca9..6b192c5b 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/CompilationCustomizerExtensionProvider.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/CompilationCustomizerExtensionProvider.groovy @@ -1,4 +1,4 @@ -package org.cid15.aem.groovy.console.api +package be.orbinson.aem.groovy.console.api import org.codehaus.groovy.control.customizers.CompilationCustomizer diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/JobProperties.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/JobProperties.groovy similarity index 63% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/api/JobProperties.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/JobProperties.groovy index 0841e53c..31aaf33f 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/JobProperties.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/JobProperties.groovy @@ -1,4 +1,4 @@ -package org.cid15.aem.groovy.console.api +package be.orbinson.aem.groovy.console.api import com.google.common.collect.ImmutableSet import groovy.transform.TupleConstructor @@ -6,25 +6,25 @@ import org.apache.sling.api.SlingHttpServletRequest import org.apache.sling.api.resource.ValueMap import org.apache.sling.event.jobs.Job -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.CRON_EXPRESSION -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.DATA -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.DATE_CREATED -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.EMAIL_TO -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.JOB_DESCRIPTION -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.JOB_PROPERTIES -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.JOB_TITLE -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.MEDIA_TYPE -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.SCHEDULED_JOB_ID -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.SCRIPT +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.CRON_EXPRESSION +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.DATA +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.DATE_CREATED +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.EMAIL_TO +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.JOB_DESCRIPTION +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.JOB_PROPERTIES +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.JOB_TITLE +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.MEDIA_TYPE +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.SCHEDULED_JOB_ID +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.SCRIPT @TupleConstructor class JobProperties { private static final Set ALL_JOB_PROPERTIES = new ImmutableSet.Builder() - .addAll(JOB_PROPERTIES) - .add(DATE_CREATED) - .add(SCHEDULED_JOB_ID) - .build() + .addAll(JOB_PROPERTIES) + .add(DATE_CREATED) + .add(SCHEDULED_JOB_ID) + .build() Map properties @@ -43,9 +43,9 @@ class JobProperties { def properties = [:] as Map job.propertyNames.findAll { propertyName -> ALL_JOB_PROPERTIES.contains(propertyName) } - .each { propertyName -> - properties[propertyName] = job.getProperty(propertyName) - } + .each { propertyName -> + properties[propertyName] = job.getProperty(propertyName) + } new JobProperties(properties) } diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/ScriptMetaClassExtensionProvider.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/ScriptMetaClassExtensionProvider.groovy similarity index 81% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/api/ScriptMetaClassExtensionProvider.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/ScriptMetaClassExtensionProvider.groovy index 50b15e42..8d2895b1 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/ScriptMetaClassExtensionProvider.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/ScriptMetaClassExtensionProvider.groovy @@ -1,6 +1,6 @@ -package org.cid15.aem.groovy.console.api +package be.orbinson.aem.groovy.console.api -import org.cid15.aem.groovy.console.api.context.ScriptContext +import be.orbinson.aem.groovy.console.api.context.ScriptContext /** * Services may implement this interface to supply additional metamethods to apply to the Script metaclass. diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/StarImport.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/StarImport.groovy similarity index 95% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/api/StarImport.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/StarImport.groovy index 421cf630..8c8505d5 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/StarImport.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/StarImport.groovy @@ -1,4 +1,4 @@ -package org.cid15.aem.groovy.console.api +package be.orbinson.aem.groovy.console.api import groovy.transform.Sortable import groovy.transform.ToString diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/StarImportExtensionProvider.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/StarImportExtensionProvider.groovy similarity index 91% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/api/StarImportExtensionProvider.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/StarImportExtensionProvider.groovy index 02697201..e8f345a7 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/StarImportExtensionProvider.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/StarImportExtensionProvider.groovy @@ -1,4 +1,4 @@ -package org.cid15.aem.groovy.console.api +package be.orbinson.aem.groovy.console.api /** * Services may implement this interface to supply additional star imports to the compiler configuration for Groovy diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/context/JobScriptContext.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/context/JobScriptContext.groovy similarity index 68% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/api/context/JobScriptContext.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/context/JobScriptContext.groovy index 23608928..c3b1a50c 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/context/JobScriptContext.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/context/JobScriptContext.groovy @@ -1,6 +1,6 @@ -package org.cid15.aem.groovy.console.api.context +package be.orbinson.aem.groovy.console.api.context -import org.cid15.aem.groovy.console.api.JobProperties +import be.orbinson.aem.groovy.console.api.JobProperties /** * Script context for scheduled jobs. diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/context/ScriptContext.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/context/ScriptContext.groovy similarity index 94% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/api/context/ScriptContext.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/context/ScriptContext.groovy index a5d5c1c5..6e22af8f 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/context/ScriptContext.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/context/ScriptContext.groovy @@ -1,4 +1,4 @@ -package org.cid15.aem.groovy.console.api.context +package be.orbinson.aem.groovy.console.api.context import org.apache.sling.api.resource.ResourceResolver diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/context/ScriptData.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/context/ScriptData.groovy similarity index 90% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/api/context/ScriptData.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/context/ScriptData.groovy index 3c67893d..5708548d 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/context/ScriptData.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/context/ScriptData.groovy @@ -1,4 +1,4 @@ -package org.cid15.aem.groovy.console.api.context +package be.orbinson.aem.groovy.console.api.context import org.apache.sling.api.resource.ResourceResolver diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/context/ServletScriptContext.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/context/ServletScriptContext.groovy similarity index 90% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/api/context/ServletScriptContext.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/context/ServletScriptContext.groovy index 4bbfc512..3d644ab3 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/context/ServletScriptContext.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/context/ServletScriptContext.groovy @@ -1,4 +1,4 @@ -package org.cid15.aem.groovy.console.api.context +package be.orbinson.aem.groovy.console.api.context import org.apache.sling.api.SlingHttpServletRequest import org.apache.sling.api.SlingHttpServletResponse diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/impl/RequestScriptContext.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/impl/RequestScriptContext.groovy similarity index 79% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/api/impl/RequestScriptContext.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/impl/RequestScriptContext.groovy index 2eafc844..a67cb792 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/impl/RequestScriptContext.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/impl/RequestScriptContext.groovy @@ -1,12 +1,12 @@ -package org.cid15.aem.groovy.console.api.impl +package be.orbinson.aem.groovy.console.api.impl +import be.orbinson.aem.groovy.console.api.context.ServletScriptContext import groovy.transform.TupleConstructor import org.apache.sling.api.SlingHttpServletRequest import org.apache.sling.api.SlingHttpServletResponse import org.apache.sling.api.resource.ResourceResolver -import org.cid15.aem.groovy.console.api.context.ServletScriptContext -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.DATA +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.DATA /** * Script context for request-based (i.e. via the console) script executions. diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/impl/RequestScriptData.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/impl/RequestScriptData.groovy similarity index 61% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/api/impl/RequestScriptData.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/impl/RequestScriptData.groovy index 15163cad..94bddf52 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/impl/RequestScriptData.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/impl/RequestScriptData.groovy @@ -1,13 +1,13 @@ -package org.cid15.aem.groovy.console.api.impl +package be.orbinson.aem.groovy.console.api.impl +import be.orbinson.aem.groovy.console.api.context.ScriptData import groovy.transform.TupleConstructor import org.apache.sling.api.SlingHttpServletRequest import org.apache.sling.api.resource.ResourceResolver -import org.cid15.aem.groovy.console.api.context.ScriptData -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.EXTENSION_GROOVY -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.FILE_NAME -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.SCRIPT +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.EXTENSION_GROOVY +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.FILE_NAME +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.SCRIPT @TupleConstructor class RequestScriptData implements ScriptData { diff --git a/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/impl/ResourceScriptContext.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/impl/ResourceScriptContext.groovy new file mode 100644 index 00000000..7eb75775 --- /dev/null +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/impl/ResourceScriptContext.groovy @@ -0,0 +1,23 @@ +package be.orbinson.aem.groovy.console.api.impl + +import be.orbinson.aem.groovy.console.api.context.ScriptContext +import groovy.transform.TupleConstructor +import org.apache.sling.api.resource.ResourceResolver + +@TupleConstructor +class ResourceScriptContext implements ScriptContext { + ResourceResolver resourceResolver + + ByteArrayOutputStream outputStream + + PrintStream printStream + + String script + + String data + + @Override + public String getUserId() { + return resourceResolver.userID + } +} diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/impl/ScheduledJobScriptContext.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/impl/ScheduledJobScriptContext.groovy similarity index 76% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/api/impl/ScheduledJobScriptContext.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/impl/ScheduledJobScriptContext.groovy index 227854e8..8e1a8259 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/api/impl/ScheduledJobScriptContext.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/api/impl/ScheduledJobScriptContext.groovy @@ -1,9 +1,9 @@ -package org.cid15.aem.groovy.console.api.impl +package be.orbinson.aem.groovy.console.api.impl +import be.orbinson.aem.groovy.console.api.JobProperties +import be.orbinson.aem.groovy.console.api.context.JobScriptContext import groovy.transform.TupleConstructor import org.apache.sling.api.resource.ResourceResolver -import org.cid15.aem.groovy.console.api.JobProperties -import org.cid15.aem.groovy.console.api.context.JobScriptContext @TupleConstructor class ScheduledJobScriptContext implements JobScriptContext { diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/audit/AuditRecord.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/audit/AuditRecord.groovy similarity index 86% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/audit/AuditRecord.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/audit/AuditRecord.groovy index c92b249d..4472868f 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/audit/AuditRecord.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/audit/AuditRecord.groovy @@ -1,10 +1,10 @@ -package org.cid15.aem.groovy.console.audit +package be.orbinson.aem.groovy.console.audit +import be.orbinson.aem.groovy.console.response.RunScriptResponse +import be.orbinson.aem.groovy.console.response.impl.DefaultRunScriptResponse import com.day.text.Text import groovy.transform.ToString import org.apache.sling.api.resource.Resource -import org.cid15.aem.groovy.console.response.RunScriptResponse -import org.cid15.aem.groovy.console.response.impl.DefaultRunScriptResponse @ToString(includePackage = false, includes = ["path"]) class AuditRecord implements RunScriptResponse { diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/audit/AuditService.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/audit/AuditService.groovy similarity index 95% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/audit/AuditService.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/audit/AuditService.groovy index d1b7088e..85455fe5 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/audit/AuditService.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/audit/AuditService.groovy @@ -1,6 +1,6 @@ -package org.cid15.aem.groovy.console.audit +package be.orbinson.aem.groovy.console.audit -import org.cid15.aem.groovy.console.response.RunScriptResponse +import be.orbinson.aem.groovy.console.response.RunScriptResponse interface AuditService { diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/audit/impl/DefaultAuditService.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/audit/impl/DefaultAuditService.groovy similarity index 76% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/audit/impl/DefaultAuditService.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/audit/impl/DefaultAuditService.groovy index 025803b0..a56adbe7 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/audit/impl/DefaultAuditService.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/audit/impl/DefaultAuditService.groovy @@ -1,16 +1,17 @@ -package org.cid15.aem.groovy.console.audit.impl - +package be.orbinson.aem.groovy.console.audit.impl + +import be.orbinson.aem.groovy.console.audit.AuditRecord +import be.orbinson.aem.groovy.console.audit.AuditService +import be.orbinson.aem.groovy.console.configuration.ConfigurationService +import be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants +import be.orbinson.aem.groovy.console.response.RunScriptResponse +import com.day.cq.commons.jcr.JcrConstants import com.day.cq.commons.jcr.JcrUtil -import org.cid15.aem.groovy.console.audit.AuditService -import org.cid15.aem.groovy.console.configuration.ConfigurationService import groovy.transform.Synchronized import groovy.util.logging.Slf4j import org.apache.sling.api.resource.PersistenceException import org.apache.sling.api.resource.ResourceResolver import org.apache.sling.api.resource.ResourceResolverFactory -import org.cid15.aem.groovy.console.audit.AuditRecord -import org.cid15.aem.groovy.console.constants.GroovyConsoleConstants -import org.cid15.aem.groovy.console.response.RunScriptResponse import org.osgi.service.component.annotations.Activate import org.osgi.service.component.annotations.Component import org.osgi.service.component.annotations.Reference @@ -19,20 +20,9 @@ import javax.jcr.Node import javax.jcr.RepositoryException import javax.jcr.Session +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.* import static com.day.cq.commons.jcr.JcrConstants.MIX_CREATED import static com.day.cq.commons.jcr.JcrConstants.NT_UNSTRUCTURED -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.AUDIT_JOB_PROPERTIES -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.AUDIT_NODE_NAME -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.AUDIT_PATH -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.AUDIT_RECORD_NODE_PREFIX -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.DATA -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.EXCEPTION_STACK_TRACE -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.JOB_ID -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.OUTPUT -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.PATH_CONSOLE_ROOT -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.RESULT -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.RUNNING_TIME -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.SCRIPT @Component(service = AuditService, immediate = true) @Slf4j("LOG") @@ -172,11 +162,6 @@ class DefaultAuditService implements AuditService { getAuditRecordsForDateRange(allScheduledJobAuditRecords, startDate, endDate) } - @Activate - void activate() { - checkAuditNode() - } - @Synchronized private Node addAuditRecordNode(ResourceResolver resourceResolver, String userId) { def date = Calendar.instance @@ -187,31 +172,21 @@ class DefaultAuditService implements AuditService { def adminSession = resourceResolver.adaptTo(Session) def auditRecordParentNode = JcrUtil.createPath("$AUDIT_PATH/$userId/$year/$month/$day", NT_UNSTRUCTURED, - adminSession) + adminSession) def auditRecordNode = JcrUtil.createUniqueNode(auditRecordParentNode, AUDIT_RECORD_NODE_PREFIX, NT_UNSTRUCTURED, - adminSession) + adminSession) - auditRecordNode.addMixin(MIX_CREATED) + try { + auditRecordNode.addMixin(MIX_CREATED) + } catch (e) { + // unsupported for jcr mocks + auditRecordNode.setProperty(JcrConstants.JCR_CREATED, Calendar.getInstance()) + } auditRecordNode } - private void checkAuditNode() { - withResourceResolver { ResourceResolver resourceResolver -> - def session = resourceResolver.adaptTo(Session) - def consoleRootNode = session.getNode(PATH_CONSOLE_ROOT) - - if (!consoleRootNode.hasNode(AUDIT_NODE_NAME)) { - LOG.info("audit node does not exist, adding") - - consoleRootNode.addNode(AUDIT_NODE_NAME, NT_UNSTRUCTURED) - - session.save() - } - } - } - private void setAuditRecordNodeProperties(Node auditRecordNode, RunScriptResponse response) { auditRecordNode.setProperty(SCRIPT, response.script) @@ -225,14 +200,14 @@ class DefaultAuditService implements AuditService { if (response.jobProperties) { response.jobProperties.toMap() - .findAll { entry -> AUDIT_JOB_PROPERTIES.contains(entry.key) } - .each { entry -> - if (entry.value instanceof String) { - auditRecordNode.setProperty(entry.key, entry.value as String) - } else if (entry.value instanceof Calendar) { - auditRecordNode.setProperty(entry.key, entry.value as Calendar) + .findAll { entry -> AUDIT_JOB_PROPERTIES.contains(entry.key) } + .each { entry -> + if (entry.value instanceof String) { + auditRecordNode.setProperty(entry.key, entry.value as String) + } else if (entry.value instanceof Calendar) { + auditRecordNode.setProperty(entry.key, entry.value as Calendar) + } } - } } if (response.exceptionStackTrace) { diff --git a/bundle/src/main/groovy/be/orbinson/aem/groovy/console/builders/AbstractContentBuilder.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/builders/AbstractContentBuilder.groovy new file mode 100644 index 00000000..799d5379 --- /dev/null +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/builders/AbstractContentBuilder.groovy @@ -0,0 +1,37 @@ +package be.orbinson.aem.groovy.console.builders + +import javax.jcr.Node +import javax.jcr.Session + +/** + * Base class for Page and Node builders. + */ +abstract class AbstractContentBuilder extends BuilderSupport { + + Session session + + Node currentNode + + AbstractContentBuilder(Session session, Node currentNode) { + this.session = session + this.currentNode = currentNode + } + + @Override + void nodeCompleted(parent, node) { + session.save() + + currentNode = currentNode.parent + } + + @Override + void setParent(parent, child) { + + } + + void setProperties(node, properties) { + properties.each { name, value -> + node.set(name, value) + } + } +} \ No newline at end of file diff --git a/bundle/src/main/groovy/be/orbinson/aem/groovy/console/builders/NodeBuilder.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/builders/NodeBuilder.groovy new file mode 100644 index 00000000..452ada57 --- /dev/null +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/builders/NodeBuilder.groovy @@ -0,0 +1,72 @@ +package be.orbinson.aem.groovy.console.builders + +import javax.jcr.Node +import javax.jcr.Session + +/** + * Builder for JCR content nodes. Each "node" in the syntax tree corresponds to a JCR node in the repository. A new + * JCR node is created only if there is no existing node for the current name. + * + *
+ * nodeBuilder.etc {
+ *     satirists("sling:Folder") {
+ *         bierce(firstName: "Ambrose", lastName: "Bierce", birthDate: Calendar.instance.updated(year: 1842, month: 5, date: 24))
+ *         mencken(firstName: "H.L.", lastName: "Mencken", birthDate: Calendar.instance.updated(year: 1880, month: 8, date: 12))
+ *         other("sling:Folder", "jcr:title": "Other")
+ *     }
+ * }
+ * 
+ * + *
    + *
  • A single string argument represents the node type name for the node ("satirists").
  • + *
  • A map argument uses the provided key:value pairs to set property values on the node ("bierce" and + * "mencken").
  • + *
  • Both string and map arguments will set the node type and property value(s) for the node ("other").
  • + *
+ */ +class NodeBuilder extends AbstractContentBuilder { + + NodeBuilder(Session session) { + super(session, session.rootNode) + } + + NodeBuilder(Session session, Node rootNode) { + super(session, rootNode) + } + + NodeBuilder(Session session, String rootPath) { + super(session, session.getNode(rootPath)) + } + + @Override + def createNode(name) { + currentNode = currentNode.getOrAddNode(name) + + currentNode + } + + @Override + def createNode(name, primaryNodeTypeName) { + currentNode = currentNode.getOrAddNode(name, primaryNodeTypeName) + + currentNode + } + + @Override + def createNode(name, Map properties) { + currentNode = currentNode.getOrAddNode(name) + + setProperties(currentNode, properties) + + currentNode + } + + @Override + def createNode(name, Map properties, primaryNodeTypeName) { + currentNode = createNode(name, primaryNodeTypeName) + + setProperties(currentNode, properties) + + currentNode + } +} \ No newline at end of file diff --git a/bundle/src/main/groovy/be/orbinson/aem/groovy/console/builders/PageBuilder.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/builders/PageBuilder.groovy new file mode 100644 index 00000000..600e7064 --- /dev/null +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/builders/PageBuilder.groovy @@ -0,0 +1,121 @@ +package be.orbinson.aem.groovy.console.builders + +import com.day.cq.commons.jcr.JcrConstants +import com.day.cq.wcm.api.NameConstants +import com.day.cq.wcm.api.Page + +import javax.jcr.Node +import javax.jcr.Session + +/** + * Builder for AEM pages. Each "node" in the syntax tree corresponds to a node, + * unless the node is a descendant of a jcr:content node, in which case nodes are treated in the same + * manner as NodeBuilder. + * + *
+ * pageBuilder.content {
+ *     beer {
+ *         styles("Styles") {
+ *             "jcr:content"("jcr:lastModifiedBy": "me", "jcr:lastModified": Calendar.instance) {
+ *                 data("sling:Folder")
+ *             }
+ *             dubbel("Dubbel")
+ *             tripel("Tripel")
+ *             saison("Saison")
+ *         }
+ *         breweries("Breweries", "jcr:lastModifiedBy": "me", "jcr:lastModified": Calendar.instance)
+ *     }
+ * }
+ * 
+ * + *
    + *
  • A single string argument is used to set the page title rather than the node type ("styles").
  • + *
  • Descendants of jcr:content nodes are not created with the cq:Page type by + * default and can have their own node type specified as described for the Node builder ("data").
  • + *
  • Page properties can be passed directly as arguments on the page node without explicitly creating a + * jcr:content node first ("breweries").
  • + *
+ */ +class PageBuilder extends AbstractContentBuilder { + + private static final String NT_PAGE_CONTENT = "cq:PageContent" + + PageBuilder(Session session) { + super(session, session.rootNode) + } + + PageBuilder(Session session, Page rootPage) { + super(session, session.getNode(rootPage.path)) + } + + PageBuilder(Session session, String rootPath) { + super(session, session.getNode(rootPath)) + } + + @Override + def createNode(name) { + if (isContentNode(name)) { + currentNode = currentNode.getOrAddNode(name) + } else { + currentNode = getOrAddPage(name: name) + } + + currentNode + } + + @Override + def createNode(name, title) { + if (isContentNode(name)) { + currentNode = currentNode.getOrAddNode(name, title) + } else { + currentNode = getOrAddPage(name: name, title: title) + } + + currentNode + } + + @Override + def createNode(name, Map properties) { + if (isContentNode(name)) { + currentNode = currentNode.getOrAddNode(name) + + setProperties(currentNode, properties) + } else { + currentNode = getOrAddPage(name: name, properties: properties) + } + + currentNode + } + + @Override + def createNode(name, Map properties, value) { + if (isContentNode(name)) { + currentNode = currentNode.getOrAddNode(name, value) + + setProperties(currentNode, properties) + } else { + currentNode = getOrAddPage(name: name, title: value, properties: properties) + } + + currentNode + } + + private Node getOrAddPage(map) { + def pageNode = currentNode.getOrAddNode(map.name, NameConstants.NT_PAGE) + def contentNode = pageNode.getOrAddNode(JcrConstants.JCR_CONTENT, NT_PAGE_CONTENT) + + if (map.title) { + contentNode.set(JcrConstants.JCR_TITLE, map.title) + } + + if (map.properties) { + setProperties(contentNode, map.properties) + } + + pageNode + } + + private boolean isContentNode(name) { + name == JcrConstants.JCR_CONTENT || currentNode.path.contains(JcrConstants.JCR_CONTENT) + } +} \ No newline at end of file diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/components/AboutPanel.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/AboutPanel.groovy similarity index 80% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/components/AboutPanel.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/AboutPanel.groovy index 6fa178fd..a1c54f2d 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/components/AboutPanel.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/AboutPanel.groovy @@ -1,4 +1,4 @@ -package org.cid15.aem.groovy.console.components +package be.orbinson.aem.groovy.console.components import org.apache.sling.api.resource.Resource import org.apache.sling.models.annotations.Model diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/components/ActiveJobsPanel.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/ActiveJobsPanel.groovy similarity index 71% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/components/ActiveJobsPanel.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/ActiveJobsPanel.groovy index 5ba13b5d..f3fc3dd7 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/components/ActiveJobsPanel.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/ActiveJobsPanel.groovy @@ -1,7 +1,8 @@ -package org.cid15.aem.groovy.console.components +package be.orbinson.aem.groovy.console.components -import org.cid15.aem.groovy.console.GroovyConsoleService -import org.cid15.aem.groovy.console.api.ActiveJob + +import be.orbinson.aem.groovy.console.GroovyConsoleService +import be.orbinson.aem.groovy.console.api.ActiveJob import org.apache.sling.api.SlingHttpServletRequest import org.apache.sling.models.annotations.Model import org.apache.sling.models.annotations.injectorspecific.OSGiService diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/components/BindingsPanel.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/BindingsPanel.groovy similarity index 73% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/components/BindingsPanel.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/BindingsPanel.groovy index d09942f3..35419f0e 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/components/BindingsPanel.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/BindingsPanel.groovy @@ -1,7 +1,8 @@ -package org.cid15.aem.groovy.console.components +package be.orbinson.aem.groovy.console.components -import org.cid15.aem.groovy.console.api.BindingVariable -import org.cid15.aem.groovy.console.api.impl.RequestScriptContext +import be.orbinson.aem.groovy.console.api.BindingVariable +import be.orbinson.aem.groovy.console.api.impl.RequestScriptContext +import be.orbinson.aem.groovy.console.extension.ExtensionService import groovy.transform.Memoized import org.apache.sling.api.SlingHttpServletRequest import org.apache.sling.api.SlingHttpServletResponse @@ -9,7 +10,6 @@ import org.apache.sling.models.annotations.Model import org.apache.sling.models.annotations.injectorspecific.OSGiService import org.apache.sling.models.annotations.injectorspecific.ScriptVariable import org.apache.sling.models.annotations.injectorspecific.Self -import org.cid15.aem.groovy.console.extension.ExtensionService @Model(adaptables = SlingHttpServletRequest) class BindingsPanel { @@ -26,8 +26,8 @@ class BindingsPanel { @Memoized Map getBindingVariables() { def scriptContext = new RequestScriptContext( - request: request, - response: response + request: request, + response: response ) extensionService.getBindingVariables(scriptContext) diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/components/Body.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/Body.groovy similarity index 73% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/components/Body.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/Body.groovy index 74a475fb..3bf8f98e 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/components/Body.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/Body.groovy @@ -1,9 +1,10 @@ -package org.cid15.aem.groovy.console.components +package be.orbinson.aem.groovy.console.components -import org.cid15.aem.groovy.console.GroovyConsoleService -import org.cid15.aem.groovy.console.audit.AuditRecord -import org.cid15.aem.groovy.console.audit.AuditService -import org.cid15.aem.groovy.console.configuration.ConfigurationService + +import be.orbinson.aem.groovy.console.GroovyConsoleService +import be.orbinson.aem.groovy.console.audit.AuditRecord +import be.orbinson.aem.groovy.console.audit.AuditService +import be.orbinson.aem.groovy.console.configuration.ConfigurationService import groovy.json.JsonBuilder import org.apache.sling.api.SlingHttpServletRequest import org.apache.sling.models.annotations.Model @@ -12,8 +13,8 @@ import org.apache.sling.models.annotations.injectorspecific.Self import javax.annotation.PostConstruct -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.SCRIPT -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.USER_ID +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.SCRIPT +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.USER_ID @Model(adaptables = SlingHttpServletRequest) class Body { diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/components/HistoryPanel.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/HistoryPanel.groovy similarity index 83% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/components/HistoryPanel.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/HistoryPanel.groovy index 43bc3ed6..a4c7c929 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/components/HistoryPanel.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/HistoryPanel.groovy @@ -1,6 +1,6 @@ -package org.cid15.aem.groovy.console.components +package be.orbinson.aem.groovy.console.components -import org.cid15.aem.groovy.console.audit.AuditService +import be.orbinson.aem.groovy.console.audit.AuditService import org.apache.sling.api.SlingHttpServletRequest import org.apache.sling.models.annotations.Model import org.apache.sling.models.annotations.injectorspecific.OSGiService diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/components/ImportsPanel.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/ImportsPanel.groovy similarity index 69% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/components/ImportsPanel.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/ImportsPanel.groovy index f274fe03..1250a74c 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/components/ImportsPanel.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/ImportsPanel.groovy @@ -1,10 +1,10 @@ -package org.cid15.aem.groovy.console.components +package be.orbinson.aem.groovy.console.components -import org.cid15.aem.groovy.console.api.StarImport +import be.orbinson.aem.groovy.console.api.StarImport +import be.orbinson.aem.groovy.console.extension.ExtensionService import org.apache.sling.api.resource.Resource import org.apache.sling.models.annotations.Model import org.apache.sling.models.annotations.injectorspecific.OSGiService -import org.cid15.aem.groovy.console.extension.ExtensionService @Model(adaptables = Resource) class ImportsPanel { diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/components/Scheduler.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/Scheduler.groovy similarity index 76% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/components/Scheduler.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/Scheduler.groovy index e41d142a..4d190b9c 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/components/Scheduler.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/Scheduler.groovy @@ -1,6 +1,6 @@ -package org.cid15.aem.groovy.console.components +package be.orbinson.aem.groovy.console.components -import org.cid15.aem.groovy.console.configuration.ConfigurationService +import be.orbinson.aem.groovy.console.configuration.ConfigurationService import org.apache.sling.api.SlingHttpServletRequest import org.apache.sling.models.annotations.Model import org.apache.sling.models.annotations.injectorspecific.OSGiService diff --git a/bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/Toolbar.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/Toolbar.groovy new file mode 100644 index 00000000..1318d089 --- /dev/null +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/components/Toolbar.groovy @@ -0,0 +1,16 @@ +package be.orbinson.aem.groovy.console.components + +import be.orbinson.aem.groovy.console.configuration.ConfigurationService +import org.apache.sling.api.SlingHttpServletRequest +import org.apache.sling.models.annotations.Model +import org.apache.sling.models.annotations.injectorspecific.OSGiService + +@Model(adaptables = SlingHttpServletRequest) +class Toolbar { + @OSGiService + private ConfigurationService configurationService + + boolean isDistributedExecutionEnabled() { + configurationService.distributedExecutionEnabled + } +} diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/configuration/ConfigurationService.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/configuration/ConfigurationService.groovy similarity index 77% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/configuration/ConfigurationService.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/configuration/ConfigurationService.groovy index e79605ed..633cae1f 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/configuration/ConfigurationService.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/configuration/ConfigurationService.groovy @@ -1,4 +1,4 @@ -package org.cid15.aem.groovy.console.configuration +package be.orbinson.aem.groovy.console.configuration import org.apache.sling.api.SlingHttpServletRequest @@ -58,4 +58,18 @@ interface ConfigurationService { * @return thread timeout */ long getThreadTimeout() -} \ No newline at end of file + + /** + * Check if distributed execution is enabled. In this way scripts can be replicated and auto executed on replication. + * + * @return true is distributed execution is enabled + */ + boolean isDistributedExecutionEnabled() + + /** + * Check if the service is running on an author instance + * + * @return true if the author runmode is present + */ + boolean isAuthor() +} diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/configuration/impl/DefaultConfigurationService.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/configuration/impl/DefaultConfigurationService.groovy similarity index 79% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/configuration/impl/DefaultConfigurationService.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/configuration/impl/DefaultConfigurationService.groovy index d407bd3c..d0cc3bf7 100755 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/configuration/impl/DefaultConfigurationService.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/configuration/impl/DefaultConfigurationService.groovy @@ -1,12 +1,13 @@ -package org.cid15.aem.groovy.console.configuration.impl +package be.orbinson.aem.groovy.console.configuration.impl +import be.orbinson.aem.groovy.console.configuration.ConfigurationService import groovy.transform.Synchronized import groovy.util.logging.Slf4j import org.apache.jackrabbit.api.security.user.User import org.apache.jackrabbit.api.security.user.UserManager import org.apache.sling.api.SlingHttpServletRequest import org.apache.sling.api.resource.ResourceResolverFactory -import org.cid15.aem.groovy.console.configuration.ConfigurationService +import org.osgi.framework.BundleContext import org.osgi.service.component.annotations.Activate import org.osgi.service.component.annotations.Component import org.osgi.service.component.annotations.Modified @@ -35,6 +36,10 @@ class DefaultConfigurationService implements ConfigurationService { private long threadTimeout + private boolean distributedExecutionEnabled + + private boolean author + @Override boolean hasPermission(SlingHttpServletRequest request) { isAdminOrAllowedGroupMember(request, allowedGroups) @@ -70,10 +75,20 @@ class DefaultConfigurationService implements ConfigurationService { threadTimeout } + @Override + boolean isDistributedExecutionEnabled() { + distributedExecutionEnabled + } + + @Override + boolean isAuthor() { + return author + } + @Activate @Modified @Synchronized - void activate(ConfigurationServiceProperties properties) { + void activate(ConfigurationServiceProperties properties, BundleContext bundleContext) { emailEnabled = properties.emailEnabled() emailRecipients = (properties.emailRecipients() ?: []).findAll() as Set allowedGroups = (properties.allowedGroups() ?: []).findAll() as Set @@ -81,6 +96,10 @@ class DefaultConfigurationService implements ConfigurationService { auditDisabled = properties.auditDisabled() displayAllAuditRecords = properties.auditDisplayAll() threadTimeout = properties.threadTimeout() + distributedExecutionEnabled = properties.distributedExecutionEnabled() + if (bundleContext.getProperty("sling.run.modes") != null) { + author = bundleContext.getProperty("sling.run.modes").contains("author") + } } private boolean isAdminOrAllowedGroupMember(SlingHttpServletRequest request, Set groupIds) { diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/constants/GroovyConsoleConstants.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/constants/GroovyConsoleConstants.groovy similarity index 71% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/constants/GroovyConsoleConstants.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/constants/GroovyConsoleConstants.groovy index c0251e3e..3bf9428d 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/constants/GroovyConsoleConstants.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/constants/GroovyConsoleConstants.groovy @@ -1,15 +1,17 @@ -package org.cid15.aem.groovy.console.constants +package be.orbinson.aem.groovy.console.constants import com.google.common.base.Charsets import com.google.common.net.MediaType class GroovyConsoleConstants { - public static final String SYSTEM_USER_NAME = "groovy-console-system-user" + public static final String SYSTEM_USER_NAME = "aem-groovy-console-service" public static final String PATH_CONSOLE_ROOT = "/var/groovyconsole" - public static final String PATH_SCRIPTS_FOLDER = "$PATH_CONSOLE_ROOT/scripts" + public static final String PATH_SCRIPTS_FOLDER = "/conf/groovyconsole/scripts" + + public static final String PATH_REPLICATION_FOLDER = "/conf/groovyconsole/replication" public static final String EXTENSION_GROOVY = ".groovy" @@ -70,24 +72,24 @@ class GroovyConsoleConstants { public static final String JOB_TOPIC = "groovyconsole/job" public static final Set JOB_PROPERTIES = [ - JOB_TITLE, - JOB_DESCRIPTION, - SCRIPT, - DATA, - CRON_EXPRESSION, - EMAIL_TO, - MEDIA_TYPE + JOB_TITLE, + JOB_DESCRIPTION, + SCRIPT, + DATA, + CRON_EXPRESSION, + EMAIL_TO, + MEDIA_TYPE ] as Set // audit public static final Set AUDIT_JOB_PROPERTIES = [ - SCHEDULED_JOB_ID, - JOB_TITLE, - JOB_DESCRIPTION, - CRON_EXPRESSION, - EMAIL_TO, - MEDIA_TYPE + SCHEDULED_JOB_ID, + JOB_TITLE, + JOB_DESCRIPTION, + CRON_EXPRESSION, + EMAIL_TO, + MEDIA_TYPE ] as Set public static final String AUDIT_NODE_NAME = "audit" @@ -97,10 +99,10 @@ class GroovyConsoleConstants { public static final String AUDIT_PATH = "$PATH_CONSOLE_ROOT/$AUDIT_NODE_NAME" public static final Map MEDIA_TYPE_EXTENSIONS = [ - (MediaType.CSV_UTF_8.withoutParameters().toString()): "csv", - (MediaType.PLAIN_TEXT_UTF_8.withoutParameters().toString()): "txt", - (MediaType.HTML_UTF_8.withoutParameters().toString()): "html", - (MediaType.XML_UTF_8.withoutParameters().toString()): "xml" + (MediaType.CSV_UTF_8.withoutParameters().toString()) : "csv", + (MediaType.PLAIN_TEXT_UTF_8.withoutParameters().toString()): "txt", + (MediaType.HTML_UTF_8.withoutParameters().toString()) : "html", + (MediaType.XML_UTF_8.withoutParameters().toString()) : "xml" ] private GroovyConsoleConstants() { diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/extension/ExtensionService.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/extension/ExtensionService.groovy similarity index 57% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/extension/ExtensionService.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/extension/ExtensionService.groovy index 33ece746..90e9863f 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/extension/ExtensionService.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/extension/ExtensionService.groovy @@ -1,15 +1,15 @@ -package org.cid15.aem.groovy.console.extension +package be.orbinson.aem.groovy.console.extension -import org.cid15.aem.groovy.console.api.BindingExtensionProvider -import org.cid15.aem.groovy.console.api.CompilationCustomizerExtensionProvider -import org.cid15.aem.groovy.console.api.context.ScriptContext -import org.cid15.aem.groovy.console.api.StarImportExtensionProvider +import be.orbinson.aem.groovy.console.api.BindingExtensionProvider +import be.orbinson.aem.groovy.console.api.CompilationCustomizerExtensionProvider +import be.orbinson.aem.groovy.console.api.StarImportExtensionProvider +import be.orbinson.aem.groovy.console.api.context.ScriptContext /** * Service that dynamically binds extensions providing additional script bindings, star imports, and script metaclasses. */ interface ExtensionService extends BindingExtensionProvider, CompilationCustomizerExtensionProvider, - StarImportExtensionProvider { + StarImportExtensionProvider { /** * Get a list of all script metaclass closures for bound extensions. diff --git a/bundle/src/main/groovy/be/orbinson/aem/groovy/console/extension/impl/DefaultBindingExtensionProvider.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/extension/impl/DefaultBindingExtensionProvider.groovy new file mode 100644 index 00000000..6f60ec58 --- /dev/null +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/extension/impl/DefaultBindingExtensionProvider.groovy @@ -0,0 +1,87 @@ +package be.orbinson.aem.groovy.console.extension.impl + +import be.orbinson.aem.groovy.console.api.BindingExtensionProvider +import be.orbinson.aem.groovy.console.api.BindingVariable +import be.orbinson.aem.groovy.console.api.context.ScriptContext +import be.orbinson.aem.groovy.console.api.context.ServletScriptContext +import be.orbinson.aem.groovy.console.builders.PageBuilder +import be.orbinson.aem.groovy.console.builders.NodeBuilder +import com.day.cq.search.QueryBuilder +import com.day.cq.wcm.api.PageManager +import groovy.json.JsonException +import groovy.json.JsonSlurper +import org.apache.sling.api.SlingHttpServletRequest +import org.apache.sling.api.SlingHttpServletResponse +import org.apache.sling.api.resource.ResourceResolver +import org.osgi.framework.BundleContext +import org.osgi.service.component.annotations.Activate +import org.osgi.service.component.annotations.Component +import org.osgi.service.component.annotations.Reference +import org.slf4j.Logger +import org.slf4j.LoggerFactory + +import javax.jcr.Session + +@Component(service = BindingExtensionProvider, immediate = true) +class DefaultBindingExtensionProvider implements BindingExtensionProvider { + + @Reference + private QueryBuilder queryBuilder + + private BundleContext bundleContext + + @Override + Map getBindingVariables(ScriptContext scriptContext) { + def resourceResolver = scriptContext.resourceResolver + def session = resourceResolver.adaptTo(Session) + + def bindingVariables = [ + log : new BindingVariable(LoggerFactory.getLogger("groovyconsole"), Logger, + "http://www.slf4j.org/api/org/slf4j/Logger.html"), + session : new BindingVariable(session, Session, + "https://developer.adobe.com/experience-manager/reference-materials/spec/javax.jcr/javadocs/jcr-2.0/javax/jcr/Session.html"), + pageManager : new BindingVariable(resourceResolver.adaptTo(PageManager), PageManager), + resourceResolver: new BindingVariable(resourceResolver, ResourceResolver, + "https://sling.apache.org/apidocs/sling12/org/apache/sling/api/resource/ResourceResolver.html"), + queryBuilder : new BindingVariable(queryBuilder, QueryBuilder, + "https://developer.adobe.com/experience-manager/reference-materials/6-5/javadoc/com/day/cq/search/QueryBuilder.html"), + nodeBuilder : new BindingVariable(new NodeBuilder(session), NodeBuilder, + "http://code.digitalatolson.com/aem-groovy-extension/groovydocs/com/icfolson/aem/groovy/extension" + + "/builders/NodeBuilder.html"), + pageBuilder : new BindingVariable(new PageBuilder(session), PageBuilder, + "http://code.digitalatolson.com/aem-groovy-extension/groovydocs/com/icfolson/aem/groovy/extension" + + "/builders/PageBuilder.html"), + bundleContext : new BindingVariable(bundleContext, BundleContext, + "http://www.osgi.org/javadoc/r4v43/core/org/osgi/framework/BundleContext.html"), + out : new BindingVariable(scriptContext.printStream, PrintStream, + "https://docs.oracle.com/javase/8/docs/api/java/io/PrintStream.html") + ] + + if (scriptContext instanceof ServletScriptContext) { + bindingVariables.putAll([ + slingRequest : new BindingVariable(scriptContext.request, SlingHttpServletRequest, + "https://sling.apache.org/apidocs/sling12/org/apache/sling/api/SlingHttpServletRequest.html"), + slingResponse: new BindingVariable(scriptContext.response, SlingHttpServletResponse, + "https://sling.apache.org/apidocs/sling12/org/apache/sling/api/SlingHttpServletResponse.html") + ]) + } + + if (scriptContext.data) { + try { + def json = new JsonSlurper().parseText(scriptContext.data) + + bindingVariables["data"] = new BindingVariable(json, json.class) + } catch (JsonException ignored) { + // if data cannot be parsed as a JSON object, bind it as a String + bindingVariables["data"] = new BindingVariable(scriptContext.data, String) + } + } + + bindingVariables + } + + @Activate + void activate(BundleContext bundleContext) { + this.bundleContext = bundleContext + } +} diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/extension/impl/DefaultExtensionService.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/extension/impl/DefaultExtensionService.groovy similarity index 87% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/extension/impl/DefaultExtensionService.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/extension/impl/DefaultExtensionService.groovy index 938ab2a9..1e00f93b 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/extension/impl/DefaultExtensionService.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/extension/impl/DefaultExtensionService.groovy @@ -1,15 +1,15 @@ -package org.cid15.aem.groovy.console.extension.impl - -import org.cid15.aem.groovy.console.api.BindingExtensionProvider -import org.cid15.aem.groovy.console.api.BindingVariable -import org.cid15.aem.groovy.console.api.CompilationCustomizerExtensionProvider -import org.cid15.aem.groovy.console.api.ScriptMetaClassExtensionProvider -import org.cid15.aem.groovy.console.api.StarImport -import org.cid15.aem.groovy.console.api.StarImportExtensionProvider -import org.cid15.aem.groovy.console.api.context.ScriptContext +package be.orbinson.aem.groovy.console.extension.impl + +import be.orbinson.aem.groovy.console.api.BindingExtensionProvider +import be.orbinson.aem.groovy.console.api.BindingVariable +import be.orbinson.aem.groovy.console.api.CompilationCustomizerExtensionProvider +import be.orbinson.aem.groovy.console.api.ScriptMetaClassExtensionProvider +import be.orbinson.aem.groovy.console.api.StarImport +import be.orbinson.aem.groovy.console.api.StarImportExtensionProvider +import be.orbinson.aem.groovy.console.api.context.ScriptContext +import be.orbinson.aem.groovy.console.extension.ExtensionService import groovy.transform.Synchronized import groovy.util.logging.Slf4j -import org.cid15.aem.groovy.console.extension.ExtensionService import org.codehaus.groovy.control.customizers.CompilationCustomizer import org.codehaus.groovy.control.customizers.ImportCustomizer import org.osgi.service.component.annotations.Component @@ -30,7 +30,7 @@ class DefaultExtensionService implements ExtensionService { private volatile List scriptMetaClassExtensionProviders = new CopyOnWriteArrayList<>() private volatile List compilationCustomizerExtensionProviders = - new CopyOnWriteArrayList<>() + new CopyOnWriteArrayList<>() @Override Map getBindingVariables(ScriptContext scriptContext) { @@ -40,7 +40,7 @@ class DefaultExtensionService implements ExtensionService { extension.getBindingVariables(scriptContext).each { name, variable -> if (bindingVariables[name]) { LOG.debug("binding variable {} is currently bound to value {}, overriding with value = {}", name, - bindingVariables[name], variable.value) + bindingVariables[name], variable.value) } bindingVariables[name] = variable diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/extension/impl/DefaultScriptMetaClassExtensionProvider.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/extension/impl/DefaultScriptMetaClassExtensionProvider.groovy similarity index 89% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/extension/impl/DefaultScriptMetaClassExtensionProvider.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/extension/impl/DefaultScriptMetaClassExtensionProvider.groovy index 2ce9790f..b455ed3c 100755 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/extension/impl/DefaultScriptMetaClassExtensionProvider.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/extension/impl/DefaultScriptMetaClassExtensionProvider.groovy @@ -1,14 +1,14 @@ -package org.cid15.aem.groovy.console.extension.impl +package be.orbinson.aem.groovy.console.extension.impl +import be.orbinson.aem.groovy.console.api.ScriptMetaClassExtensionProvider +import be.orbinson.aem.groovy.console.api.context.ScriptContext +import be.orbinson.aem.groovy.console.table.Table import com.day.cq.replication.ReplicationActionType import com.day.cq.replication.ReplicationOptions import com.day.cq.replication.Replicator import com.day.cq.search.PredicateGroup import com.day.cq.search.QueryBuilder import com.day.cq.wcm.api.PageManager -import org.cid15.aem.groovy.console.api.context.ScriptContext -import org.cid15.aem.groovy.console.api.ScriptMetaClassExtensionProvider -import org.cid15.aem.groovy.console.table.Table import org.apache.sling.models.factory.ModelFactory import org.osgi.framework.BundleContext import org.osgi.service.component.annotations.Activate @@ -128,6 +128,14 @@ class DefaultScriptMetaClassExtensionProvider implements ScriptMetaClassExtensio queryBuilder.createQuery(PredicateGroup.create(predicates), session) } + delegate.xpathQuery { String query -> + session.workspace.queryManager.createQuery(query, "xpath").execute().nodes + } + + delegate.sql2Query { String query -> + session.workspace.queryManager.createQuery(query, "JCR-SQL2").execute().nodes + } + delegate.table = { Closure closure -> def table = new Table() diff --git a/bundle/src/main/groovy/be/orbinson/aem/groovy/console/extension/impl/DefaultStarImportExtensionProvider.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/extension/impl/DefaultStarImportExtensionProvider.groovy new file mode 100644 index 00000000..dfad064e --- /dev/null +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/extension/impl/DefaultStarImportExtensionProvider.groovy @@ -0,0 +1,35 @@ +package be.orbinson.aem.groovy.console.extension.impl + +import be.orbinson.aem.groovy.console.api.StarImport +import be.orbinson.aem.groovy.console.api.StarImportExtensionProvider +import com.google.common.collect.ImmutableSet +import org.osgi.service.component.annotations.Component + +@Component(service = StarImportExtensionProvider, immediate = true) +class DefaultStarImportExtensionProvider implements StarImportExtensionProvider { + + private static final String AEM_JAVADOC_PREFIX = "https://developer.adobe.com/experience-manager/reference-materials/6-5/javadoc" + + private static final String JCR_JAVADOC_PREFIX = "https://developer.adobe.com/experience-manager/reference-materials/spec/javax.jcr/javadocs/jcr-2.0" + + private static final String SLING_JAVADOC_PREFIX = "http://sling.apache.org/apidocs/sling12" + + private static final String JAVADOC_SUFFIX = "package-summary.html" + + private static final Set IMPORTS = ImmutableSet.of( + new StarImport("com.day.cq.dam.api", "$AEM_JAVADOC_PREFIX/com/day/cq/dam/api/$JAVADOC_SUFFIX"), + new StarImport("com.day.cq.search", "$AEM_JAVADOC_PREFIX/com/day/cq/search/$JAVADOC_SUFFIX"), + new StarImport("com.day.cq.tagging", "$AEM_JAVADOC_PREFIX/com/day/cq/tagging/$JAVADOC_SUFFIX"), + new StarImport("com.day.cq.wcm.api", "$AEM_JAVADOC_PREFIX/com/day/cq/wcm/api/$JAVADOC_SUFFIX"), + new StarImport("com.day.cq.replication", "$AEM_JAVADOC_PREFIX/com/day/cq/replication/$JAVADOC_SUFFIX"), + new StarImport("javax.jcr", "$JCR_JAVADOC_PREFIX/javax/jcr/$JAVADOC_SUFFIX"), + new StarImport("org.apache.sling.api", "$SLING_JAVADOC_PREFIX/org/apache/sling/api/$JAVADOC_SUFFIX"), + new StarImport("org.apache.sling.api.resource", + "$SLING_JAVADOC_PREFIX/org/apache/sling/api/resource/$JAVADOC_SUFFIX") + ) + + @Override + Set getStarImports() { + IMPORTS + } +} diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/impl/DefaultGroovyConsoleService.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/impl/DefaultGroovyConsoleService.groovy similarity index 78% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/impl/DefaultGroovyConsoleService.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/impl/DefaultGroovyConsoleService.groovy index 96260d2e..8f9a3336 100755 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/impl/DefaultGroovyConsoleService.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/impl/DefaultGroovyConsoleService.groovy @@ -1,27 +1,27 @@ -package org.cid15.aem.groovy.console.impl - +package be.orbinson.aem.groovy.console.impl + +import be.orbinson.aem.groovy.console.GroovyConsoleService +import be.orbinson.aem.groovy.console.api.ActiveJob +import be.orbinson.aem.groovy.console.api.JobProperties +import be.orbinson.aem.groovy.console.api.context.ScriptContext +import be.orbinson.aem.groovy.console.api.context.ScriptData +import be.orbinson.aem.groovy.console.audit.AuditService +import be.orbinson.aem.groovy.console.configuration.ConfigurationService +import be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants +import be.orbinson.aem.groovy.console.extension.ExtensionService +import be.orbinson.aem.groovy.console.notification.NotificationService +import be.orbinson.aem.groovy.console.response.RunScriptResponse +import be.orbinson.aem.groovy.console.response.SaveScriptResponse +import be.orbinson.aem.groovy.console.response.impl.DefaultRunScriptResponse +import be.orbinson.aem.groovy.console.response.impl.DefaultSaveScriptResponse import com.day.cq.commons.jcr.JcrConstants import com.day.cq.commons.jcr.JcrUtil import com.google.common.net.MediaType -import org.cid15.aem.groovy.console.GroovyConsoleService -import org.cid15.aem.groovy.console.audit.AuditService -import org.cid15.aem.groovy.console.configuration.ConfigurationService -import org.cid15.aem.groovy.console.notification.NotificationService import groovy.transform.Synchronized import groovy.transform.TimedInterrupt import groovy.util.logging.Slf4j import org.apache.jackrabbit.util.Text import org.apache.sling.event.jobs.JobManager -import org.cid15.aem.groovy.console.api.ActiveJob -import org.cid15.aem.groovy.console.api.JobProperties -import org.cid15.aem.groovy.console.api.context.ScriptContext -import org.cid15.aem.groovy.console.api.context.ScriptData -import org.cid15.aem.groovy.console.constants.GroovyConsoleConstants -import org.cid15.aem.groovy.console.extension.ExtensionService -import org.cid15.aem.groovy.console.response.RunScriptResponse -import org.cid15.aem.groovy.console.response.SaveScriptResponse -import org.cid15.aem.groovy.console.response.impl.DefaultRunScriptResponse -import org.cid15.aem.groovy.console.response.impl.DefaultSaveScriptResponse import org.codehaus.groovy.control.CompilerConfiguration import org.codehaus.groovy.control.MultipleCompilationErrorsException import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer @@ -35,10 +35,10 @@ import javax.jcr.Node import javax.jcr.Session import java.util.concurrent.CopyOnWriteArrayList -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.CHARSET -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.FORMAT_RUNNING_TIME -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.PATH_SCRIPTS_FOLDER -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.TIME_ZONE_RUNNING_TIME +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.CHARSET +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.FORMAT_RUNNING_TIME +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.PATH_SCRIPTS_FOLDER +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.TIME_ZONE_RUNNING_TIME @Component(service = GroovyConsoleService, immediate = true) @Slf4j("LOG") @@ -91,19 +91,19 @@ class DefaultGroovyConsoleService implements GroovyConsoleService { LOG.debug("script execution completed, running time : {}", runningTime) runScriptResponse = DefaultRunScriptResponse.fromResult(scriptContext, result, - scriptContext.outputStream.toString(CHARSET), runningTime) + scriptContext.outputStream.toString(CHARSET), runningTime) auditAndNotify(runScriptResponse) } catch (MultipleCompilationErrorsException e) { LOG.error("script compilation error", e) runScriptResponse = DefaultRunScriptResponse.fromException(scriptContext, - scriptContext.outputStream.toString(CHARSET), e) + scriptContext.outputStream.toString(CHARSET), e) } catch (Throwable t) { LOG.error("error running script", t) runScriptResponse = DefaultRunScriptResponse.fromException(scriptContext, - scriptContext.outputStream.toString(CHARSET), t) + scriptContext.outputStream.toString(CHARSET), t) auditAndNotify(runScriptResponse) } finally { @@ -143,10 +143,10 @@ class DefaultGroovyConsoleService implements GroovyConsoleService { LOG.info("adding scheduled job with properties : {}", jobProperties.toMap()) jobManager.createJob(GroovyConsoleConstants.JOB_TOPIC) - .properties(jobProperties.toMap()) - .schedule() - .cron(jobProperties.cronExpression) - .add() + .properties(jobProperties.toMap()) + .schedule() + .cron(jobProperties.cronExpression) + .add() } else { LOG.info("adding immediate job with properties : {}", jobProperties.toMap()) @@ -200,11 +200,11 @@ class DefaultGroovyConsoleService implements GroovyConsoleService { } configuration.addCompilationCustomizers(extensionService.compilationCustomizers - as CompilationCustomizer[]) + as CompilationCustomizer[]) } private void saveFile(Session session, Node folderNode, String script, String fileName, Date date, - String mimeType) { + String mimeType) { def fileNode = folderNode.addNode(Text.escapeIllegalJcrChars(fileName), JcrConstants.NT_FILE) def resourceNode = fileNode.addNode(JcrConstants.JCR_CONTENT, JcrConstants.NT_RESOURCE) diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/job/consumer/GroovyConsoleScheduledJobConsumer.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/job/consumer/GroovyConsoleScheduledJobConsumer.groovy similarity index 67% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/job/consumer/GroovyConsoleScheduledJobConsumer.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/job/consumer/GroovyConsoleScheduledJobConsumer.groovy index e86c2b69..ae605a8f 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/job/consumer/GroovyConsoleScheduledJobConsumer.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/job/consumer/GroovyConsoleScheduledJobConsumer.groovy @@ -1,18 +1,18 @@ -package org.cid15.aem.groovy.console.job.consumer +package be.orbinson.aem.groovy.console.job.consumer +import be.orbinson.aem.groovy.console.GroovyConsoleService +import be.orbinson.aem.groovy.console.api.JobProperties +import be.orbinson.aem.groovy.console.api.impl.ScheduledJobScriptContext import com.google.common.base.Charsets -import org.cid15.aem.groovy.console.GroovyConsoleService -import org.cid15.aem.groovy.console.api.impl.ScheduledJobScriptContext import groovy.util.logging.Slf4j import org.apache.sling.api.resource.ResourceResolverFactory import org.apache.sling.event.jobs.Job import org.apache.sling.event.jobs.consumer.JobConsumer -import org.cid15.aem.groovy.console.api.JobProperties import org.osgi.service.component.annotations.Component import org.osgi.service.component.annotations.Reference @Component(service = JobConsumer, immediate = true, property = [ - "job.topics=groovyconsole/job" + "job.topics=groovyconsole/job" ]) @Slf4j("LOG") class GroovyConsoleScheduledJobConsumer implements JobConsumer { @@ -33,11 +33,11 @@ class GroovyConsoleScheduledJobConsumer implements JobConsumer { def outputStream = new ByteArrayOutputStream() def scriptContext = new ScheduledJobScriptContext( - resourceResolver: resourceResolver, - outputStream: outputStream, - printStream: new PrintStream(outputStream, true, Charsets.UTF_8.name()), - jobId: job.id, - jobProperties: JobProperties.fromJob(job) + resourceResolver: resourceResolver, + outputStream: outputStream, + printStream: new PrintStream(outputStream, true, Charsets.UTF_8.name()), + jobId: job.id, + jobProperties: JobProperties.fromJob(job) ) groovyConsoleService.runScript(scriptContext) diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/job/event/AbstractGroovyConsoleScheduledJobEventHandler.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/job/event/AbstractGroovyConsoleScheduledJobEventHandler.groovy similarity index 83% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/job/event/AbstractGroovyConsoleScheduledJobEventHandler.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/job/event/AbstractGroovyConsoleScheduledJobEventHandler.groovy index 582ec180..ac348f41 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/job/event/AbstractGroovyConsoleScheduledJobEventHandler.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/job/event/AbstractGroovyConsoleScheduledJobEventHandler.groovy @@ -1,9 +1,9 @@ -package org.cid15.aem.groovy.console.job.event +package be.orbinson.aem.groovy.console.job.event -import org.cid15.aem.groovy.console.audit.AuditService +import be.orbinson.aem.groovy.console.audit.AuditService +import be.orbinson.aem.groovy.console.response.RunScriptResponse import groovy.util.logging.Slf4j import org.apache.sling.event.jobs.NotificationConstants -import org.cid15.aem.groovy.console.response.RunScriptResponse import org.osgi.service.event.Event import org.osgi.service.event.EventHandler @@ -17,7 +17,7 @@ abstract class AbstractGroovyConsoleScheduledJobEventHandler implements EventHan @Override final void handleEvent(Event event) { LOG.debug("handling completed scheduled job with properties : {}", event.propertyNames - .collectEntries { propertyName -> [propertyName, event.getProperty(propertyName)] }) + .collectEntries { propertyName -> [propertyName, event.getProperty(propertyName)] }) def jobId = event.getProperty(NotificationConstants.NOTIFICATION_PROPERTY_JOB_ID) as String def auditRecord = getAuditService().getAuditRecord(jobId) diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/job/event/impl/DefaultGroovyConsoleEmailNotificationEventHandler.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/job/event/impl/DefaultGroovyConsoleEmailNotificationEventHandler.groovy similarity index 78% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/job/event/impl/DefaultGroovyConsoleEmailNotificationEventHandler.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/job/event/impl/DefaultGroovyConsoleEmailNotificationEventHandler.groovy index 9488863d..691378e0 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/job/event/impl/DefaultGroovyConsoleEmailNotificationEventHandler.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/job/event/impl/DefaultGroovyConsoleEmailNotificationEventHandler.groovy @@ -1,11 +1,11 @@ -package org.cid15.aem.groovy.console.job.event.impl +package be.orbinson.aem.groovy.console.job.event.impl -import org.cid15.aem.groovy.console.audit.AuditService -import org.cid15.aem.groovy.console.notification.EmailNotificationService +import be.orbinson.aem.groovy.console.audit.AuditService +import be.orbinson.aem.groovy.console.job.event.AbstractGroovyConsoleScheduledJobEventHandler +import be.orbinson.aem.groovy.console.notification.EmailNotificationService +import be.orbinson.aem.groovy.console.response.RunScriptResponse import groovy.util.logging.Slf4j import org.apache.sling.event.jobs.NotificationConstants -import org.cid15.aem.groovy.console.job.event.AbstractGroovyConsoleScheduledJobEventHandler -import org.cid15.aem.groovy.console.response.RunScriptResponse import org.osgi.service.component.annotations.Component import org.osgi.service.component.annotations.Reference import org.osgi.service.event.EventHandler diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/notification/EmailNotificationService.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/notification/EmailNotificationService.groovy similarity index 86% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/notification/EmailNotificationService.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/notification/EmailNotificationService.groovy index 3e6cf9b8..2a160c88 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/notification/EmailNotificationService.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/notification/EmailNotificationService.groovy @@ -1,6 +1,6 @@ -package org.cid15.aem.groovy.console.notification +package be.orbinson.aem.groovy.console.notification -import org.cid15.aem.groovy.console.response.RunScriptResponse +import be.orbinson.aem.groovy.console.response.RunScriptResponse /** * Services may implement this interface to send email notifications for Groovy Console script executions. @@ -27,5 +27,5 @@ interface EmailNotificationService extends NotificationService { * @param attachOutput if true, attach the script output file */ void notify(RunScriptResponse response, Set recipients, String successTemplate, - String failureTemplate, boolean attachOutput) + String failureTemplate, boolean attachOutput) } diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/notification/NotificationService.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/notification/NotificationService.groovy similarity index 74% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/notification/NotificationService.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/notification/NotificationService.groovy index 953c10f1..32dd789a 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/notification/NotificationService.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/notification/NotificationService.groovy @@ -1,6 +1,6 @@ -package org.cid15.aem.groovy.console.notification +package be.orbinson.aem.groovy.console.notification -import org.cid15.aem.groovy.console.response.RunScriptResponse +import be.orbinson.aem.groovy.console.response.RunScriptResponse /** * Services may implement this interface to provide additional notifications for Groovy Console script executions. diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/notification/impl/DefaultEmailNotificationService.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/notification/impl/DefaultEmailNotificationService.groovy similarity index 77% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/notification/impl/DefaultEmailNotificationService.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/notification/impl/DefaultEmailNotificationService.groovy index 3067a4d7..8b80ba62 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/notification/impl/DefaultEmailNotificationService.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/notification/impl/DefaultEmailNotificationService.groovy @@ -1,17 +1,17 @@ -package org.cid15.aem.groovy.console.notification.impl +package be.orbinson.aem.groovy.console.notification.impl +import be.orbinson.aem.groovy.console.configuration.ConfigurationService +import be.orbinson.aem.groovy.console.notification.EmailNotificationService +import be.orbinson.aem.groovy.console.notification.NotificationService +import be.orbinson.aem.groovy.console.response.RunScriptResponse import com.day.cq.mailer.MailService import com.google.common.base.Charsets import com.google.common.net.MediaType -import org.cid15.aem.groovy.console.notification.EmailNotificationService -import org.cid15.aem.groovy.console.notification.NotificationService import groovy.text.GStringTemplateEngine import groovy.util.logging.Slf4j import org.apache.commons.mail.Email import org.apache.commons.mail.HtmlEmail import org.apache.commons.mail.MultiPartEmail -import org.cid15.aem.groovy.console.configuration.ConfigurationService -import org.cid15.aem.groovy.console.response.RunScriptResponse import org.osgi.service.component.annotations.Component import org.osgi.service.component.annotations.Reference import org.osgi.service.component.annotations.ReferenceCardinality @@ -48,7 +48,7 @@ class DefaultEmailNotificationService implements EmailNotificationService { @Override void notify(RunScriptResponse response, Set recipients, String successTemplate, - String failureTemplate, boolean attachOutput) { + String failureTemplate, boolean attachOutput) { if (configurationService.emailEnabled && mailService) { if (recipients) { def email = createEmail(response, recipients, successTemplate, failureTemplate, attachOutput) @@ -65,7 +65,7 @@ class DefaultEmailNotificationService implements EmailNotificationService { } private Email createEmail(RunScriptResponse response, Set recipients, String successTemplate, - String failureTemplate, boolean attachOutput) { + String failureTemplate, boolean attachOutput) { def email = attachOutput ? new MultiPartEmail() : new HtmlEmail() recipients.each { name -> @@ -81,7 +81,7 @@ class DefaultEmailNotificationService implements EmailNotificationService { (email as MultiPartEmail).addPart(message, MediaType.HTML_UTF_8.toString()) def dataSource = new ByteArrayDataSource(response.output.getBytes(Charsets.UTF_8.name()), - MediaType.parse(response.mediaType).toString()) + MediaType.parse(response.mediaType).toString()) // attach output file (email as MultiPartEmail).attach(dataSource, response.outputFileName, null) @@ -102,28 +102,28 @@ class DefaultEmailNotificationService implements EmailNotificationService { } new GStringTemplateEngine() - .createTemplate(template) - .make(createBinding(response)) - .toString() + .createTemplate(template) + .make(createBinding(response)) + .toString() } private Map createBinding(RunScriptResponse response) { def binding = [ - username: response.userId, - timestamp: new Date().format(FORMAT_TIMESTAMP), - script: response.script + username : response.userId, + timestamp: new Date().format(FORMAT_TIMESTAMP), + script : response.script ] if (response.exceptionStackTrace) { binding.putAll([ - stackTrace: response.exceptionStackTrace, - output: response.output + stackTrace: response.exceptionStackTrace, + output : response.output ]) } else { binding.putAll([ - result: response.result, - output: response.output, - runningTime: response.runningTime + result : response.result, + output : response.output, + runningTime: response.runningTime ]) } diff --git a/bundle/src/main/groovy/be/orbinson/aem/groovy/console/replication/ReplicatedScriptListener.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/replication/ReplicatedScriptListener.groovy new file mode 100644 index 00000000..537a5c66 --- /dev/null +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/replication/ReplicatedScriptListener.groovy @@ -0,0 +1,76 @@ +package be.orbinson.aem.groovy.console.replication + +import be.orbinson.aem.groovy.console.GroovyConsoleService +import be.orbinson.aem.groovy.console.api.context.ScriptContext +import be.orbinson.aem.groovy.console.api.impl.ResourceScriptContext +import be.orbinson.aem.groovy.console.configuration.ConfigurationService +import com.day.cq.commons.jcr.JcrConstants +import com.google.common.base.Charsets +import groovy.util.logging.Slf4j +import org.apache.sling.api.resource.ResourceResolver +import org.apache.sling.api.resource.ResourceResolverFactory +import org.apache.sling.api.resource.observation.ResourceChange +import org.apache.sling.api.resource.observation.ResourceChangeListener +import org.jetbrains.annotations.NotNull +import org.osgi.service.component.annotations.Component +import org.osgi.service.component.annotations.Reference + +import javax.jcr.Session + +import static com.google.common.base.Preconditions.checkNotNull + +@Component(property = [ + "resource.paths=glob:/conf/groovyconsole/replication/*.groovy", + "resource.change.types=ADDED" +]) +@Slf4j("LOG") +public class ReplicatedScriptListener implements ResourceChangeListener { + @Reference + private GroovyConsoleService consoleService; + + @Reference + private ResourceResolverFactory resourceResolverFactory; + + @Reference + private ConfigurationService configurationService; + + @Override + public void onChange(@NotNull List list) { + if (!configurationService.isAuthor() && configurationService.isDistributedExecutionEnabled()) { + list.each { change -> + resourceResolverFactory.getServiceResourceResolver(null).withCloseable { resourceResolver -> + LOG.debug("Detected replicated script on path '{}'", change.path) + consoleService.runScript(getScriptContext(resourceResolver, change.path)) + } + } + } + } + + private ScriptContext getScriptContext(ResourceResolver resourceResolver, String scriptPath) { + def outputStream = new ByteArrayOutputStream() + + new ResourceScriptContext( + resourceResolver: resourceResolver, + outputStream: outputStream, + printStream: new PrintStream(outputStream, true, Charsets.UTF_8.name()), + script: checkNotNull(loadScript(resourceResolver, scriptPath), "Script cannot be empty.") + ) + } + + // FIXME: extract to service that can be shared between services and servlets + private String loadScript(ResourceResolver resourceResolver, String scriptPath) { + def session = resourceResolver.adaptTo(Session) + + // FIXME: use adaptTo(InputStream.class) to get binary data + def binary = session.getNode(scriptPath) + .getNode(JcrConstants.JCR_CONTENT) + .getProperty(JcrConstants.JCR_DATA) + .binary + + def script = binary.stream.text + + binary.dispose() + + script + } +} diff --git a/bundle/src/main/groovy/be/orbinson/aem/groovy/console/response/ReplicateScriptResponse.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/response/ReplicateScriptResponse.groovy new file mode 100644 index 00000000..cf3ce7a9 --- /dev/null +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/response/ReplicateScriptResponse.groovy @@ -0,0 +1,10 @@ +package be.orbinson.aem.groovy.console.response + +/** + * Response for replicated scripts. + */ +interface ReplicateScriptResponse { + + String getResult() + +} diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/response/RunScriptResponse.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/response/RunScriptResponse.groovy similarity index 82% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/response/RunScriptResponse.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/response/RunScriptResponse.groovy index 8b1f1433..165be455 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/response/RunScriptResponse.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/response/RunScriptResponse.groovy @@ -1,6 +1,6 @@ -package org.cid15.aem.groovy.console.response +package be.orbinson.aem.groovy.console.response -import org.cid15.aem.groovy.console.api.JobProperties +import be.orbinson.aem.groovy.console.api.JobProperties /** * Response for script executions. diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/response/SaveScriptResponse.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/response/SaveScriptResponse.groovy similarity index 67% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/response/SaveScriptResponse.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/response/SaveScriptResponse.groovy index b2eb6928..3de654df 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/response/SaveScriptResponse.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/response/SaveScriptResponse.groovy @@ -1,4 +1,4 @@ -package org.cid15.aem.groovy.console.response +package be.orbinson.aem.groovy.console.response /** * Response for saved scripts. diff --git a/bundle/src/main/groovy/be/orbinson/aem/groovy/console/response/impl/DefaultReplicateScriptResponse.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/response/impl/DefaultReplicateScriptResponse.groovy new file mode 100644 index 00000000..dea6d09c --- /dev/null +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/response/impl/DefaultReplicateScriptResponse.groovy @@ -0,0 +1,9 @@ +package be.orbinson.aem.groovy.console.response.impl + +import be.orbinson.aem.groovy.console.response.ReplicateScriptResponse +import groovy.transform.TupleConstructor + +@TupleConstructor +class DefaultReplicateScriptResponse implements ReplicateScriptResponse { + String result +} diff --git a/bundle/src/main/groovy/be/orbinson/aem/groovy/console/response/impl/DefaultRunScriptResponse.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/response/impl/DefaultRunScriptResponse.groovy new file mode 100644 index 00000000..ea287d7e --- /dev/null +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/response/impl/DefaultRunScriptResponse.groovy @@ -0,0 +1,149 @@ +package be.orbinson.aem.groovy.console.response.impl + +import be.orbinson.aem.groovy.console.api.JobProperties +import be.orbinson.aem.groovy.console.api.context.JobScriptContext +import be.orbinson.aem.groovy.console.api.context.ScriptContext +import be.orbinson.aem.groovy.console.response.RunScriptResponse +import be.orbinson.aem.groovy.console.table.Table +import com.day.cq.commons.jcr.JcrConstants +import com.day.cq.commons.jcr.JcrUtil +import com.day.text.Text +import com.google.common.net.MediaType +import groovy.json.JsonBuilder +import groovy.transform.TupleConstructor +import org.apache.commons.lang3.exception.ExceptionUtils +import org.apache.sling.api.resource.Resource +import org.apache.sling.api.resource.ResourceUtil + +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.DATA +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.DATE_FORMAT_FILE_NAME +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.EXCEPTION_STACK_TRACE +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.JOB_ID +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.MEDIA_TYPE_EXTENSIONS +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.OUTPUT +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.RESULT +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.RUNNING_TIME +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.SCRIPT + +@TupleConstructor +class DefaultRunScriptResponse implements RunScriptResponse { + + private static final int LEVEL_USERID = 4 + + static RunScriptResponse fromResult(ScriptContext scriptContext, Object result, String output, String runningTime) { + def resultString + + if (result instanceof Table) { + resultString = new JsonBuilder([table: result]).toString() + } else { + resultString = result as String + } + + new DefaultRunScriptResponse( + date: Calendar.instance, + script: scriptContext.script, + data: scriptContext.data, + result: resultString, + output: output, + exceptionStackTrace: "", + runningTime: runningTime, + userId: scriptContext.userId, + jobId: scriptContext instanceof JobScriptContext ? scriptContext.jobId : null, + jobProperties: scriptContext instanceof JobScriptContext ? scriptContext.jobProperties : null + ) + } + + static RunScriptResponse fromException(ScriptContext scriptContext, String output, Throwable throwable) { + def exceptionStackTrace = ExceptionUtils.getStackTrace(throwable) + + new DefaultRunScriptResponse( + date: Calendar.instance, + script: scriptContext.script, + data: scriptContext.data, + result: "", + output: output, + exceptionStackTrace: exceptionStackTrace, + runningTime: "", + userId: scriptContext.userId, + jobId: scriptContext instanceof JobScriptContext ? scriptContext.jobId : null, + jobProperties: scriptContext instanceof JobScriptContext ? scriptContext.jobProperties : null + ) + } + + static RunScriptResponse fromAuditRecordResource(Resource resource) { + def properties = resource.valueMap + + def exceptionStackTrace = properties.get(EXCEPTION_STACK_TRACE, "") + def userIdResourcePath = ResourceUtil.getParent(resource.path, LEVEL_USERID) + def userId = Text.getName(userIdResourcePath) + + new DefaultRunScriptResponse( + date: properties.get(JcrConstants.JCR_CREATED, Calendar), + script: properties.get(SCRIPT, ""), + data: properties.get(DATA, ""), + result: exceptionStackTrace ? "" : properties.get(RESULT, ""), + output: properties.get(OUTPUT, ""), + exceptionStackTrace: exceptionStackTrace ?: "", + runningTime: exceptionStackTrace ? "" : properties.get(RUNNING_TIME, ""), + userId: userId, + jobId: properties.get(JOB_ID, String), + jobProperties: JobProperties.fromValueMap(properties) + ) + } + + Calendar date + + String script + + String data + + String result + + String output + + String exceptionStackTrace + + String runningTime + + String userId + + String jobId + + JobProperties jobProperties + + @Override + String getMediaType() { + def mediaType + + if (jobProperties?.mediaType) { + mediaType = MediaType.parse(jobProperties.mediaType) + } else { + mediaType = MediaType.PLAIN_TEXT_UTF_8 + } + + mediaType.withoutParameters().toString() + } + + @Override + String getOutputFileName() { + new StringBuilder() + .append(outputFileNamePrefix) + .append(date.format(DATE_FORMAT_FILE_NAME)) + .append(".") + .append(MEDIA_TYPE_EXTENSIONS[mediaType]) + .toString() + } + + private String getOutputFileNamePrefix() { + def outputFileNamePrefix + + if (jobProperties?.jobTitle) { + outputFileNamePrefix = JcrUtil.createValidName(jobProperties.jobTitle, + JcrUtil.HYPHEN_LABEL_CHAR_MAPPING).toLowerCase() + "-" + } else { + outputFileNamePrefix = "output-" + } + + outputFileNamePrefix + } +} diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/response/impl/DefaultSaveScriptResponse.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/response/impl/DefaultSaveScriptResponse.groovy similarity index 53% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/response/impl/DefaultSaveScriptResponse.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/response/impl/DefaultSaveScriptResponse.groovy index 5fdde0de..9ff63eaf 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/response/impl/DefaultSaveScriptResponse.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/response/impl/DefaultSaveScriptResponse.groovy @@ -1,7 +1,7 @@ -package org.cid15.aem.groovy.console.response.impl +package be.orbinson.aem.groovy.console.response.impl +import be.orbinson.aem.groovy.console.response.SaveScriptResponse import groovy.transform.Immutable -import org.cid15.aem.groovy.console.response.SaveScriptResponse @Immutable class DefaultSaveScriptResponse implements SaveScriptResponse { diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/servlets/AbstractJsonResponseServlet.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/AbstractJsonResponseServlet.groovy similarity index 82% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/servlets/AbstractJsonResponseServlet.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/AbstractJsonResponseServlet.groovy index d384df74..0c81f3f4 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/servlets/AbstractJsonResponseServlet.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/AbstractJsonResponseServlet.groovy @@ -1,7 +1,7 @@ -package org.cid15.aem.groovy.console.servlets +package be.orbinson.aem.groovy.console.servlets +import be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants import com.google.common.net.MediaType -import org.cid15.aem.groovy.console.constants.GroovyConsoleConstants import groovy.json.JsonBuilder import org.apache.sling.api.SlingHttpServletResponse import org.apache.sling.api.servlets.SlingAllMethodsServlet diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/servlets/AuditServlet.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/AuditServlet.groovy similarity index 72% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/servlets/AuditServlet.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/AuditServlet.groovy index 7e032281..f47b841a 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/servlets/AuditServlet.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/AuditServlet.groovy @@ -1,10 +1,11 @@ -package org.cid15.aem.groovy.console.servlets +package be.orbinson.aem.groovy.console.servlets -import org.cid15.aem.groovy.console.audit.AuditRecord -import org.cid15.aem.groovy.console.audit.AuditService -import org.cid15.aem.groovy.console.configuration.ConfigurationService -import org.cid15.aem.groovy.console.constants.GroovyConsoleConstants -import org.cid15.aem.groovy.console.utils.GroovyScriptUtils + +import be.orbinson.aem.groovy.console.audit.AuditRecord +import be.orbinson.aem.groovy.console.audit.AuditService +import be.orbinson.aem.groovy.console.configuration.ConfigurationService +import be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants +import be.orbinson.aem.groovy.console.utils.GroovyScriptUtils import org.apache.sling.api.SlingHttpServletRequest import org.apache.sling.api.SlingHttpServletResponse import org.osgi.service.component.annotations.Component @@ -13,7 +14,7 @@ import org.osgi.service.component.annotations.Reference import javax.servlet.Servlet @Component(service = Servlet, immediate = true, property = [ - "sling.servlet.paths=/bin/groovyconsole/audit" + "sling.servlet.paths=/bin/groovyconsole/audit" ]) class AuditServlet extends AbstractJsonResponseServlet { @@ -54,16 +55,16 @@ class AuditServlet extends AbstractJsonResponseServlet { [data: auditRecords.collect { auditRecord -> [ - date: auditRecord.date.format(GroovyConsoleConstants.DATE_FORMAT_DISPLAY), - scriptPreview: GroovyScriptUtils.getScriptPreview(auditRecord.script), - jobTitle: auditRecord.jobProperties.jobTitle, - userId: auditRecord.userId, - script: auditRecord.script, - data: auditRecord.data, - exception: auditRecord.exception, - queryString: "?userId=${auditRecord.userId}&script=${auditRecord.relativePath}", - relativePath: auditRecord.relativePath, - downloadUrl: auditRecord.downloadUrl + date : auditRecord.date.format(GroovyConsoleConstants.DATE_FORMAT_DISPLAY), + scriptPreview: GroovyScriptUtils.getScriptPreview(auditRecord.script), + jobTitle : auditRecord.jobProperties.jobTitle, + userId : auditRecord.userId, + script : auditRecord.script, + data : auditRecord.data, + exception : auditRecord.exception, + queryString : "?userId=${auditRecord.userId}&script=${auditRecord.relativePath}", + relativePath : auditRecord.relativePath, + downloadUrl : auditRecord.downloadUrl ] }] } diff --git a/bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/ReplicateScriptServlet.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/ReplicateScriptServlet.groovy new file mode 100644 index 00000000..88528fe5 --- /dev/null +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/ReplicateScriptServlet.groovy @@ -0,0 +1,82 @@ +package be.orbinson.aem.groovy.console.servlets + +import be.orbinson.aem.groovy.console.configuration.ConfigurationService +import be.orbinson.aem.groovy.console.response.impl.DefaultReplicateScriptResponse +import com.day.cq.commons.jcr.JcrConstants +import com.day.cq.replication.ReplicationActionType +import com.day.cq.replication.Replicator +import com.google.common.base.Charsets +import com.google.common.net.MediaType +import groovy.util.logging.Slf4j +import org.apache.commons.io.IOUtils +import org.apache.sling.api.SlingHttpServletRequest +import org.apache.sling.api.SlingHttpServletResponse +import org.apache.sling.api.resource.ResourceResolverFactory +import org.jetbrains.annotations.NotNull +import org.osgi.service.component.annotations.Component +import org.osgi.service.component.annotations.Reference + +import javax.jcr.Session +import javax.servlet.Servlet +import javax.servlet.ServletException + +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.* +import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST +import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN + +@Component(service = Servlet, immediate = true, property = [ + "sling.servlet.paths=/bin/groovyconsole/replicate" +]) +@Slf4j("LOG") +class ReplicateScriptServlet extends AbstractJsonResponseServlet { + @Reference + private ConfigurationService configurationService + + @Reference + private ResourceResolverFactory resourceResolverFactory + + @Reference + Replicator replicator + + @Override + protected void doPost(@NotNull SlingHttpServletRequest request, @NotNull SlingHttpServletResponse response) throws ServletException, IOException { + if (configurationService.hasPermission(request) && configurationService.isDistributedExecutionEnabled()) { + def script = request.getRequestParameter(SCRIPT)?.getString(Charsets.UTF_8.name()) + if (script) { + def resourceResolver = request.resourceResolver + def scriptName = createScriptResource(script) + LOG.debug("Replicate script '{}'", scriptName) + def session = resourceResolver.adaptTo(Session) + def scriptPath = "${PATH_REPLICATION_FOLDER}/${scriptName}" + replicator.replicate(session, ReplicationActionType.ACTIVATE, "${scriptPath}") + writeJsonResponse(response, new DefaultReplicateScriptResponse("Replicated script on path '${scriptPath}'")) + } else { + LOG.warn("Script should not be empty") + response.status = SC_BAD_REQUEST + } + } else { + response.status = SC_FORBIDDEN + } + } + + private String createScriptResource(String script) { + resourceResolverFactory.getServiceResourceResolver(null).withCloseable { resourceResolver -> + def parent = resourceResolver.getResource(PATH_REPLICATION_FOLDER) + Map properties = new HashMap<>() + + properties.put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_FILE) + def scriptName = "script-${System.currentTimeMillis()}.groovy" + def scriptResource = resourceResolver.create(parent, scriptName, properties) + + properties.clear() + properties.put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_RESOURCE) + properties.put(JcrConstants.JCR_ENCODING, CHARSET) + properties.put(JcrConstants.JCR_MIMETYPE, MediaType.OCTET_STREAM.toString()) + properties.put(JcrConstants.JCR_DATA, IOUtils.toInputStream(script, CHARSET)) + resourceResolver.create(scriptResource, JcrConstants.JCR_CONTENT, properties) + + resourceResolver.commit() + scriptName + } + } +} diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/servlets/ScheduledJobsServlet.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/ScheduledJobsServlet.groovy similarity index 66% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/servlets/ScheduledJobsServlet.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/ScheduledJobsServlet.groovy index 9d20e51f..6b700819 100755 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/servlets/ScheduledJobsServlet.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/ScheduledJobsServlet.groovy @@ -1,32 +1,33 @@ -package org.cid15.aem.groovy.console.servlets - +package be.orbinson.aem.groovy.console.servlets + +import be.orbinson.aem.groovy.console.GroovyConsoleService +import be.orbinson.aem.groovy.console.api.JobProperties +import be.orbinson.aem.groovy.console.audit.AuditRecord +import be.orbinson.aem.groovy.console.audit.AuditService +import be.orbinson.aem.groovy.console.configuration.ConfigurationService +import be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants +import be.orbinson.aem.groovy.console.utils.GroovyScriptUtils import com.google.common.collect.ImmutableMap -import org.cid15.aem.groovy.console.GroovyConsoleService -import org.cid15.aem.groovy.console.api.JobProperties -import org.cid15.aem.groovy.console.audit.AuditRecord -import org.cid15.aem.groovy.console.audit.AuditService -import org.cid15.aem.groovy.console.configuration.ConfigurationService -import org.cid15.aem.groovy.console.utils.GroovyScriptUtils import groovy.util.logging.Slf4j import org.apache.sling.api.SlingHttpServletRequest import org.apache.sling.api.SlingHttpServletResponse import org.apache.sling.event.jobs.JobManager import org.apache.sling.event.jobs.ScheduledJobInfo -import org.cid15.aem.groovy.console.constants.GroovyConsoleConstants import org.osgi.service.component.annotations.Component import org.osgi.service.component.annotations.Reference import javax.servlet.Servlet import javax.servlet.ServletException -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.DATE_CREATED -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.SCHEDULED_JOB_ID -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.SCRIPT +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.DATE_CREATED +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.SCHEDULED_JOB_ID +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.SCRIPT + import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN @Component(service = Servlet, immediate = true, property = [ - "sling.servlet.paths=/bin/groovyconsole/jobs" + "sling.servlet.paths=/bin/groovyconsole/jobs" ]) @Slf4j("LOG") class ScheduledJobsServlet extends AbstractJsonResponseServlet { @@ -45,7 +46,7 @@ class ScheduledJobsServlet extends AbstractJsonResponseServlet { @Override protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) - throws ServletException, IOException { + throws ServletException, IOException { def scheduledJob = findScheduledJobById(request) if (scheduledJob) { @@ -56,19 +57,19 @@ class ScheduledJobsServlet extends AbstractJsonResponseServlet { // list all jobs def scheduledJobs = jobManager.getScheduledJobs(GroovyConsoleConstants.JOB_TOPIC, 0, null) - .collect { scheduledJobInfo -> - def auditRecords = scheduledJobAuditRecords.findAll { record -> - isAuditRecordForScheduledJob(record, scheduledJobInfo) + .collect { scheduledJobInfo -> + def auditRecords = scheduledJobAuditRecords.findAll { record -> + isAuditRecordForScheduledJob(record, scheduledJobInfo) + } + + new ImmutableMap.Builder() + .putAll(scheduledJobInfo.jobProperties) + .put("downloadUrl", (auditRecords ? auditRecords.last().downloadUrl : null) ?: "") + .put("scriptPreview", GroovyScriptUtils.getScriptPreview(scheduledJobInfo.jobProperties[SCRIPT] as String)) + .put("nextExecutionDate", scheduledJobInfo.nextScheduledExecution.format(GroovyConsoleConstants.DATE_FORMAT_DISPLAY)) + .build() } - - new ImmutableMap.Builder() - .putAll(scheduledJobInfo.jobProperties) - .put("downloadUrl", (auditRecords ? auditRecords.last().downloadUrl : null) ?: "") - .put("scriptPreview", GroovyScriptUtils.getScriptPreview(scheduledJobInfo.jobProperties[SCRIPT] as String)) - .put("nextExecutionDate", scheduledJobInfo.nextScheduledExecution.format(GroovyConsoleConstants.DATE_FORMAT_DISPLAY)) - .build() - } - .sort { properties -> properties[DATE_CREATED] } + .sort { properties -> properties[DATE_CREATED] } writeJsonResponse(response, [data: scheduledJobs]) } @@ -76,7 +77,7 @@ class ScheduledJobsServlet extends AbstractJsonResponseServlet { @Override protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) - throws ServletException, IOException { + throws ServletException, IOException { if (configurationService.hasScheduledJobPermission(request)) { def scheduledJob = findScheduledJobById(request) @@ -105,7 +106,7 @@ class ScheduledJobsServlet extends AbstractJsonResponseServlet { @Override protected void doDelete(SlingHttpServletRequest request, SlingHttpServletResponse response) - throws ServletException, IOException { + throws ServletException, IOException { if (configurationService.hasScheduledJobPermission(request)) { def scheduledJob = findScheduledJobById(request) diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/servlets/ScriptDownloadServlet.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/ScriptDownloadServlet.groovy similarity index 86% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/servlets/ScriptDownloadServlet.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/ScriptDownloadServlet.groovy index 3e2eadba..4a3d7319 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/servlets/ScriptDownloadServlet.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/ScriptDownloadServlet.groovy @@ -1,11 +1,11 @@ -package org.cid15.aem.groovy.console.servlets +package be.orbinson.aem.groovy.console.servlets +import be.orbinson.aem.groovy.console.audit.AuditService +import be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants import com.google.common.net.HttpHeaders -import org.cid15.aem.groovy.console.audit.AuditService import org.apache.sling.api.SlingHttpServletRequest import org.apache.sling.api.SlingHttpServletResponse import org.apache.sling.api.servlets.SlingSafeMethodsServlet -import org.cid15.aem.groovy.console.constants.GroovyConsoleConstants import org.osgi.service.component.annotations.Component import org.osgi.service.component.annotations.Reference @@ -14,7 +14,7 @@ import javax.servlet.Servlet import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST @Component(service = Servlet, immediate = true, property = [ - "sling.servlet.paths=/bin/groovyconsole/download" + "sling.servlet.paths=/bin/groovyconsole/download" ]) class ScriptDownloadServlet extends SlingSafeMethodsServlet { diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/servlets/ScriptPostServlet.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/ScriptPostServlet.groovy similarity index 71% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/servlets/ScriptPostServlet.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/ScriptPostServlet.groovy index 996a9288..d26467af 100755 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/servlets/ScriptPostServlet.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/ScriptPostServlet.groovy @@ -1,11 +1,11 @@ -package org.cid15.aem.groovy.console.servlets +package be.orbinson.aem.groovy.console.servlets +import be.orbinson.aem.groovy.console.GroovyConsoleService +import be.orbinson.aem.groovy.console.api.context.ScriptContext +import be.orbinson.aem.groovy.console.api.impl.RequestScriptContext +import be.orbinson.aem.groovy.console.configuration.ConfigurationService import com.day.cq.commons.jcr.JcrConstants import com.google.common.base.Charsets -import org.cid15.aem.groovy.console.GroovyConsoleService -import org.cid15.aem.groovy.console.api.context.ScriptContext -import org.cid15.aem.groovy.console.api.impl.RequestScriptContext -import org.cid15.aem.groovy.console.configuration.ConfigurationService import groovy.util.logging.Slf4j import org.apache.sling.api.SlingHttpServletRequest import org.apache.sling.api.SlingHttpServletResponse @@ -16,14 +16,15 @@ import javax.jcr.Session import javax.servlet.Servlet import javax.servlet.ServletException +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.SCRIPT +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.SCRIPT_PATH +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.SCRIPT_PATHS + import static com.google.common.base.Preconditions.checkNotNull -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.SCRIPT -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.SCRIPT_PATH -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.SCRIPT_PATHS import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN @Component(service = Servlet, immediate = true, property = [ - "sling.servlet.paths=/bin/groovyconsole/post" + "sling.servlet.paths=/bin/groovyconsole/post" ]) @Slf4j("LOG") class ScriptPostServlet extends AbstractJsonResponseServlet { @@ -36,7 +37,7 @@ class ScriptPostServlet extends AbstractJsonResponseServlet { @Override protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws - ServletException, IOException { + ServletException, IOException { if (configurationService.hasPermission(request)) { def scriptPaths = request.getParameterValues(SCRIPT_PATHS) @@ -70,11 +71,11 @@ class ScriptPostServlet extends AbstractJsonResponseServlet { def outputStream = new ByteArrayOutputStream() new RequestScriptContext( - request: request, - response: response, - outputStream: outputStream, - printStream: new PrintStream(outputStream, true, Charsets.UTF_8.name()), - script: checkNotNull(getScript(request, scriptPath), "Script cannot be empty.") + request: request, + response: response, + outputStream: outputStream, + printStream: new PrintStream(outputStream, true, Charsets.UTF_8.name()), + script: checkNotNull(getScript(request, scriptPath), "Script cannot be empty.") ) } @@ -90,9 +91,9 @@ class ScriptPostServlet extends AbstractJsonResponseServlet { def session = request.resourceResolver.adaptTo(Session) def binary = session.getNode(scriptPath) - .getNode(JcrConstants.JCR_CONTENT) - .getProperty(JcrConstants.JCR_DATA) - .binary + .getNode(JcrConstants.JCR_CONTENT) + .getProperty(JcrConstants.JCR_DATA) + .binary def script = binary.stream.text diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/servlets/ScriptSavingServlet.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/ScriptSavingServlet.groovy similarity index 73% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/servlets/ScriptSavingServlet.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/ScriptSavingServlet.groovy index eec00684..7718e2ee 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/servlets/ScriptSavingServlet.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/ScriptSavingServlet.groovy @@ -1,7 +1,8 @@ -package org.cid15.aem.groovy.console.servlets +package be.orbinson.aem.groovy.console.servlets -import org.cid15.aem.groovy.console.GroovyConsoleService -import org.cid15.aem.groovy.console.api.impl.RequestScriptData + +import be.orbinson.aem.groovy.console.GroovyConsoleService +import be.orbinson.aem.groovy.console.api.impl.RequestScriptData import org.apache.sling.api.SlingHttpServletRequest import org.apache.sling.api.SlingHttpServletResponse import org.osgi.service.component.annotations.Component @@ -11,7 +12,7 @@ import javax.servlet.Servlet import javax.servlet.ServletException @Component(service = Servlet, immediate = true, property = [ - "sling.servlet.paths=/bin/groovyconsole/save" + "sling.servlet.paths=/bin/groovyconsole/save" ]) class ScriptSavingServlet extends AbstractJsonResponseServlet { @@ -20,7 +21,7 @@ class ScriptSavingServlet extends AbstractJsonResponseServlet { @Override protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws - ServletException, IOException { + ServletException, IOException { def scriptData = new RequestScriptData(request) writeJsonResponse(response, consoleService.saveScript(scriptData)) diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/servlets/ServicesListServlet.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/ServicesListServlet.groovy similarity index 95% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/servlets/ServicesListServlet.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/ServicesListServlet.groovy index 4819cea5..21a8ce85 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/servlets/ServicesListServlet.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/servlets/ServicesListServlet.groovy @@ -1,4 +1,4 @@ -package org.cid15.aem.groovy.console.servlets +package be.orbinson.aem.groovy.console.servlets import org.apache.commons.lang3.StringUtils import org.apache.sling.api.SlingHttpServletRequest @@ -17,7 +17,7 @@ import static org.apache.sling.api.adapter.AdapterFactory.ADAPTER_CLASSES import static org.osgi.framework.Constants.OBJECTCLASS @Component(service = Servlet, immediate = true, property = [ - "sling.servlet.paths=/bin/groovyconsole/services" + "sling.servlet.paths=/bin/groovyconsole/services" ]) class ServicesListServlet extends AbstractJsonResponseServlet { @@ -25,7 +25,7 @@ class ServicesListServlet extends AbstractJsonResponseServlet { @Override protected void doGet(SlingHttpServletRequest request, - SlingHttpServletResponse response) throws ServletException, IOException { + SlingHttpServletResponse response) throws ServletException, IOException { writeJsonResponse(response, adaptersMap + servicesMap) } diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/table/Table.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/table/Table.groovy similarity index 96% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/table/Table.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/table/Table.groovy index 9bb37b7e..4ba8a2d7 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/table/Table.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/table/Table.groovy @@ -1,4 +1,4 @@ -package org.cid15.aem.groovy.console.table +package be.orbinson.aem.groovy.console.table class Table { diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/utils/GroovyScriptUtils.groovy b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/utils/GroovyScriptUtils.groovy similarity index 94% rename from bundle/src/main/groovy/org/cid15/aem/groovy/console/utils/GroovyScriptUtils.groovy rename to bundle/src/main/groovy/be/orbinson/aem/groovy/console/utils/GroovyScriptUtils.groovy index ad9991c4..b64f99ef 100644 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/utils/GroovyScriptUtils.groovy +++ b/bundle/src/main/groovy/be/orbinson/aem/groovy/console/utils/GroovyScriptUtils.groovy @@ -1,4 +1,4 @@ -package org.cid15.aem.groovy.console.utils +package be.orbinson.aem.groovy.console.utils final class GroovyScriptUtils { diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/extension/impl/DefaultBindingExtensionProvider.groovy b/bundle/src/main/groovy/org/cid15/aem/groovy/console/extension/impl/DefaultBindingExtensionProvider.groovy deleted file mode 100644 index d34b8f04..00000000 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/extension/impl/DefaultBindingExtensionProvider.groovy +++ /dev/null @@ -1,88 +0,0 @@ -package org.cid15.aem.groovy.console.extension.impl - -import com.day.cq.search.QueryBuilder -import com.day.cq.wcm.api.PageManager -import org.cid15.aem.groovy.console.api.BindingExtensionProvider -import org.cid15.aem.groovy.console.api.BindingVariable -import org.cid15.aem.groovy.console.api.context.ScriptContext -import org.cid15.aem.groovy.console.api.context.ServletScriptContext -import com.icfolson.aem.groovy.extension.builders.NodeBuilder -import com.icfolson.aem.groovy.extension.builders.PageBuilder -import groovy.json.JsonException -import groovy.json.JsonSlurper -import org.apache.sling.api.SlingHttpServletRequest -import org.apache.sling.api.SlingHttpServletResponse -import org.apache.sling.api.resource.ResourceResolver -import org.osgi.framework.BundleContext -import org.osgi.service.component.annotations.Activate -import org.osgi.service.component.annotations.Component -import org.osgi.service.component.annotations.Reference -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -import javax.jcr.Session - -@Component(service = BindingExtensionProvider, immediate = true) -class DefaultBindingExtensionProvider implements BindingExtensionProvider { - - @Reference - private QueryBuilder queryBuilder - - private BundleContext bundleContext - - @Override - Map getBindingVariables(ScriptContext scriptContext) { - def resourceResolver = scriptContext.resourceResolver - def session = resourceResolver.adaptTo(Session) - - def bindingVariables = [ - log: new BindingVariable(LoggerFactory.getLogger("groovyconsole"), Logger, - "http://www.slf4j.org/api/org/slf4j/Logger.html"), - session: new BindingVariable(session, Session, - "https://docs.adobe.com/docs/en/spec/javax.jcr/javadocs/jcr-2.0/javax/jcr/Session.html"), - pageManager: new BindingVariable(resourceResolver.adaptTo(PageManager), PageManager), - resourceResolver: new BindingVariable(resourceResolver, ResourceResolver, - "https://sling.apache.org/apidocs/sling10/org/apache/sling/api/resource/ResourceResolver.html"), - queryBuilder: new BindingVariable(queryBuilder, QueryBuilder, - "https://helpx.adobe.com/experience-manager/6-4/sites/developing/using/reference-materials/javadoc" + - "/com/day/cq/search/QueryBuilder.html"), - nodeBuilder: new BindingVariable(new NodeBuilder(session), NodeBuilder, - "http://code.digitalatolson.com/aem-groovy-extension/groovydocs/com/icfolson/aem/groovy/extension" + - "/builders/NodeBuilder.html"), - pageBuilder: new BindingVariable(new PageBuilder(session), PageBuilder, - "http://code.digitalatolson.com/aem-groovy-extension/groovydocs/com/icfolson/aem/groovy/extension" + - "/builders/PageBuilder.html"), - bundleContext: new BindingVariable(bundleContext, BundleContext, - "http://www.osgi.org/javadoc/r4v43/core/org/osgi/framework/BundleContext.html"), - out: new BindingVariable(scriptContext.printStream, PrintStream, - "https://docs.oracle.com/javase/8/docs/api/java/io/PrintStream.html") - ] - - if (scriptContext instanceof ServletScriptContext) { - bindingVariables.putAll([ - slingRequest: new BindingVariable(scriptContext.request, SlingHttpServletRequest, - "https://sling.apache.org/apidocs/sling10/org/apache/sling/api/SlingHttpServletRequest.html"), - slingResponse: new BindingVariable(scriptContext.response, SlingHttpServletResponse, - "https://sling.apache.org/apidocs/sling10/org/apache/sling/api/SlingHttpServletResponse.html") - ]) - } - - if (scriptContext.data) { - try { - def json = new JsonSlurper().parseText(scriptContext.data) - - bindingVariables["data"] = new BindingVariable(json, json.class) - } catch (JsonException ignored) { - // if data cannot be parsed as a JSON object, bind it as a String - bindingVariables["data"] = new BindingVariable(scriptContext.data, String) - } - } - - bindingVariables - } - - @Activate - void activate(BundleContext bundleContext) { - this.bundleContext = bundleContext - } -} \ No newline at end of file diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/extension/impl/DefaultStarImportExtensionProvider.groovy b/bundle/src/main/groovy/org/cid15/aem/groovy/console/extension/impl/DefaultStarImportExtensionProvider.groovy deleted file mode 100644 index 7999309c..00000000 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/extension/impl/DefaultStarImportExtensionProvider.groovy +++ /dev/null @@ -1,36 +0,0 @@ -package org.cid15.aem.groovy.console.extension.impl - -import com.google.common.collect.ImmutableSet -import org.cid15.aem.groovy.console.api.StarImport -import org.cid15.aem.groovy.console.api.StarImportExtensionProvider -import org.osgi.service.component.annotations.Component - -@Component(service = StarImportExtensionProvider, immediate = true) -class DefaultStarImportExtensionProvider implements StarImportExtensionProvider { - - private static final String AEM_JAVADOC_PREFIX = "https://helpx.adobe" + - ".com/experience-manager/6-5/sites/developing/using/reference-materials/javadoc" - - private static final String JCR_JAVADOC_PREFIX = "https://docs.adobe.com/docs/en/spec/javax.jcr/javadocs/jcr-2.0" - - private static final String SLING_JAVADOC_PREFIX = "http://sling.apache.org/apidocs/sling9" - - private static final String JAVADOC_SUFFIX = "package-summary.html" - - private static final Set IMPORTS = ImmutableSet.of( - new StarImport("com.day.cq.dam.api", "$AEM_JAVADOC_PREFIX/com/day/cq/dam/api/$JAVADOC_SUFFIX"), - new StarImport("com.day.cq.search", "$AEM_JAVADOC_PREFIX/com/day/cq/search/$JAVADOC_SUFFIX"), - new StarImport("com.day.cq.tagging", "$AEM_JAVADOC_PREFIX/com/day/cq/tagging/$JAVADOC_SUFFIX"), - new StarImport("com.day.cq.wcm.api", "$AEM_JAVADOC_PREFIX/com/day/cq/wcm/api/$JAVADOC_SUFFIX"), - new StarImport("com.day.cq.replication", "$AEM_JAVADOC_PREFIX/com/day/cq/replication/$JAVADOC_SUFFIX"), - new StarImport("javax.jcr", "$JCR_JAVADOC_PREFIX/javax/jcr/$JAVADOC_SUFFIX"), - new StarImport("org.apache.sling.api", "$SLING_JAVADOC_PREFIX/org/apache/sling/api/$JAVADOC_SUFFIX"), - new StarImport("org.apache.sling.api.resource", - "$SLING_JAVADOC_PREFIX/org/apache/sling/api/resource/$JAVADOC_SUFFIX") - ) - - @Override - Set getStarImports() { - IMPORTS - } -} \ No newline at end of file diff --git a/bundle/src/main/groovy/org/cid15/aem/groovy/console/response/impl/DefaultRunScriptResponse.groovy b/bundle/src/main/groovy/org/cid15/aem/groovy/console/response/impl/DefaultRunScriptResponse.groovy deleted file mode 100644 index 70b85702..00000000 --- a/bundle/src/main/groovy/org/cid15/aem/groovy/console/response/impl/DefaultRunScriptResponse.groovy +++ /dev/null @@ -1,149 +0,0 @@ -package org.cid15.aem.groovy.console.response.impl - -import com.day.cq.commons.jcr.JcrConstants -import com.day.cq.commons.jcr.JcrUtil -import com.day.text.Text -import com.google.common.net.MediaType -import org.cid15.aem.groovy.console.api.JobProperties -import org.cid15.aem.groovy.console.api.context.JobScriptContext -import org.cid15.aem.groovy.console.api.context.ScriptContext -import org.cid15.aem.groovy.console.response.RunScriptResponse -import org.cid15.aem.groovy.console.table.Table -import groovy.json.JsonBuilder -import groovy.transform.TupleConstructor -import org.apache.commons.lang3.exception.ExceptionUtils -import org.apache.sling.api.resource.Resource -import org.apache.sling.api.resource.ResourceUtil - -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.DATA -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.DATE_FORMAT_FILE_NAME -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.EXCEPTION_STACK_TRACE -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.JOB_ID -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.MEDIA_TYPE_EXTENSIONS -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.OUTPUT -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.RESULT -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.RUNNING_TIME -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.SCRIPT - -@TupleConstructor -class DefaultRunScriptResponse implements RunScriptResponse { - - private static final int LEVEL_USERID = 4 - - static RunScriptResponse fromResult(ScriptContext scriptContext, Object result, String output, String runningTime) { - def resultString - - if (result instanceof Table) { - resultString = new JsonBuilder([table: result]).toString() - } else { - resultString = result as String - } - - new DefaultRunScriptResponse( - date: Calendar.instance, - script: scriptContext.script, - data: scriptContext.data, - result: resultString, - output: output, - exceptionStackTrace: "", - runningTime: runningTime, - userId: scriptContext.userId, - jobId: scriptContext instanceof JobScriptContext ? scriptContext.jobId : null, - jobProperties: scriptContext instanceof JobScriptContext ? scriptContext.jobProperties : null - ) - } - - static RunScriptResponse fromException(ScriptContext scriptContext, String output, Throwable throwable) { - def exceptionStackTrace = ExceptionUtils.getStackTrace(throwable) - - new DefaultRunScriptResponse( - date: Calendar.instance, - script: scriptContext.script, - data: scriptContext.data, - result: "", - output: output, - exceptionStackTrace: exceptionStackTrace, - runningTime: "", - userId: scriptContext.userId, - jobId: scriptContext instanceof JobScriptContext ? scriptContext.jobId : null, - jobProperties: scriptContext instanceof JobScriptContext ? scriptContext.jobProperties : null - ) - } - - static RunScriptResponse fromAuditRecordResource(Resource resource) { - def properties = resource.valueMap - - def exceptionStackTrace = properties.get(EXCEPTION_STACK_TRACE, "") - def userIdResourcePath = ResourceUtil.getParent(resource.path, LEVEL_USERID) - def userId = Text.getName(userIdResourcePath) - - new DefaultRunScriptResponse( - date: properties.get(JcrConstants.JCR_CREATED, Calendar), - script: properties.get(SCRIPT, ""), - data: properties.get(DATA, ""), - result: exceptionStackTrace ? "" : properties.get(RESULT, ""), - output: properties.get(OUTPUT, ""), - exceptionStackTrace: exceptionStackTrace ?: "", - runningTime: exceptionStackTrace ? "" : properties.get(RUNNING_TIME, ""), - userId: userId, - jobId: properties.get(JOB_ID, String), - jobProperties: JobProperties.fromValueMap(properties) - ) - } - - Calendar date - - String script - - String data - - String result - - String output - - String exceptionStackTrace - - String runningTime - - String userId - - String jobId - - JobProperties jobProperties - - @Override - String getMediaType() { - def mediaType - - if (jobProperties?.mediaType) { - mediaType = MediaType.parse(jobProperties.mediaType) - } else { - mediaType = MediaType.PLAIN_TEXT_UTF_8 - } - - mediaType.withoutParameters().toString() - } - - @Override - String getOutputFileName() { - new StringBuilder() - .append(outputFileNamePrefix) - .append(date.format(DATE_FORMAT_FILE_NAME)) - .append(".") - .append(MEDIA_TYPE_EXTENSIONS[mediaType]) - .toString() - } - - private String getOutputFileNamePrefix() { - def outputFileNamePrefix - - if (jobProperties?.jobTitle) { - outputFileNamePrefix = JcrUtil.createValidName(jobProperties.jobTitle, - JcrUtil.HYPHEN_LABEL_CHAR_MAPPING).toLowerCase() + "-" - } else { - outputFileNamePrefix = "output-" - } - - outputFileNamePrefix - } -} diff --git a/bundle/src/main/java/org/cid15/aem/groovy/console/configuration/impl/ConfigurationServiceProperties.java b/bundle/src/main/java/be/orbinson/aem/groovy/console/configuration/impl/ConfigurationServiceProperties.java similarity index 74% rename from bundle/src/main/java/org/cid15/aem/groovy/console/configuration/impl/ConfigurationServiceProperties.java rename to bundle/src/main/java/be/orbinson/aem/groovy/console/configuration/impl/ConfigurationServiceProperties.java index f54e5412..f163eac6 100644 --- a/bundle/src/main/java/org/cid15/aem/groovy/console/configuration/impl/ConfigurationServiceProperties.java +++ b/bundle/src/main/java/be/orbinson/aem/groovy/console/configuration/impl/ConfigurationServiceProperties.java @@ -1,4 +1,4 @@ -package org.cid15.aem.groovy.console.configuration.impl; +package be.orbinson.aem.groovy.console.configuration.impl; import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.ObjectClassDefinition; @@ -32,10 +32,15 @@ boolean auditDisabled() default false; @AttributeDefinition(name = "Display All Audit Records?", - description = "If enabled, all audit records (including records for other users) will be displayed in the console history.") + description = "If enabled, all audit records (including records for other users) will be displayed in the console history.") boolean auditDisplayAll() default false; @AttributeDefinition(name = "Thread Timeout", - description = "Time in seconds that scripts are allowed to execute before being interrupted. If 0, no timeout is enforced.") + description = "Time in seconds that scripts are allowed to execute before being interrupted. If 0, no timeout is enforced.") long threadTimeout() default 0; -} \ No newline at end of file + + @AttributeDefinition(name = "Distributed execution enabled?", + description = "If enabled, a script will be able to be replicated from an author and executed on all default replication agents." + ) + boolean distributedExecutionEnabled() default false; +} diff --git a/bundle/src/main/javadoc/README b/bundle/src/main/javadoc/README deleted file mode 100644 index 30c5e1de..00000000 --- a/bundle/src/main/javadoc/README +++ /dev/null @@ -1 +0,0 @@ -The AEM Groovy Console does not provide a Javadoc as it contains no Java source classes. See the published source JAR for comments and implementation details. \ No newline at end of file diff --git a/bundle/src/test/groovy/be/orbinson/aem/groovy/console/audit/impl/DefaultAuditServiceTest.groovy b/bundle/src/test/groovy/be/orbinson/aem/groovy/console/audit/impl/DefaultAuditServiceTest.groovy new file mode 100644 index 00000000..36f1cebe --- /dev/null +++ b/bundle/src/test/groovy/be/orbinson/aem/groovy/console/audit/impl/DefaultAuditServiceTest.groovy @@ -0,0 +1,137 @@ +package be.orbinson.aem.groovy.console.audit.impl + +import be.orbinson.aem.groovy.console.api.impl.RequestScriptContext +import be.orbinson.aem.groovy.console.audit.AuditRecord +import be.orbinson.aem.groovy.console.audit.AuditService +import be.orbinson.aem.groovy.console.configuration.impl.DefaultConfigurationService +import be.orbinson.aem.groovy.console.response.impl.DefaultRunScriptResponse +import io.wcm.testing.mock.aem.junit5.AemContext +import io.wcm.testing.mock.aem.junit5.AemContextExtension +import org.apache.commons.lang3.exception.ExceptionUtils +import org.apache.sling.testing.mock.sling.ResourceResolverType +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +import static org.junit.jupiter.api.Assertions.assertEquals +import static org.junit.jupiter.api.Assertions.assertNotNull + +@ExtendWith(AemContextExtension.class) +class DefaultAuditServiceTest { + + private final AemContext context = new AemContext(ResourceResolverType.JCR_MOCK); + + AuditService auditService; + + @BeforeEach + void beforeEach() { + context.build().resource("/var/groovyconsole").commit(); + context.registerInjectActivateService(new DefaultConfigurationService()) + auditService = context.registerInjectActivateService(new DefaultAuditService()) + } + + @Test + void createAuditRecordForScriptWithResultAndOutput() { + def request = context.request() + def response = context.response() + + def script = "script content" + def output = "output" + def runningTime = "running time" + def result = "result" + + def scriptContext = new RequestScriptContext(request, response, new ByteArrayOutputStream(), null, script) + + def runScriptResponse = DefaultRunScriptResponse.fromResult(scriptContext, result, output, runningTime) + + def auditRecord = auditService.createAuditRecord(runScriptResponse) + + assertNotNull(context.resourceResolver().getResource(auditRecord.path)) + + assertEquals(auditRecord.script, script) + assertEquals(auditRecord.result, result) + assertEquals(auditRecord.output, output) + } + + @Test + void createAuditRecordWithException() { + def request = context.request() + def response = context.response() + + def scriptContext = new RequestScriptContext(request, response, new ByteArrayOutputStream(), null, "script content") + + def exception = new RuntimeException("") + + def runScriptResponse = DefaultRunScriptResponse.fromException(scriptContext, "output", exception) + + def auditRecord = auditService.createAuditRecord(runScriptResponse) + + assertNotNull(context.resourceResolver().getResource(auditRecord.path)) + + assertEquals(auditRecord.script, "script content") + assertEquals(auditRecord.output, "output") + assertEquals(auditRecord.exceptionStackTrace, ExceptionUtils.getStackTrace(exception)) + + } + + @Test + void createMultipleAuditRecords() { + def request = context.request() + def response = context.response() + + def scriptContext = new RequestScriptContext(request, response, new ByteArrayOutputStream(), null, "script content") + + def runScriptResponse = DefaultRunScriptResponse.fromResult(scriptContext, "result", "output", "running time") + + def auditRecords = [] + + (1..5).each { + auditRecords.add(auditService.createAuditRecord(runScriptResponse)) + } + + assertAuditRecordsCreated(auditRecords) + } + + @Test + void getAuditRecordsForValidDateRange() { + def request = context.request() + def response = context.response() + + def scriptContext = new RequestScriptContext(request, response, new ByteArrayOutputStream(), null, "script content") + + def runScriptResponse = DefaultRunScriptResponse.fromResult(scriptContext, "result", "output", "running time") + + auditService.createAuditRecord(runScriptResponse) + + def tests = [ + [startDateOffset: -2, endDateOffset: -1, size: 0], + [startDateOffset: -1, endDateOffset: 0, size: 1], + [startDateOffset: 0, endDateOffset: 0, size: 1], + [startDateOffset: 0, endDateOffset: 1, size: 1], + [startDateOffset: -1, endDateOffset: 1, size: 1], + [startDateOffset: 1, endDateOffset: 2, size: 0] + ] + tests.each { map -> + def startDate = getDate(map.startDateOffset) + def endDate = getDate(map.endDateOffset) + assertEquals(map.size, auditService.getAuditRecords(context.resourceResolver().userID, startDate, endDate).size()) + } + } + + private Calendar getDate(Integer offset) { + def date = (new Date() + offset).toCalendar() + + date.set(Calendar.HOUR_OF_DAY, 0) + date.set(Calendar.MINUTE, 0) + date.set(Calendar.SECOND, 0) + date.set(Calendar.MILLISECOND, 0) + + date + } + + private void assertAuditRecordsCreated(List auditRecords) { + auditRecords.each { + assertNotNull(context.resourceResolver().getResource(it.path)) + } + } +} diff --git a/bundle/src/test/groovy/org/cid15/aem/groovy/console/extension/impl/DefaultExtensionServiceSpec.groovy b/bundle/src/test/groovy/be/orbinson/aem/groovy/console/extension/impl/DefaultExtensionServiceTest.groovy similarity index 54% rename from bundle/src/test/groovy/org/cid15/aem/groovy/console/extension/impl/DefaultExtensionServiceSpec.groovy rename to bundle/src/test/groovy/be/orbinson/aem/groovy/console/extension/impl/DefaultExtensionServiceTest.groovy index e4ae7fcc..7000634d 100644 --- a/bundle/src/test/groovy/org/cid15/aem/groovy/console/extension/impl/DefaultExtensionServiceSpec.groovy +++ b/bundle/src/test/groovy/be/orbinson/aem/groovy/console/extension/impl/DefaultExtensionServiceTest.groovy @@ -1,24 +1,30 @@ -package org.cid15.aem.groovy.console.extension.impl +package be.orbinson.aem.groovy.console.extension.impl +import be.orbinson.aem.groovy.console.api.* +import be.orbinson.aem.groovy.console.api.context.ScriptContext +import be.orbinson.aem.groovy.console.api.impl.RequestScriptContext +import be.orbinson.aem.groovy.console.extension.ExtensionService import com.google.common.io.ByteStreams -import org.cid15.aem.groovy.console.api.impl.RequestScriptContext -import com.icfolson.aem.prosper.specs.ProsperSpec -import org.cid15.aem.groovy.console.api.BindingExtensionProvider -import org.cid15.aem.groovy.console.api.BindingVariable -import org.cid15.aem.groovy.console.api.ScriptMetaClassExtensionProvider -import org.cid15.aem.groovy.console.api.StarImport -import org.cid15.aem.groovy.console.api.StarImportExtensionProvider -import org.cid15.aem.groovy.console.api.context.ScriptContext -import org.cid15.aem.groovy.console.extension.ExtensionService +import io.wcm.testing.mock.aem.junit5.AemContext +import io.wcm.testing.mock.aem.junit5.AemContextExtension +import org.apache.sling.testing.mock.sling.ResourceResolverType import org.codehaus.groovy.control.CompilerConfiguration import org.codehaus.groovy.control.MultipleCompilationErrorsException import org.codehaus.groovy.control.customizers.CompilationCustomizer +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith import java.text.SimpleDateFormat -class DefaultExtensionServiceSpec extends ProsperSpec { +import static org.junit.jupiter.api.Assertions.assertEquals +import static org.junit.jupiter.api.Assertions.assertThrows - static final def SELECTORS = ["mobile"] +@ExtendWith(AemContextExtension.class) +class DefaultExtensionServiceTest { + + private final AemContext context = new AemContext(ResourceResolverType.JCR_MOCK); + + static final def SELECTORS = "mobile" static final def PARAMETERS = [firstName: "Clarence", lastName: "Wiggum"] @@ -37,8 +43,8 @@ class DefaultExtensionServiceSpec extends ProsperSpec { @Override Map getBindingVariables(ScriptContext scriptContext) { [ - parameterNames: new BindingVariable((scriptContext as RequestScriptContext).request.parameterMap.keySet()), - selectors: new BindingVariable([]) + parameterNames: new BindingVariable((scriptContext as RequestScriptContext).request.parameterMap.keySet()), + selectors : new BindingVariable([]) ] } } @@ -48,8 +54,8 @@ class DefaultExtensionServiceSpec extends ProsperSpec { @Override Map getBindingVariables(ScriptContext scriptContext) { [ - path: new BindingVariable((scriptContext as RequestScriptContext).request.requestPathInfo.resourcePath), - selectors: new BindingVariable((scriptContext as RequestScriptContext).request.requestPathInfo.selectors as List) + path : new BindingVariable((scriptContext as RequestScriptContext).request.requestPathInfo.resourcePath), + selectors: new BindingVariable((scriptContext as RequestScriptContext).request.requestPathInfo.selectors as List) ] } } @@ -66,57 +72,45 @@ class DefaultExtensionServiceSpec extends ProsperSpec { } } - def "get compilation customizers"() { - setup: + @Test + void getCompilationCustomizers() { def extensionService = new DefaultExtensionService() def firstProvider = new TestStarImportExtensionProvider() - when: extensionService.bindStarImportExtensionProvider(firstProvider) - then: - extensionService.compilationCustomizers.size() == 1 + assertEquals(extensionService.compilationCustomizers.size(), 1) - when: extensionService.unbindStarImportExtensionProvider(firstProvider) - then: - extensionService.compilationCustomizers.size() == 0 + assertEquals(extensionService.compilationCustomizers.size(), 0) } - def "star imports"() { - setup: + @Test + void starImports() { def extensionService = new DefaultExtensionService() def starImportExtensionProvider = new TestStarImportExtensionProvider() - when: extensionService.bindStarImportExtensionProvider(starImportExtensionProvider) - and: runScriptWithExtensionService(extensionService) - then: - notThrown(MultipleCompilationErrorsException) - - when: extensionService.unbindStarImportExtensionProvider(starImportExtensionProvider) - and: - runScriptWithExtensionService(extensionService) - then: - thrown(MultipleCompilationErrorsException) + assertThrows(MultipleCompilationErrorsException) { + runScriptWithExtensionService(extensionService) + } } - def "get binding"() { - setup: - def request = requestBuilder.build { - path = "/" - selectors = SELECTORS - parameterMap = PARAMETERS - } + @Test + void getBinding() { + def request = context.request(); + request.setParameterMap(PARAMETERS); + request.getRequestPathInfo().setSelectorString(SELECTORS) + request.getRequestPathInfo().setResourcePath("/") - def response = responseBuilder.build() + def response = context.response() def scriptContext = new RequestScriptContext(request, response, null, null, null) @@ -124,31 +118,23 @@ class DefaultExtensionServiceSpec extends ProsperSpec { def firstProvider = new FirstBindingExtensionProvider() def secondProvider = new SecondBindingExtensionProvider() - when: extensionService.bindBindingExtensionProvider(firstProvider) extensionService.bindBindingExtensionProvider(secondProvider) - then: - extensionService.getBindingVariables(scriptContext)["selectors"].value == request.requestPathInfo.selectors as List - extensionService.getBindingVariables(scriptContext)["parameterNames"].value == request.parameterMap.keySet() - extensionService.getBindingVariables(scriptContext)["path"].value == "/" + assert extensionService.getBindingVariables(scriptContext)["selectors"].value == request.requestPathInfo.selectors as List + assert extensionService.getBindingVariables(scriptContext)["parameterNames"].value == request.parameterMap.keySet() + assert extensionService.getBindingVariables(scriptContext)["path"].value == "/" - when: extensionService.unbindBindingExtensionProvider(secondProvider) - then: - extensionService.getBindingVariables(scriptContext)["selectors"].value == [] + assert extensionService.getBindingVariables(scriptContext)["selectors"].value == [] - and: - !extensionService.getBindingVariables(scriptContext)["path"] + assert !extensionService.getBindingVariables(scriptContext)["path"] } - def "get script metaclasses"() { - setup: - def request = requestBuilder.build { - selectors = SELECTORS - parameterMap = PARAMETERS - } + @Test + void getScriptMetaClasses() { + def request = context.request(); def scriptContext = new RequestScriptContext(request) @@ -156,25 +142,21 @@ class DefaultExtensionServiceSpec extends ProsperSpec { def firstProvider = new TestScriptMetaClassExtensionProvider() def secondProvider = new TestScriptMetaClassExtensionProvider() - when: extensionService.bindScriptMetaClassExtensionProvider(firstProvider) extensionService.bindScriptMetaClassExtensionProvider(secondProvider) - then: - extensionService.getScriptMetaClasses(scriptContext).size() == 2 + assert extensionService.getScriptMetaClasses(scriptContext).size() == 2 - when: extensionService.unbindScriptMetaClassExtensionProvider(secondProvider) - then: - extensionService.getScriptMetaClasses(scriptContext).size() == 1 + assert extensionService.getScriptMetaClasses(scriptContext).size() == 1 } private void runScriptWithExtensionService(ExtensionService extensionService) { def binding = new Binding(out: new PrintStream(ByteStreams.nullOutputStream())) def configuration = new CompilerConfiguration().addCompilationCustomizers( - extensionService.compilationCustomizers as CompilationCustomizer[]) + extensionService.compilationCustomizers as CompilationCustomizer[]) new GroovyShell(binding, configuration).parse(SCRIPT).run() } diff --git a/bundle/src/test/groovy/be/orbinson/aem/groovy/console/impl/DefaultGroovyConsoleServiceTest.groovy b/bundle/src/test/groovy/be/orbinson/aem/groovy/console/impl/DefaultGroovyConsoleServiceTest.groovy new file mode 100755 index 00000000..a87c8a8d --- /dev/null +++ b/bundle/src/test/groovy/be/orbinson/aem/groovy/console/impl/DefaultGroovyConsoleServiceTest.groovy @@ -0,0 +1,123 @@ +package be.orbinson.aem.groovy.console.impl + +import be.orbinson.aem.groovy.console.GroovyConsoleService +import be.orbinson.aem.groovy.console.api.impl.RequestScriptContext +import be.orbinson.aem.groovy.console.api.impl.RequestScriptData +import be.orbinson.aem.groovy.console.audit.AuditService +import be.orbinson.aem.groovy.console.configuration.ConfigurationService +import be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants +import be.orbinson.aem.groovy.console.extension.impl.DefaultBindingExtensionProvider +import be.orbinson.aem.groovy.console.extension.impl.DefaultExtensionService +import be.orbinson.aem.groovy.console.extension.impl.DefaultScriptMetaClassExtensionProvider +import com.day.cq.commons.jcr.JcrConstants +import com.day.cq.replication.Replicator +import com.day.cq.search.QueryBuilder +import com.google.common.base.Charsets +import io.wcm.testing.mock.aem.junit5.AemContext +import io.wcm.testing.mock.aem.junit5.AemContextExtension +import org.apache.sling.event.jobs.JobManager +import org.apache.sling.testing.mock.sling.ResourceResolverType +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +import javax.jcr.Session + +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.PATH_SCRIPTS_FOLDER +import static be.orbinson.aem.groovy.console.constants.GroovyConsoleConstants.SCRIPT +import static org.junit.jupiter.api.Assertions.* +import static org.mockito.Mockito.mock + +@ExtendWith(AemContextExtension.class) +class DefaultGroovyConsoleServiceTest { + + private final AemContext context = new AemContext(ResourceResolverType.JCR_MOCK); + + def SCRIPT_NAME = "Script" + + def SCRIPT_FILE_NAME = "${SCRIPT_NAME}.groovy" + + def PATH_FILE = "$PATH_SCRIPTS_FOLDER/$SCRIPT_FILE_NAME" + + def PATH_FILE_CONTENT = "$PATH_FILE/${JcrConstants.JCR_CONTENT}" + + @BeforeEach + void beforeEach() { + context.registerService(JobManager, mock(JobManager)) + context.registerService(QueryBuilder, mock(QueryBuilder)) + context.registerService(ConfigurationService, mock(ConfigurationService)) + context.registerService(AuditService, mock(AuditService)) + context.registerService(Replicator, mock(Replicator)) + context.registerInjectActivateService(new DefaultBindingExtensionProvider()) + context.registerInjectActivateService(new DefaultExtensionService()) + context.registerInjectActivateService(new DefaultScriptMetaClassExtensionProvider()) + context.registerInjectActivateService(new DefaultGroovyConsoleService()) + } + + @Test + void runScript() { + def consoleService = context.getService(GroovyConsoleService) + + def request = context.request() + def response = context.response(); + + def outputStream = new ByteArrayOutputStream() + + def scriptContext = new RequestScriptContext( + request: request, + response: response, + outputStream: outputStream, + printStream: new PrintStream(outputStream, true, Charsets.UTF_8.name()), + script: scriptAsString + ) + + def map = consoleService.runScript(scriptContext) + assertScriptResult(map) + } + + @Test + void saveScript() { + + def consoleService = context.getService(GroovyConsoleService) + + def request = context.request(); + request.setParameterMap(this.parameterMap) + + def scriptData = new RequestScriptData(request) + + consoleService.saveScript(scriptData) + + assertNodeExists(PATH_SCRIPTS_FOLDER, JcrConstants.NT_FOLDER) + assertNodeExists(PATH_FILE, JcrConstants.NT_FILE) + assertNodeExists(PATH_FILE_CONTENT, JcrConstants.NT_RESOURCE) + + assertNotNull(context.resourceResolver().adaptTo(Session).getNode(PATH_FILE_CONTENT).getProperty(JcrConstants.JCR_DATA).getBinary().getStream().getText()) + } + + void assertScriptResult(map) { + assertNull(map.result) + assertEquals("BEER" + System.lineSeparator(), map.output) + assertEquals("",map.exceptionStackTrace) + assertNotNull(map.runningTime) + } + + private String getScriptAsString() { + def scriptAsString = null + + this.class.getResourceAsStream("/$SCRIPT_FILE_NAME").withStream { stream -> + scriptAsString = stream.text + } + + scriptAsString + } + + private Map getParameterMap() { + [(GroovyConsoleConstants.FILE_NAME): (SCRIPT_NAME), (SCRIPT): scriptAsString] + } + + void assertNodeExists(String path, String type) { + def node = context.resourceResolver().getResource(path); + assertNotNull(node) + assertTrue(node.isResourceType(type)) + } +} diff --git a/bundle/src/test/groovy/org/cid15/aem/groovy/console/audit/impl/DefaultAuditServiceSpec.groovy b/bundle/src/test/groovy/org/cid15/aem/groovy/console/audit/impl/DefaultAuditServiceSpec.groovy deleted file mode 100644 index e190891c..00000000 --- a/bundle/src/test/groovy/org/cid15/aem/groovy/console/audit/impl/DefaultAuditServiceSpec.groovy +++ /dev/null @@ -1,146 +0,0 @@ -package org.cid15.aem.groovy.console.audit.impl - -import org.cid15.aem.groovy.console.api.impl.RequestScriptContext -import org.cid15.aem.groovy.console.configuration.impl.DefaultConfigurationService -import com.icfolson.aem.prosper.specs.ProsperSpec -import org.apache.commons.lang3.exception.ExceptionUtils -import org.apache.sling.jcr.resource.JcrResourceConstants -import org.cid15.aem.groovy.console.audit.AuditRecord -import org.cid15.aem.groovy.console.response.impl.DefaultRunScriptResponse -import spock.lang.Shared -import spock.lang.Unroll - -@Unroll -class DefaultAuditServiceSpec extends ProsperSpec { - - @Shared - DefaultAuditService auditService = new DefaultAuditService() - - def setupSpec() { - pageBuilder.var { - groovyconsole(JcrResourceConstants.NT_SLING_FOLDER) - } - - slingContext.registerInjectActivateService(new DefaultConfigurationService()) - slingContext.registerInjectActivateService(auditService) - } - - def cleanup() { - // remove all audit nodes - auditService.getAllAuditRecords(resourceResolver.userID)*.path.each { - session.getNode(it).remove() - } - - session.save() - } - - def "create audit record for script with result and output"() { - when: - def request = requestBuilder.build() - def response = responseBuilder.build() - - def scriptContext = new RequestScriptContext(request, response, new ByteArrayOutputStream(), null, script) - - def runScriptResponse = DefaultRunScriptResponse.fromResult(scriptContext, result, output, runningTime) - - def auditRecord = auditService.createAuditRecord(runScriptResponse) - - then: - assertNodeExists(auditRecord.path) - - and: - auditRecord.script == script - auditRecord.result == result - auditRecord.output == output - - where: - script | result | output | runningTime - "script content" | "result" | "output" | "running time" - } - - def "create audit record for script with exception"() { - when: - def request = requestBuilder.build() - def response = responseBuilder.build() - - def scriptContext = new RequestScriptContext(request, response, new ByteArrayOutputStream(), null, "script content") - - def exception = new RuntimeException("") - - def runScriptResponse = DefaultRunScriptResponse.fromException(scriptContext, "output", exception) - - def auditRecord = auditService.createAuditRecord(runScriptResponse) - - then: - assertNodeExists(auditRecord.path) - - and: - auditRecord.script == "script content" - auditRecord.output == "output" - auditRecord.exceptionStackTrace == ExceptionUtils.getStackTrace(exception) - } - - def "create multiple audit records"() { - setup: - def request = requestBuilder.build() - def response = responseBuilder.build() - - def scriptContext = new RequestScriptContext(request, response, new ByteArrayOutputStream(), null, "script content") - - def runScriptResponse = DefaultRunScriptResponse.fromResult(scriptContext, "result", "output", "running time") - - def auditRecords = [] - - when: - (1..5).each { - auditRecords.add(auditService.createAuditRecord(runScriptResponse)) - } - - then: - assertAuditRecordsCreated(auditRecords) - } - - def "get audit records for valid date range"() { - setup: - def request = requestBuilder.build() - def response = responseBuilder.build() - - def scriptContext = new RequestScriptContext(request, response, new ByteArrayOutputStream(), null, "script content") - - def runScriptResponse = DefaultRunScriptResponse.fromResult(scriptContext, "result", "output", "running time") - - auditService.createAuditRecord(runScriptResponse) - - def startDate = getDate(startDateOffset) - def endDate = getDate(endDateOffset) - - expect: - auditService.getAuditRecords(resourceResolver.userID, startDate, endDate).size() == size - - where: - startDateOffset | endDateOffset | size - -2 | -1 | 0 - -1 | 0 | 1 - 0 | 0 | 1 - 0 | 1 | 1 - -1 | 1 | 1 - 1 | 2 | 0 - } - - private Calendar getDate(Integer offset) { - def date = (new Date() + offset).toCalendar() - - date.set(Calendar.HOUR_OF_DAY, 0) - date.set(Calendar.MINUTE, 0) - date.set(Calendar.SECOND, 0) - date.set(Calendar.MILLISECOND, 0) - - date - } - - private void assertAuditRecordsCreated(List auditRecords) { - auditRecords.each { - assertNodeExists(it.path) - } - } -} diff --git a/bundle/src/test/groovy/org/cid15/aem/groovy/console/impl/DefaultGroovyConsoleServiceSpec.groovy b/bundle/src/test/groovy/org/cid15/aem/groovy/console/impl/DefaultGroovyConsoleServiceSpec.groovy deleted file mode 100755 index 5ac7290f..00000000 --- a/bundle/src/test/groovy/org/cid15/aem/groovy/console/impl/DefaultGroovyConsoleServiceSpec.groovy +++ /dev/null @@ -1,116 +0,0 @@ -package org.cid15.aem.groovy.console.impl - -import com.day.cq.commons.jcr.JcrConstants -import com.day.cq.replication.Replicator -import com.day.cq.search.QueryBuilder -import com.google.common.base.Charsets -import org.cid15.aem.groovy.console.GroovyConsoleService -import org.cid15.aem.groovy.console.api.impl.RequestScriptContext -import org.cid15.aem.groovy.console.api.impl.RequestScriptData -import org.cid15.aem.groovy.console.configuration.ConfigurationService -import com.icfolson.aem.prosper.specs.ProsperSpec -import org.apache.sling.event.jobs.JobManager -import org.apache.sling.jcr.resource.JcrResourceConstants -import org.cid15.aem.groovy.console.audit.AuditService -import org.cid15.aem.groovy.console.constants.GroovyConsoleConstants -import org.cid15.aem.groovy.console.extension.impl.DefaultBindingExtensionProvider -import org.cid15.aem.groovy.console.extension.impl.DefaultExtensionService -import org.cid15.aem.groovy.console.extension.impl.DefaultScriptMetaClassExtensionProvider - -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.PATH_SCRIPTS_FOLDER -import static org.cid15.aem.groovy.console.constants.GroovyConsoleConstants.SCRIPT - -class DefaultGroovyConsoleServiceSpec extends ProsperSpec { - - static final def SCRIPT_NAME = "Script" - - static final def SCRIPT_FILE_NAME = "${SCRIPT_NAME}.groovy" - - static final def PATH_FILE = "$PATH_SCRIPTS_FOLDER/$SCRIPT_FILE_NAME" - - static final def PATH_FILE_CONTENT = "$PATH_FILE/${JcrConstants.JCR_CONTENT}" - - def setupSpec() { - slingContext.registerService(JobManager, Mock(JobManager)) - slingContext.registerService(QueryBuilder, Mock(QueryBuilder)) - slingContext.registerService(ConfigurationService, Mock(ConfigurationService)) - slingContext.registerService(AuditService, Mock(AuditService)) - slingContext.registerService(Replicator, Mock(Replicator)) - slingContext.registerInjectActivateService(new DefaultBindingExtensionProvider()) - slingContext.registerInjectActivateService(new DefaultExtensionService()) - slingContext.registerInjectActivateService(new DefaultScriptMetaClassExtensionProvider()) - slingContext.registerInjectActivateService(new DefaultGroovyConsoleService()) - } - - def "run script"() { - setup: - def consoleService = slingContext.getService(GroovyConsoleService) - - def request = requestBuilder.build() - def response = responseBuilder.build() - - def outputStream = new ByteArrayOutputStream() - - def scriptContext = new RequestScriptContext( - request: request, - response: response, - outputStream: outputStream, - printStream: new PrintStream(outputStream, true, Charsets.UTF_8.name()), - script: scriptAsString - ) - - when: - def map = consoleService.runScript(scriptContext) - - then: - assertScriptResult(map) - } - - def "save script"() { - setup: - nodeBuilder.var { - groovyconsole(JcrResourceConstants.NT_SLING_FOLDER) - } - - def consoleService = slingContext.getService(GroovyConsoleService) - - def request = requestBuilder.build { - parameterMap = this.parameterMap - } - - def scriptData = new RequestScriptData(request) - - when: - consoleService.saveScript(scriptData) - - then: - assertNodeExists(PATH_SCRIPTS_FOLDER, JcrConstants.NT_FOLDER) - assertNodeExists(PATH_FILE, JcrConstants.NT_FILE) - assertNodeExists(PATH_FILE_CONTENT, JcrConstants.NT_RESOURCE, - [(JcrConstants.JCR_MIMETYPE): "application/octet-stream"]) - - and: - assert session.getNode(PATH_FILE_CONTENT).get(JcrConstants.JCR_DATA).stream.text == scriptAsString - } - - void assertScriptResult(map) { - assert !map.result - assert map.output == "BEER" + System.getProperty("line.separator") - assert !map.exceptionStackTrace - assert map.runningTime - } - - private String getScriptAsString() { - def scriptAsString = null - - this.class.getResourceAsStream("/$SCRIPT_FILE_NAME").withStream { stream -> - scriptAsString = stream.text - } - - scriptAsString - } - - private Map getParameterMap() { - [(GroovyConsoleConstants.FILE_NAME): (SCRIPT_NAME), (SCRIPT): scriptAsString] - } -} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 7d787c2d..c049758a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,10 +4,10 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4.0.0 - org.cid15.aem.groovy.console + be.orbinson.aem aem-groovy-console pom - 17.0.0 + 18.0.0 AEM Groovy Console The AEM Groovy Console provides an interface for running Groovy scripts in the AEM container. Scripts can be @@ -24,18 +24,21 @@ ui.content - https://github.com/cid15/aem-groovy-console - - - CID 15 - https://www.cid15.org - + https://github.com/orbinson/aem-groovy-console Mark Daugherty mark.r.daugherty@gmail.com + + Barry d'Hoine + barrydhoine@gmail.com + + + Roy Teeuwen + roy@orbinson.be + @@ -47,24 +50,26 @@ - scm:git:git@github.com:cid15/aem-groovy-console.git - scm:git:git@github.com:cid15/aem-groovy-console.git - https://github.com/cid15/aem-groovy-console + scm:git:git@github.com:orbinson/aem-groovy-console.git + scm:git:git@github.com:orbinson/aem-groovy-console.git + https://github.com/orbinson/aem-groovy-console GitHub - https://github.com/cid15/aem-groovy-console/issues + https://github.com/orbinson/aem-groovy-console/issues - sonatype-nexus-staging - https://oss.sonatype.org/content/repositories/snapshots + ossrh + Central Repository OSSRH - Snapshots + https://s01.oss.sonatype.org/content/repositories/snapshots - sonatype-nexus-staging - https://oss.sonatype.org/service/local/staging/deploy/maven2/ + ossrh + Central Repository OSSRH + https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ @@ -83,60 +88,100 @@ admin admin aem-groovy-console - - - 2020.12.4676.20201216T130744Z-201201 - adobe-public + on-prem true - adobe-public-releases - Adobe Public Releases - https://repo.adobe.com/nexus/content/groups/public + 6.5.10 - - - adobe-public-releases - Adobe Public Repository - https://repo.adobe.com/nexus/content/groups/public - - true - never - - - false - - - - oss-snapshots - https://oss.sonatype.org/content/repositories/snapshots - - false - - - true - - - - - - adobe-public-releases - Adobe Public Repository - https://repo.adobe.com/nexus/content/groups/public - - true - never - - - false - - - + + + + + com.adobe.aem + uber-jar + ${aem.version} + provided + + + + + + + cloud + + 2022.11.9850.20221116T162329Z-220900 + + + + + + io.wcm.maven + io.wcm.maven.aem-cloud-dependencies + ${aem.version}.0000 + pom + import + + + + + + + autoInstallBundle + + false + + + + + + org.apache.sling + sling-maven-plugin + + + install-bundle + + install + + + + + + + + + + + autoInstallBundlePublish + + false + + + + + + org.apache.sling + sling-maven-plugin + + http://${aem.publish.host}:${aem.publish.port}/system/console + + + + install-bundle + + install + + + + + + + @@ -160,8 +205,8 @@
- com.day.jcr.vault - content-package-maven-plugin + io.wcm.maven.plugins + wcmio-content-package-maven-plugin install-package @@ -169,7 +214,7 @@ install - http://${aem.host}:${aem.port}/crx/packmgr/service.jsp + http://${aem.host}:${aem.port}/crx/packmgr/service.jsp @@ -200,8 +245,8 @@ - com.day.jcr.vault - content-package-maven-plugin + io.wcm.maven.plugins + wcmio-content-package-maven-plugin install-package-publish @@ -209,7 +254,9 @@ install - http://${aem.publish.host}:${aem.publish.port}/crx/packmgr/service.jsp + + http://${aem.publish.host}:${aem.publish.port}/crx/packmgr/service.jsp + @@ -248,6 +295,13 @@ org.apache.maven.plugins maven-gpg-plugin 1.6 + + + + --pinentry-mode + loopback + + deploy @@ -304,21 +358,23 @@ false false - **/*Spec* + **/*Test* - - - org.apache.maven.surefire - surefire-junit4 - 2.22.0 - - maven-deploy-plugin 2.8.2 + + org.apache.sling + sling-maven-plugin + 2.4.0 + + http://${aem.host}:${aem.port}/system/console + WebConsole + + org.apache.jackrabbit filevault-package-maven-plugin @@ -349,23 +405,34 @@ - com.day.jcr.vault - content-package-maven-plugin - 1.0.2 + io.wcm.maven.plugins + wcmio-content-package-maven-plugin + 2.1.2 - http://${aem.host}:${aem.port}/crx/packmgr/service.jsp - true ${vault.user} ${vault.password} + + com.adobe.aem + aemanalyser-maven-plugin + 1.5.8 + true +
- + + org.jetbrains + annotations + 23.0.0 + provided + + + org.codehaus.groovy groovy-all @@ -379,20 +446,37 @@ provided - + - com.icfolson.aem.prosper - prosper - 15.1.0 + org.junit + junit-bom + 5.8.2 + pom + import + + + org.mockito + mockito-inline + 4.1.0 test - - - com.adobe.aem - aem-sdk-api - ${aem.sdk.version} - provided + org.mockito + mockito-junit-jupiter + 4.1.0 + test + + + io.wcm + io.wcm.testing.aem-mock.junit5 + 5.1.2 + test + + + org.apache.sling + org.apache.sling.testing.sling-mock-oak + 3.1.4-1.40.0 + test diff --git a/ui.apps.structure/pom.xml b/ui.apps.structure/pom.xml index 9beff4ee..fcfeda07 100644 --- a/ui.apps.structure/pom.xml +++ b/ui.apps.structure/pom.xml @@ -3,9 +3,9 @@ 4.0.0 - org.cid15.aem.groovy.console + be.orbinson.aem aem-groovy-console - 17.0.0 + 18.0.0 aem-groovy-console-ui.apps.structure @@ -35,4 +35,4 @@
- \ No newline at end of file + diff --git a/ui.apps/pom.xml b/ui.apps/pom.xml index bf422994..55ab7006 100644 --- a/ui.apps/pom.xml +++ b/ui.apps/pom.xml @@ -1,11 +1,12 @@ - + 4.0.0 - org.cid15.aem.groovy.console + be.orbinson.aem aem-groovy-console - 17.0.0 + 18.0.0 aem-groovy-console-ui.apps @@ -29,7 +30,7 @@ - org.cid15.aem.groovy.console + be.orbinson.aem aem-groovy-console-ui.apps.structure @@ -41,32 +42,49 @@
- com.day.jcr.vault - content-package-maven-plugin + io.wcm.maven.plugins + wcmio-content-package-maven-plugin true - - true - true -
- org.cid15.aem.groovy.console + be.orbinson.aem aem-groovy-console-bundle ${project.version} - org.cid15.aem.groovy.console + be.orbinson.aem aem-groovy-console-ui.apps.structure ${project.version} zip - - com.adobe.aem - aem-sdk-api - + + + + on-prem + + true + + + + com.adobe.aem + uber-jar + + + + + + cloud + + + com.adobe.aem + aem-sdk-api + + + + diff --git a/ui.apps/src/main/content/jcr_root/apps/groovyconsole/clientlibs/js/audit.js b/ui.apps/src/main/content/jcr_root/apps/groovyconsole/clientlibs/js/audit.js index 3a4ed1e4..47409a8f 100644 --- a/ui.apps/src/main/content/jcr_root/apps/groovyconsole/clientlibs/js/audit.js +++ b/ui.apps/src/main/content/jcr_root/apps/groovyconsole/clientlibs/js/audit.js @@ -9,6 +9,7 @@ GroovyConsole.Audit = function () { return { initialize: function () { table = $('.audit').DataTable({ + retrieve: true, ajax: AUDIT_URL, columns: [ { @@ -197,4 +198,4 @@ GroovyConsole.Audit = function () { $(function () { GroovyConsole.Audit.initialize(); GroovyConsole.Audit.initializeDatePicker(); -}); \ No newline at end of file +}); diff --git a/ui.apps/src/main/content/jcr_root/apps/groovyconsole/clientlibs/js/console.js b/ui.apps/src/main/content/jcr_root/apps/groovyconsole/clientlibs/js/console.js index 924229ee..8f4fa141 100644 --- a/ui.apps/src/main/content/jcr_root/apps/groovyconsole/clientlibs/js/console.js +++ b/ui.apps/src/main/content/jcr_root/apps/groovyconsole/clientlibs/js/console.js @@ -1,559 +1,600 @@ var GroovyConsole = function () { - var resultDataTable; + var resultDataTable; - return { - initializeEditors: function () { - // script editor - window.scriptEditor = ace.edit('script-editor'); + return { + initializeEditors: function () { + // script editor + window.scriptEditor = ace.edit('script-editor'); - scriptEditor.getSession().setMode('ace/mode/groovy'); - scriptEditor.setShowPrintMargin(false); - scriptEditor.on('change', function () { - GroovyConsole.localStorage.saveScriptEditorContent(scriptEditor.getSession().getDocument().getValue()); - }); - scriptEditor.setOptions({ + scriptEditor.getSession().setMode('ace/mode/groovy'); + scriptEditor.setShowPrintMargin(false); + scriptEditor.on('change', function () { + GroovyConsole.localStorage.saveScriptEditorContent(scriptEditor.getSession().getDocument().getValue()); + }); + scriptEditor.setOptions({ - enableBasicAutocompletion: true - }); + enableBasicAutocompletion: true + }); - var $scriptEditor = $('#script-editor'); + var $scriptEditor = $('#script-editor'); - $scriptEditor.resizable({ - resize: function () { - scriptEditor.resize(true); + $scriptEditor.resizable({ + resize: function () { + scriptEditor.resize(true); - GroovyConsole.localStorage.saveScriptEditorHeight($scriptEditor.height()); - }, - handles: 's' - }); + GroovyConsole.localStorage.saveScriptEditorHeight($scriptEditor.height()); + }, + handles: 's' + }); - $scriptEditor.css('height', GroovyConsole.localStorage.getScriptEditorHeight()); + $scriptEditor.css('height', GroovyConsole.localStorage.getScriptEditorHeight()); - // data/JSON editor - window.dataEditor = ace.edit('data-editor'); + // data/JSON editor + window.dataEditor = ace.edit('data-editor'); - dataEditor.getSession().setOption('useWorker', false); - dataEditor.getSession().setMode('ace/mode/json'); - dataEditor.setShowPrintMargin(false); - dataEditor.on('change', function () { - GroovyConsole.localStorage.saveDataEditorContent(dataEditor.getSession().getDocument().getValue()); - }); + dataEditor.getSession().setOption('useWorker', false); + dataEditor.getSession().setMode('ace/mode/json'); + dataEditor.setShowPrintMargin(false); + dataEditor.on('change', function () { + GroovyConsole.localStorage.saveDataEditorContent(dataEditor.getSession().getDocument().getValue()); + }); - var $dataEditor = $('#data-editor'); + var $dataEditor = $('#data-editor'); - $dataEditor.resizable({ - resize: function () { - dataEditor.resize(true); + $dataEditor.resizable({ + resize: function () { + dataEditor.resize(true); - GroovyConsole.localStorage.saveDataEditorHeight($dataEditor.height()); - }, - handles: 's' - }); + GroovyConsole.localStorage.saveDataEditorHeight($dataEditor.height()); + }, + handles: 's' + }); - $dataEditor.css('height', GroovyConsole.localStorage.getDataEditorHeight()); + $dataEditor.css('height', GroovyConsole.localStorage.getDataEditorHeight()); - // load editor content - var auditRecord = window.auditRecord; + // load editor content + var auditRecord = window.auditRecord; - if (auditRecord) { - scriptEditor.getSession().setValue(auditRecord.script); - dataEditor.getSession().setValue(auditRecord.data); + if (auditRecord) { + scriptEditor.getSession().setValue(auditRecord.script); + dataEditor.getSession().setValue(auditRecord.data); - GroovyConsole.showResult(auditRecord); - } else { - scriptEditor.getSession().setValue(GroovyConsole.localStorage.getScriptEditorContent()); - dataEditor.getSession().setValue(GroovyConsole.localStorage.getDataEditorContent()); - } + GroovyConsole.showResult(auditRecord); + } else { + scriptEditor.getSession().setValue(GroovyConsole.localStorage.getScriptEditorContent()); + dataEditor.getSession().setValue(GroovyConsole.localStorage.getDataEditorContent()); + } - if (dataEditor.getSession().getDocument().getValue().length) { - GroovyConsole.showData(); - } - }, + if (dataEditor.getSession().getDocument().getValue().length) { + GroovyConsole.showData(); + } + }, - initializeThemeMenu: function () { - var theme = GroovyConsole.localStorage.getTheme(); + initializeThemeMenu: function () { + var theme = GroovyConsole.localStorage.getTheme(); - scriptEditor.setTheme(theme); - dataEditor.setTheme(theme); + scriptEditor.setTheme(theme); + dataEditor.setTheme(theme); - var themes = $('#dropdown-themes li'); + var themes = $('#dropdown-themes li'); - var selectedElement = $.grep(themes, function (element) { - return $(element).find('a').data('target') === theme; - }); + var selectedElement = $.grep(themes, function (element) { + return $(element).find('a').data('target') === theme; + }); - if (selectedElement.length) { - $(selectedElement).addClass('active'); - } + if (selectedElement.length) { + $(selectedElement).addClass('active'); + } - themes.click(function () { - var theme = $(this).find('a').data('target'); + themes.click(function () { + var theme = $(this).find('a').data('target'); - scriptEditor.setTheme(theme); - dataEditor.setTheme(theme); + scriptEditor.setTheme(theme); + dataEditor.setTheme(theme); - themes.removeClass('active'); - $(this).addClass('active'); + themes.removeClass('active'); + $(this).addClass('active'); - GroovyConsole.localStorage.saveTheme(theme); - }); - }, + GroovyConsole.localStorage.saveTheme(theme); + }); + }, - initializeButtons: function () { - $('#new-script').click(function () { - if ($(this).hasClass('disabled')) { - return; - } - - GroovyConsole.localStorage.clearScriptName(); - GroovyConsole.reset(); - GroovyConsole.clearScheduler(); - - scriptEditor.getSession().setValue(''); - dataEditor.getSession().setValue(''); - - GroovyConsole.hideData(); - GroovyConsole.hideScheduler(); - }); - - $('#open-script').click(function () { - if ($(this).hasClass('disabled')) { - return; - } - - GroovyConsole.disableButtons(); - GroovyConsole.showOpenDialog(); - }); - - $('#save-script').click(function () { - if ($(this).hasClass('disabled')) { - return; - } - - var script = scriptEditor.getSession().getValue(); - - if (script.length) { - GroovyConsole.disableButtons(); - GroovyConsole.showSaveDialog(); - } else { - GroovyConsole.showError('Script is empty.'); - } - }); - - $('#schedule-job').click(function () { - if ($('#schedule-job').hasClass('disabled')) { - return; - } - - GroovyConsole.reset(); - - var jobTitle = $('input[name="jobTitle"]').val(); - var cronExpression = $('input[name="cronExpression"]').val(); - - if (jobTitle.length === 0) { - GroovyConsole.showError('Job Title is required.'); - return; - } - - if (!$('input[name="immediate"]').prop('checked') && cronExpression.length === 0) { - GroovyConsole.showError('Cron Expression is required if job is not immediate.'); - return; - } - - var script = scriptEditor.getSession().getValue(); - - if (script.length) { - scriptEditor.setReadOnly(true); - dataEditor.setReadOnly(true); - - GroovyConsole.showLoader(); - GroovyConsole.disableButtons(); - - $('#schedule-job-text').text('Scheduling...'); - - $.post(CQ.shared.HTTP.getContextPath() + '/bin/groovyconsole/jobs.json', { - script: script, - data: dataEditor.getSession().getValue(), - jobTitle: jobTitle, - jobDescription: $('input[name="jobDescription"]').val(), - cronExpression: cronExpression, - mediaType: $('select[name="mediaType"]').val(), - emailTo: $('input[name="emailTo"]').val(), - scheduledJobId: $('input[name="scheduledJobId"]').val() - }).done(function () { - GroovyConsole.showSuccess('Job scheduled successfully.'); - GroovyConsole.clearScheduler(); - GroovyConsole.hideScheduler(); - - $('#scheduled-jobs').collapse('show'); - }).fail(function (jqXHR) { - if (jqXHR.status === 400) { - GroovyConsole.showError('Invalid Cron expression.'); - } else if (jqXHR.status === 403) { - GroovyConsole.showError('You do not have permission to schedule jobs in the Groovy Console.'); - } else { - GroovyConsole.showError('Job scheduling failed. Check error.log file.'); - } - }).always(function () { - scriptEditor.setReadOnly(false); - dataEditor.setReadOnly(false); - - GroovyConsole.hideLoader(); - GroovyConsole.enableButtons(); - GroovyConsole.ScheduledJobs.refreshScheduledJobs(); - - $('#schedule-job-text').text('Schedule Job'); - }); - } else { - GroovyConsole.showError('Script is empty.'); - } - }); - - $('#run-script').click(function () { - if ($('#run-script').hasClass('disabled')) { - return; - } - - GroovyConsole.reset(); - GroovyConsole.clearScheduler(); - - var script = scriptEditor.getSession().getValue(); - - if (script.length) { - scriptEditor.setReadOnly(true); - dataEditor.setReadOnly(true); - - GroovyConsole.showLoader(); - GroovyConsole.disableButtons(); - - $('#run-script-text').text('Running...'); - - $.post(CQ.shared.HTTP.getContextPath() + '/bin/groovyconsole/post.json', { - script: script, - data: dataEditor.getSession().getValue() - }).done(function (response) { - GroovyConsole.showResult(response); - }).fail(function (jqXHR) { - if (jqXHR.status === 403) { - GroovyConsole.showError('You do not have permission to run scripts in the Groovy Console.'); - } else { - GroovyConsole.showError('Script execution failed. Check error.log file.'); - } - }).always(function () { - scriptEditor.setReadOnly(false); - dataEditor.setReadOnly(false); - - GroovyConsole.hideLoader(); - GroovyConsole.enableButtons(); - GroovyConsole.Audit.refreshAuditRecords(); - - $('#run-script-text').text('Run Script'); - }); - } else { - GroovyConsole.showError('Script is empty.'); - } - }); - - $('body').keydown(function (e) { - if (e.ctrlKey) { - if (e.keyCode === 13) { - $('#run-script').click(); - } else if (e.keyCode === 78) { - $('#new-script').click(); - } - } - }); - - $('.copy-link').click(function (e) { - e.preventDefault(); - - var $copyLink = $(this); - var $temp = $('