diff --git a/.git-hooks-matomo/pre-push b/.git-hooks-matomo/pre-push new file mode 100755 index 0000000..61d26af --- /dev/null +++ b/.git-hooks-matomo/pre-push @@ -0,0 +1,107 @@ +#!/bin/bash + +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# + + + +### Check we're running in the context of a plugin and get helpful dir variables ### + +REPO_DIR="$(git rev-parse --show-toplevel)" +echo "Running pre-commit hook in repo: $REPO_DIR" + +if [[ "$REPO_DIR" =~ /plugins/(.*) ]]; then + PLUGIN_PATH="plugins/${BASH_REMATCH[1]}/" +else + echo "Not a plugin, not running any further checks" + exit 1 +fi +MATOMO_DIR=$(echo "$REPO_DIR" | sed -E 's|/plugins/.*$||') + + + +### Figure out how to run PHPStan - ddev or not. ### + +COMMAND="" +# Use local PHP if setup +if command -v php >/dev/null 2>&1; then + if [ -f "${MATOMO_DIR}/vendor/bin/phpstan" ]; then + COMMAND="${MATOMO_DIR}/vendor/bin/phpstan" + PLUGIN_PATH='' + fi +fi +# Use ddev if setup (overridding local setup) +if command -v ddev >/dev/null 2>&1; then + if [ -d "$MATOMO_DIR/.ddev" ]; then + cd "$MATOMO_DIR" || exit 1 + if ddev status 2>&1 > /dev/null; then + COMMAND="ddev exec phpstan" + fi + fi +fi +# If no command, exit +if [[ -z "$COMMAND" ]]; then + echo "No way to run phpstan found." + exit 1 +fi + + + +# Basic setup +cd "$REPO_DIR" +STATUS=0 + + + + +### Run PHPStan on newly created files. ### + +PHPSTAN_CREATED_CONFIG=phpstan/phpstan.created.neon +MAIN_BRANCH='5.x-dev' +if [[ -f "$PHPSTAN_CREATED_CONFIG" ]]; then + CHANGED_FILES=$(git diff --name-only ${MAIN_BRANCH} --diff-filter=A | grep '\.php$' || true) + if [ -z "$CHANGED_FILES" ]; then + echo "No created PHP files" + else + echo "Running PHPstan at a very high level on new files" + CHANGED_FILES=`echo "$CHANGED_FILES" | sed -e 's/^\(.*\)$/"\1"/' | xargs -I{} echo "${PLUGIN_PATH}{}"` + echo "$CHANGED_FILES" | xargs $COMMAND analyse -c ${PLUGIN_PATH}${PHPSTAN_CREATED_CONFIG} || STATUS=1 + fi +fi + + + +### Run PHPStan on modified files. ### +PHPSTAN_MODIFIED_CONFIG=phpstan/phpstan.modified.neon +if [[ -f "$PHPSTAN_MODIFIED_CONFIG" ]]; then + CHANGED_FILES=$(git diff --name-only ${MAIN_BRANCH} --diff-filter=CM | grep '\.php$' || true) + if [ -z "$CHANGED_FILES" ]; then + echo "No changed PHP files" + else + echo "Running PHPstan on modified files" + CHANGED_FILES=`echo "$CHANGED_FILES" | sed -e 's/^\(.*\)$/"\1"/' | xargs -I{} echo "${PLUGIN_PATH}{}"` + echo "$CHANGED_FILES" | xargs $COMMAND analyse -c ${PLUGIN_PATH}${PHPSTAN_MODIFIED_CONFIG} || STATUS=1 + fi +fi + +# Don't bother running the full check, as we check changes files already, and +# can assume that the unchanged files don't need rechecking. +# +# Github will check this anyway. +# +# PHPSTAN_BASE_CONFIG=phpstan.neon +# if [[ -f "$PHPSTAN_BASE_CONFIG" ]]; then +# echo "Running PHPstan at a base level on all plugin files" +# $COMMAND analyse -c ${PLUGIN_PATH}/${PHPSTAN_BASE_CONFIG} || STATUS=1 +# fi + +exit $STATUS diff --git a/.github/workflows/matomo-tests.yml b/.github/workflows/matomo-tests.yml new file mode 100644 index 0000000..ca69b70 --- /dev/null +++ b/.github/workflows/matomo-tests.yml @@ -0,0 +1,76 @@ +# Action for running tests +# This file has been automatically created. +# To recreate it you can run this command +# ./console generate:test-action --plugin="Slack" --php-versions="7.2,8.4" --schedule-cron="0 5 * * 6" + +name: Plugin Slack Tests + +on: + pull_request: + types: [opened, synchronize] + push: + branches: + - '**.x-dev' + workflow_dispatch: + schedule: + - cron: "0 5 * * 6" + +permissions: + actions: read + checks: none + contents: read + deployments: none + issues: read + packages: none + pull-requests: read + repository-projects: none + security-events: none + statuses: none + +concurrency: + group: php-${{ github.ref }} + cancel-in-progress: true + +jobs: + PluginTests: + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + php: [ '7.2', '8.4' ] + target: ['minimum_required_matomo', 'maximum_supported_matomo'] + steps: + - uses: actions/checkout@v3 + with: + lfs: true + persist-credentials: false + - name: Install package ripgrep + run: sudo apt-get install ripgrep + - name: Run tests + uses: matomo-org/github-action-tests@main + with: + plugin-name: 'Slack' + php-version: ${{ matrix.php }} + test-type: 'PluginTests' + matomo-test-branch: ${{ matrix.target }} + redis-service: true + artifacts-pass: ${{ secrets.ARTIFACTS_PASS }} + upload-artifacts: ${{ matrix.php == '7.2' && matrix.target == 'maximum_supported_matomo' }} + UI: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v3 + with: + lfs: true + persist-credentials: false + - name: running tests + uses: matomo-org/github-action-tests@main + with: + plugin-name: 'Slack' + matomo-test-branch: 'maximum_supported_matomo' + test-type: 'UI' + php-version: '7.2' + node-version: '16' + redis-service: true + artifacts-pass: ${{ secrets.ARTIFACTS_PASS }} + upload-artifacts: true diff --git a/.github/workflows/phpcs.yml b/.github/workflows/phpcs.yml new file mode 100644 index 0000000..9df218c --- /dev/null +++ b/.github/workflows/phpcs.yml @@ -0,0 +1,43 @@ +name: PHPCS check + +on: pull_request + +permissions: + actions: read + checks: read + contents: read + deployments: none + issues: read + packages: none + pull-requests: read + repository-projects: none + security-events: none + statuses: read + +jobs: + phpcs: + name: PHPCS + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + with: + lfs: false + persist-credentials: false + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + tools: cs2pr + - name: Install dependencies + run: + composer init --name=matomo/slack --quiet; + composer --no-plugins config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true -n; + composer config repositories.matomo-coding-standards vcs https://github.com/matomo-org/matomo-coding-standards -n; + composer require matomo-org/matomo-coding-standards:dev-master; + composer install --dev --prefer-dist --no-progress --no-suggest + - name: Check PHP code styles + id: phpcs + run: ./vendor/bin/phpcs --report-full --standard=phpcs.xml --report-checkstyle=./phpcs-report.xml + - name: Show PHPCS results in PR + if: ${{ always() && steps.phpcs.outcome == 'failure' }} + run: cs2pr ./phpcs-report.xml --prepend-filename diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml new file mode 100644 index 0000000..acb9bf9 --- /dev/null +++ b/.github/workflows/phpstan.yml @@ -0,0 +1,83 @@ +name: PHPStan check + +on: pull_request + +permissions: + actions: read + checks: read + contents: read + deployments: none + issues: read + packages: none + pull-requests: read + repository-projects: none + security-events: none + statuses: read + +env: + PLUGIN_NAME: Slack + +jobs: + phpstan: + name: PHPStan + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + lfs: false + persist-credentials: false + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.2' + + - name: Check out github-action-tests repository + uses: actions/checkout@v4 + with: + repository: matomo-org/github-action-tests + ref: main + path: github-action-tests + + - name: checkout matomo for plugin builds + shell: bash + run: ${{ github.workspace }}/github-action-tests/scripts/bash/checkout_matomo.sh + env: + PLUGIN_NAME: ${{ env.PLUGIN_NAME }} + WORKSPACE: ${{ github.workspace }} + ACTION_PATH: ${{ github.workspace }}/github-action-tests + MATOMO_TEST_TARGET: maximum_supported_matomo + + - name: prepare setup + shell: bash + run: | + cd ${{ github.workspace }}/matomo + echo -e "composer install" + composer install --ignore-platform-reqs + + - name: checkout additional plugins + if: ${{ env.DEPENDENT_PLUGINS != '' }} + shell: bash + working-directory: ${{ github.workspace }}/matomo + run: ${{ github.workspace }}/github-action-tests/scripts/bash/checkout_dependent_plugins.sh + + env: + GITHUB_USER_TOKEN: ${{ secrets.TESTS_ACCESS_TOKEN || secrets.GITHUB_TOKEN }} + + - name: "Restore result cache" + uses: actions/cache/restore@v4 + with: + path: /tmp/phpstan # same as in phpstan.neon + key: "phpstan-result-cache-${{ github.run_id }}" + restore-keys: | + phpstan-result-cache- + + - name: PHPStan whole repo + id: phpstan-all + run: cd ${{ github.workspace }}/matomo && composer run phpstan -- -vvv -c plugins/${{ env.PLUGIN_NAME }}/phpstan.neon + + - name: "Save result cache" + uses: actions/cache/save@v4 + if: ${{ !cancelled() }} + with: + path: /tmp/phpstan # same as in phpstan.neon + key: "phpstan-result-cache-${{ github.run_id }}" \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1d2be6c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/tests/System/processed/ +/tests/Integration/Importers/processed/ +/tests/UI/processed-ui-screenshots/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..dc8bc79 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,4 @@ +## Changelog + +5.0.0 - 2025-09-15 +- Initial release to send scheduled reports to a Slack channel diff --git a/ScheduleReportSlack.php b/ScheduleReportSlack.php new file mode 100644 index 0000000..d0a5aff --- /dev/null +++ b/ScheduleReportSlack.php @@ -0,0 +1,60 @@ +subject = $subject; + $this->fileName = $fileName; + $this->fileContents = $fileContents; + $this->channel = $channel; + $this->token = $token; + } + + public function send(): bool + { + $slackApi = new SlackApi($this->token); + return $slackApi->uploadFile($this->subject, $this->fileName, $this->fileContents, $this->channel); + } +} diff --git a/Slack.php b/Slack.php new file mode 100644 index 0000000..0f9ed54 --- /dev/null +++ b/Slack.php @@ -0,0 +1,291 @@ + true, + ScheduledReports::EVOLUTION_GRAPH_PARAMETER => false, + ScheduledReports::DISPLAY_FORMAT_PARAMETER => true, + ); + + private static $managedReportTypes = array( + self::SLACK_TYPE => 'plugins/Slack/images/slack.png' + ); + + private static $managedReportFormats = array( + ReportRenderer::PDF_FORMAT => 'plugins/Morpheus/icons/dist/plugins/pdf.png', + ReportRenderer::CSV_FORMAT => 'plugins/Morpheus/images/export.png', + ReportRenderer::TSV_FORMAT => 'plugins/Morpheus/images/export.png', + ); + + public function registerEvents() + { + return [ + 'ScheduledReports.getReportParameters' => 'getReportParameters', + 'ScheduledReports.validateReportParameters' => 'validateReportParameters', + 'ScheduledReports.getReportMetadata' => 'getReportMetadata', + 'ScheduledReports.getReportTypes' => 'getReportTypes', + 'ScheduledReports.getReportFormats' => 'getReportFormats', + 'ScheduledReports.getRendererInstance' => 'getRendererInstance', + 'ScheduledReports.getReportRecipients' => 'getReportRecipients', + 'ScheduledReports.processReports' => 'processReports', + 'ScheduledReports.allowMultipleReports' => 'allowMultipleReports', + 'ScheduledReports.sendReport' => 'sendReport', + 'Template.reportParametersScheduledReports' => 'templateReportParametersScheduledReports', + 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys', + ]; + } + + public function requiresInternetConnection() + { + return true; + } + + public function getClientSideTranslationKeys(&$translationKeys) + { + $translationKeys[] = 'Slack_ChannelId'; + $translationKeys[] = 'Slack_NoOauthTokenAdded'; + $translationKeys[] = 'Slack_SlackChannel'; + $translationKeys[] = 'Slack_SlackEnterYourSlackChannelIdHelpText'; + } + + public function validateReportParameters(&$parameters, $reportType) + { + if (!self::isSlackEvent($reportType)) { + return; + } + + $reportFormat = $parameters[ScheduledReports::DISPLAY_FORMAT_PARAMETER]; + $availableDisplayFormats = array_keys(ScheduledReports::getDisplayFormats()); + if (!in_array($reportFormat, $availableDisplayFormats)) { + throw new \Exception( + Piwik::translate( + 'General_ExceptionInvalidAggregateReportsFormat', + array($reportFormat, implode(', ', $availableDisplayFormats)) + ) + ); + } + + // evolutionGraph is an optional parameter + if (!isset($parameters[ScheduledReports::EVOLUTION_GRAPH_PARAMETER])) { + $parameters[ScheduledReports::EVOLUTION_GRAPH_PARAMETER] = ScheduledReports::EVOLUTION_GRAPH_PARAMETER_DEFAULT_VALUE; + } else { + $parameters[ScheduledReports::EVOLUTION_GRAPH_PARAMETER] = self::valueIsTrue($parameters[ScheduledReports::EVOLUTION_GRAPH_PARAMETER]); + } + + $settings = StaticContainer::get(SystemSettings::class); + if (empty($settings->slackOauthToken->getValue())) { + throw new \Exception(Piwik::translate('Slack_OauthTokenRequiredErrorMessage')); + } elseif (empty($parameters[self::SLACK_CHANNEL_ID_PARAMETER])) { + throw new \Exception(Piwik::translate('Slack_SlackChannelIdRequiredErrorMessage')); + } + } + + public function getReportMetadata(&$availableReportMetadata, $reportType, $idSite) + { + if (! self::isSlackEvent($reportType)) { + return; + } + + // Use same metadata as E-mail report from ScheduledReports plugin + Piwik::postEvent( + 'ScheduledReports.getReportMetadata', + [&$availableReportMetadata, ScheduledReports::EMAIL_TYPE, $idSite] + ); + } + + public function getReportTypes(&$reportTypes) + { + $reportTypes = array_merge($reportTypes, self::$managedReportTypes); + } + + public function getReportFormats(&$reportFormats, $reportType) + { + if (self::isSlackEvent($reportType)) { + $reportFormats = array_merge($reportFormats, self::$managedReportFormats); + } + } + + public function getReportParameters(&$availableParameters, $reportType) + { + if (self::isSlackEvent($reportType)) { + $availableParameters = self::$availableParameters; + } + } + + public function processReports(&$processedReports, $reportType, $outputType, $report) + { + if (! self::isSlackEvent($reportType)) { + return; + } + + // Use same metadata as E-mail report from ScheduledReports plugin + Piwik::postEvent( + 'ScheduledReports.processReports', + [&$processedReports, ScheduledReports::EMAIL_TYPE, $outputType, $report] + ); + } + + public function getRendererInstance(&$reportRenderer, $reportType, $outputType, $report) + { + if (! self::isSlackEvent($reportType)) { + return; + } + + $reportFormat = $report['format']; + + $reportRenderer = ReportRenderer::factory($reportFormat); + } + + public function allowMultipleReports(&$allowMultipleReports, $reportType) + { + if (self::isSlackEvent($reportType)) { + $allowMultipleReports = true; + } + } + + public function getReportRecipients(&$recipients, $reportType, $report) + { + if (!self::isSlackEvent($reportType) || empty($report['parameters'][self::SLACK_CHANNEL_ID_PARAMETER])) { + return; + } + + $recipients = [Piwik::translate('Slack_SlackChannel') . ': ' . $report['parameters'][self::SLACK_CHANNEL_ID_PARAMETER]]; + } + + /** + * @param $reportType + * @param $report + * @param $contents + * @param $filename + * @param $prettyDate + * @param $reportSubject + * @param $reportTitle + * @param $additionalFiles + * @param Period|null $period + * @param $force + */ + public function sendReport( + $reportType, + $report, + $contents, + $filename, + $prettyDate, + $reportSubject, + $reportTitle, + $additionalFiles, + $period, + $force + ) { + if (! self::isSlackEvent($reportType)) { + return; + } + $logger = StaticContainer::get(LoggerInterface::class); + // Safeguard against sending the same report twice to the same Slack channel (unless $force is true) + if (!$force && $this->reportAlreadySent($report, $period)) { + $logger->warning( + 'Preventing the same scheduled report from being sent again (report #%s for period "%s")', + $report['idreport'], + $prettyDate + ); + return; + } + + $settings = StaticContainer::get(SystemSettings::class); + $token = $settings->slackOauthToken->getValue(); + if (empty($token)) { + $logger->error('Slack OAuth token not set'); + return; + } + + $periods = ScheduledReports::getPeriodToFrequency(); + $subject = Piwik::translate('Slack_PleaseFindYourReport', [$periods[$report['period']], $reportSubject]); + $channelId = $report['parameters'][self::SLACK_CHANNEL_ID_PARAMETER]; + $scheduleReportSlack = new ScheduleReportSlack($subject, $filename, $contents, $channelId, $token); + $scheduleReportSlack->send(); + } + + public function templateReportParametersScheduledReports(&$out, $context = '') + { + if (Piwik::isUserIsAnonymous()) { + return; + } + + $view = new View('@Slack/reportParametersScheduledReports'); + $view->reportType = self::SLACK_TYPE; + $view->context = $context; + + $settings = StaticContainer::get(SystemSettings::class); + $view->isSlackOauthTokenAdded = !empty($settings->slackOauthToken->getValue()); + $view->defaultDisplayFormat = ScheduledReports::DEFAULT_DISPLAY_FORMAT; + $view->defaultFormat = ReportRenderer::PDF_FORMAT; + $view->defaultEvolutionGraph = ScheduledReports::EVOLUTION_GRAPH_PARAMETER_DEFAULT_VALUE; + $out .= $view->render(); + } + + private static function isSlackEvent($reportType): bool + { + return in_array($reportType, array_keys(self::$managedReportTypes)); + } + + public function install() + { + } + + public function deactivate() + { + // delete all slack reports + $APIScheduledReports = APIScheduledReports::getInstance(); + $reports = $APIScheduledReports->getReports(); + + foreach ($reports as $report) { + if ($report['type'] == self::SLACK_TYPE) { + $APIScheduledReports->deleteReport($report['idreport']); + } + } + } + + public function uninstall() + { + return; + } + + private function reportAlreadySent($report, Period $period) + { + $key = ScheduledReports::OPTION_KEY_LAST_SENT_DATERANGE . $report['idreport']; + + $previousDate = Option::get($key); + + return $previousDate === $period->getRangeString(); + } + + private static function valueIsTrue($value) + { + return $value == 'true' || $value == 1 || $value == '1' || $value === true; + } +} diff --git a/SlackApi.php b/SlackApi.php new file mode 100644 index 0000000..d47d8f4 --- /dev/null +++ b/SlackApi.php @@ -0,0 +1,162 @@ +token = $token; + $this->logger = StaticContainer::get(LoggerInterface::class); + } + + /** + * Slack file upload is done in 3 parts - https://api.slack.com/messaging/files + * + * 1. Call files.getUploadURLExternal. The response will contain a URL that you can POST the contents of your file to + * 2. POST the contents of your file to the URL returned in step 1 + * 3. Call files.completeUploadExternal along with ChannelId to post the file to a Channel. + */ + public function uploadFile(string $subject, string $fileName, string $fileContents, string $channel): bool + { + $uploadURL = $this->getUploadURLExternal($fileName, strlen($fileContents)); + if (!empty($uploadURL) && $this->sendFile($uploadURL, $fileContents)) { + return $this->completeUploadExternal($channel, $subject); + } + + $this->logger->debug('Unable to send ' . $fileName . ' report to Slack'); + + return false; + } + + public function getUploadURLExternal(string $fileName, int $fileLength): string + { + try { + $response = $this->sendHttpRequest( + self::SLACK_UPLOAD_URL_EXTERNAL, + self::SLACK_TIMEOUT, + [ + 'token' => $this->token, + 'filename' => $fileName, + 'length' => $fileLength, + ], + ['Content-Type' => 'multipart/form-data'] + ); + } catch (\Exception $e) { + $this->logger->debug('Slack error getUploadURLExternal: ' . $e->getMessage()); + return ''; + } + + $data = json_decode($response, true); + if (!empty($data) && !empty($data['upload_url']) && !empty($data['file_id'])) { + $this->fileID = $data['file_id']; + + return $data['upload_url']; + } + + return ''; + } + + public function sendFile(string $uploadURL, string $fileContents): bool + { + try { + $response = $this->sendHttpRequest( + $uploadURL, + self::SLACK_TIMEOUT, + [$fileContents], + [], + true + ); + } catch (\Exception $e) { + $this->logger->debug('Slack error sendFile: ' . $e->getMessage()); + return false; + } + + return strtolower($response) === ('ok - ' . strlen($fileContents)); + } + + public function completeUploadExternal(string $channel, string $subject): bool + { + try { + $response = $this->sendHttpRequest( + self::SLACK_COMPLETE_UPLOAD_EXTERNAL, + self::SLACK_TIMEOUT, + [ + 'token' => $this->token, + 'files' => json_encode([['id' => $this->fileID]]), + 'channels' => $channel, + 'initial_comment' => $subject + ], + ['Content-Type' => 'multipart/form-data'] + ); + } catch (\Exception $e) { + $this->logger->debug('Slack error completeUploadExternal:' . $e->getMessage()); + return false; + } + + $data = json_decode($response, true); + + return !empty($data['ok']); + } + + private function sendHttpRequest(string $url, int $timeout, array $requestBody, array $additionalHeaders = [], $requestBodyAsString = false) + { + if ($requestBodyAsString && !empty($requestBody[0])) { + $requestBody = $requestBody[0]; + } + + return Http::sendHttpRequestBy( + Http::getTransportMethod(), + $url, + $timeout, + $userAgent = null, + $destinationPath = null, + $file = null, + $followDepth = 0, + $acceptLanguage = false, + $acceptInvalidSslCertificate = false, + $byteRange = false, + $getExtendedInfo = false, + $httpMethod = 'POST', + $httpUsername = null, + $httpPassword = null, + $requestBody, + $additionalHeaders + ); + } +} diff --git a/SystemSettings.php b/SystemSettings.php new file mode 100644 index 0000000..0371bb9 --- /dev/null +++ b/SystemSettings.php @@ -0,0 +1,38 @@ + allows selection of a single value + $this->slackOauthToken = $this->createSlackOauthTokenSetting(); + } + + private function createSlackOauthTokenSetting() + { + return $this->makeSetting('slackOauthToken', $default = '', FieldConfig::TYPE_STRING, function (FieldConfig $field) { + $field->title = Piwik::translate('Slack_OauthTokenSettingTitle'); + $field->uiControl = FieldConfig::UI_CONTROL_PASSWORD; + $field->description = Piwik::translate('Slack_OauthTokenSettingDescription'); + $field->transform = function ($value) { + return trim($value); + }; + }); + } +} diff --git a/config/config.php b/config/config.php new file mode 100644 index 0000000..d5be5de --- /dev/null +++ b/config/config.php @@ -0,0 +1,3 @@ + + + + Matomo Coding Standard for Slack plugin + + + + . + + tests/javascript/* + */vendor/* + + + + + + + + tests/* + + + + + Updates/* + + + + + tests/* + + + + + tests/* + + \ No newline at end of file diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..fbc5b99 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,21 @@ +parameters: + level: 5 + phpVersion: 70200 + tmpDir: /tmp/phpstan/Slack/main + paths: + - . + excludePaths: + - tests/* + - github-action-tests + bootstrapFiles: + - ../../bootstrap-phpstan.php + universalObjectCratesClasses: + - Piwik\Config + - Piwik\View + - Piwik\ViewDataTable\Config + scanDirectories: + # ../../ does not actually seem to give us anything + # that ../plugins/ does not, but including it for + # completeness. It does not seem to slow down performance. + - . + diff --git a/phpstan/phpstan.created.neon b/phpstan/phpstan.created.neon new file mode 100644 index 0000000..ee4a72a --- /dev/null +++ b/phpstan/phpstan.created.neon @@ -0,0 +1,5 @@ +includes: + - ../phpstan.neon +parameters: + level: 5 + tmpDir: /tmp/phpstan/Slack/created \ No newline at end of file diff --git a/phpstan/phpstan.modified.neon b/phpstan/phpstan.modified.neon new file mode 100644 index 0000000..981c06f --- /dev/null +++ b/phpstan/phpstan.modified.neon @@ -0,0 +1,5 @@ +includes: + - ../phpstan.neon +parameters: + level: 5 + tmpDir: /tmp/phpstan/Slack/modified \ No newline at end of file diff --git a/plugin.json b/plugin.json new file mode 100644 index 0000000..e6c6c77 --- /dev/null +++ b/plugin.json @@ -0,0 +1,32 @@ +{ + "name": "Slack", + "description": "Send Matomo reports and alerts to Slack channels, keeping your team informed and ready to act in real time.", + "version": "5.0.0", + "theme": false, + "require": { + "matomo": ">=5.4.0-b4,<6.0.0-b1" + }, + "authors": [ + { + "name": "Matomo", + "email": "", + "homepage": "" + } + ], + "support": { + "email": "", + "issues": "", + "forum": "", + "irc": "", + "wiki": "", + "source": "", + "docs": "", + "rss": "" + }, + "homepage": "", + "license": "GPL v3+", + "keywords": [ + "Slack", + "ScheduledReports" + ] +} \ No newline at end of file diff --git a/pull_request_template.md b/pull_request_template.md new file mode 100644 index 0000000..e7d9cf5 --- /dev/null +++ b/pull_request_template.md @@ -0,0 +1,26 @@ +## Description + + +## Issue No + + +## Steps to Replicate the Issue +1. +2. +3. + + + +## Checklist +- [✔/✖] Tested locally or on demo2/demo3? +- [✔/✖/NA] New test case added/updated? +- [✔/✖/NA] Are all newly added texts included via translation? +- [✔/✖/NA] Are text sanitized properly? (Eg use of v-text v/s v-html for vue) +- [✔/✖/NA] Version bumped? \ No newline at end of file diff --git a/screenshots/.gitkeep b/screenshots/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/templates/reportParametersScheduledReports.twig b/templates/reportParametersScheduledReports.twig new file mode 100644 index 0000000..8a32104 --- /dev/null +++ b/templates/reportParametersScheduledReports.twig @@ -0,0 +1,7 @@ +
\ No newline at end of file diff --git a/tests/Integration/SlackApiTest.php b/tests/Integration/SlackApiTest.php new file mode 100644 index 0000000..24c0736 --- /dev/null +++ b/tests/Integration/SlackApiTest.php @@ -0,0 +1,95 @@ +getMockBuilder(SlackApi::class) + ->setMethods([ + 'getUploadURLExternal', + 'sendFile', + 'completeUploadExternal' + ]) + ->setConstructorArgs(array('token')) + ->getMock(); + $helperMock->expects($this->once())->method('getUploadURLExternal')->willReturn(''); + $helperMock->expects($this->never())->method('sendFile'); + $helperMock->expects($this->never())->method('completeUploadExternal'); + + $this->assertFalse($helperMock->uploadFile('test file', 'test.csv', "a,b,c", 'channelID')); + } + + public function testSendShouldReturnFalseWhenSendFileFails() + { + $helperMock = $this->getMockBuilder(SlackApi::class) + ->setMethods([ + 'getUploadURLExternal', + 'sendFile', + 'completeUploadExternal' + ]) + ->setConstructorArgs(array('token')) + ->getMock(); + $helperMock->expects($this->once())->method('getUploadURLExternal')->willReturn('https://SLACL_URL'); + $helperMock->expects($this->once())->method('sendFile')->willReturn(false); + $helperMock->expects($this->never())->method('completeUploadExternal'); + + $this->assertFalse($helperMock->uploadFile('test file', 'test.csv', "a,b,c", 'channelID')); + } + + public function testSendShouldReturnFalseWhenCompleteUploadExternalFails() + { + $helperMock = $this->getMockBuilder(SlackApi::class) + ->setMethods([ + 'getUploadURLExternal', + 'sendFile', + 'completeUploadExternal' + ]) + ->setConstructorArgs(array('token')) + ->getMock(); + $helperMock->expects($this->once())->method('getUploadURLExternal')->willReturn('https://SLACL_URL'); + $helperMock->expects($this->once())->method('sendFile')->willReturn(true); + $helperMock->expects($this->once())->method('completeUploadExternal')->willReturn(false); + + $this->assertFalse($helperMock->uploadFile('test file', 'test.csv', "a,b,c", 'channelID')); + } + + public function testSendSuccess() + { + $helperMock = $this->getMockBuilder(SlackApi::class) + ->setMethods([ + 'getUploadURLExternal', + 'sendFile', + 'completeUploadExternal' + ]) + ->setConstructorArgs(array('token')) + ->getMock(); + $helperMock->expects($this->once())->method('getUploadURLExternal')->willReturn('https://SLACL_URL'); + $helperMock->expects($this->once())->method('sendFile')->willReturn(true); + $helperMock->expects($this->once())->method('completeUploadExternal')->willReturn(true); + + $this->assertTrue($helperMock->uploadFile('test file', 'test.csv', "a,b,c", 'channelID')); + } +} diff --git a/tests/Integration/SlackTest.php b/tests/Integration/SlackTest.php new file mode 100644 index 0000000..de6dd6f --- /dev/null +++ b/tests/Integration/SlackTest.php @@ -0,0 +1,136 @@ +reports = new ScheduledReports(); + $this->setIdentity('userlogin'); + + \Piwik\Plugin\Manager::getInstance()->loadPlugins(array('ScheduledReports', 'Slack')); + \Piwik\Plugin\Manager::getInstance()->installLoadedPlugins(); + + for ($i = 1; $i <= 4; $i++) { + Fixture::createWebsite('2014-01-01 00:00:00'); + } + } + + public function testAddReportShouldFailWhenTokenNotSet() + { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Slack_OauthTokenRequiredErrorMessage'); + + $this->addReport('userlogin', 1); + } + + public function testAddReportSuccess() + { + $settings = StaticContainer::get(SystemSettings::class); + $settings->slackOauthToken->setValue('test123'); + + $this->addReport($userLogin = 'userlogin', $idSite = 1); + $this->assertHasReport($userLogin, $idSite); + } + + public function testAddReportSuccessCsv() + { + $settings = StaticContainer::get(SystemSettings::class); + $settings->slackOauthToken->setValue('test123'); + + $this->addReport($userLogin = 'userlogin', $idSite = 2, 'csv'); + $this->assertHasReport($userLogin, $idSite); + } + + public function testAddReportSuccessTsv() + { + $settings = StaticContainer::get(SystemSettings::class); + $settings->slackOauthToken->setValue('test123'); + + $this->addReport($userLogin = 'userlogin', $idSite = 3, 'tsv'); + $this->assertHasReport($userLogin, $idSite); + } + + public function testAddReportFailureWhenInvalidReportType() + { + $settings = StaticContainer::get(SystemSettings::class); + $settings->slackOauthToken->setValue('test123'); + $this->expectException(\Exception::class); + $this->expectExceptionMessage('General_ExceptionInvalidReportRendererFormat'); + + $this->addReport($userLogin = 'userlogin', $idSite = 3, 'html'); + } + + private function assertHasReport($login, $idSite) + { + $report = $this->getReport($login, $idSite); + + $this->assertNotEmpty($report, "Report for $login, $idSite should exist but does not"); + } + + private function getReport($login, $idSite) + { + $this->setIdentity($login); + + return API::getInstance()->getReports($idSite, 'day', $this->reportIds[$login . '_' . $idSite]); + } + + private function addReport($login, $idSite, $reportFormat = 'pdf') + { + $this->setIdentity($login); + + $reportType = 'slack'; + $reports = array(); + $parameters = array( + Slack::SLACK_CHANNEL_ID_PARAMETER => 'test123', + ScheduledReports::DISPLAY_FORMAT_PARAMETER => ScheduledReports::DEFAULT_DISPLAY_FORMAT, + ScheduledReports::EVOLUTION_GRAPH_PARAMETER => ScheduledReports::EVOLUTION_GRAPH_PARAMETER_DEFAULT_VALUE, + ); + + $reportId = API::getInstance()->addReport($idSite, 'description', 'day', 3, $reportType, $reportFormat, $reports, $parameters); + $this->reportIds[$login . '_' . $idSite] = $reportId; + } + + private function setIdentity($login) + { + FakeAccess::$identity = $login; + FakeAccess::$superUser = true; + } + + public function provideContainerConfig() + { + return array( + 'Piwik\Access' => new FakeAccess() + ); + } +} diff --git a/tests/Integration/SystemSettingsTest.php b/tests/Integration/SystemSettingsTest.php new file mode 100644 index 0000000..8a24598 --- /dev/null +++ b/tests/Integration/SystemSettingsTest.php @@ -0,0 +1,54 @@ +settings = new SystemSettings(); + } + + public function testSlackOauthTokenDefaultValue() + { + $this->assertEmpty($this->settings->slackOauthToken->getValue()); + } + + public function testSlackOauthTokenValueChangeSuccess() + { + $this->settings->slackOauthToken->setValue('token'); + $this->assertEquals('token', $this->settings->slackOauthToken->getValue()); + } + + public function testSlackOauthTokenValueChangeSuccess2() + { + $this->settings->slackOauthToken->setValue('token '); + $this->assertEquals('token', $this->settings->slackOauthToken->getValue()); + } +} diff --git a/tests/UI/SlackSystemSetting_spec.js b/tests/UI/SlackSystemSetting_spec.js new file mode 100644 index 0000000..e4a05d1 --- /dev/null +++ b/tests/UI/SlackSystemSetting_spec.js @@ -0,0 +1,35 @@ +/*! + * Matomo - free/libre analytics platform + * + * Screenshot integration tests. + * + * @link https://matomo.org + * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + + describe("SlackSystemSetting", function () { + this.fixture = "Piwik\\Tests\\Fixtures\\EmptySite"; + + // required to ensure no provider is set initially + this.optionsOverride = { + 'persist-fixture-data': false, + }; + + async function captureScreen(screenshotName, theTest, selector) { + if (!selector) { + selector = reportSelector; + } + await theTest(); + await page.waitForTimeout(100); + await page.waitForNetworkIdle(); + expect(await page.screenshotSelector(selector)).to.matchImage(screenshotName); + } + + it('should load the Settings page for Slack correctly', async function () { + const selector = '.card-content:contains(Slack)'; + await captureScreen('settings_page', async () => { + await page.goto('?module=CoreAdminHome&action=generalSettings&idSite=1&period=day&date=yesterday'); + }, selector); + }); + +}); \ No newline at end of file diff --git a/tests/UI/Slack_spec.js b/tests/UI/Slack_spec.js new file mode 100644 index 0000000..e2896f6 --- /dev/null +++ b/tests/UI/Slack_spec.js @@ -0,0 +1,125 @@ +/*! + * Matomo - free/libre analytics platform + * + * Screenshot integration tests. + * + * @link https://matomo.org + * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + + describe("Slack", function () { + this.fixture = "Piwik\\Tests\\Fixtures\\EmptySite"; + + // required to ensure no provider is set initially + this.optionsOverride = { + 'persist-fixture-data': false, + }; + + async function captureScreen(screenshotName, theTest, selector) { + if (!selector) { + selector = reportSelector; + } + await theTest(); + await page.waitForNetworkIdle(); + await page.waitForSelector(selector); + expect(await page.screenshotSelector(selector)).to.matchImage(screenshotName); + } + + it('should load the schedule report as empty', async function () { + const selector = '.page'; + await captureScreen('empty_report', async () => { + await page.goto('?module=ScheduledReports&action=index&idSite=1&period=day&date=yesterday'); + }, selector); + }); + + it('should show create new report screen', async function () { + const selector = '.page'; + await captureScreen('new_scheduled_reports', async () => { + await page.goto('?module=ScheduledReports&action=index&idSite=1&period=day&date=yesterday'); + await page.evaluate(() => $('#add-report').click()); + }, selector); + }); + + it('should show send report via Slack as an option', async function () { + const selector = '.page'; + await captureScreen('send_via_slack_new', async () => { + await page.evaluate(() => $('#addEditReport .matomo-form-field:eq(6) input')[0].click()); + }, selector); + }); + + it('should show slack channel ID input as disabled as Oauth token not configured', async function () { + const selector = '.page'; + await captureScreen('slack_report_disabled', async () => { + await page.evaluate(() => $('#addEditReport .matomo-form-field:eq(6) ul li:last').click()); + }, selector); + }); + + it('should show report format for slack', async function () { + const selector = '.page'; + await captureScreen('send_via_slack', async () => { + await page.evaluate(() => $('#addEditReport .matomo-form-field.slack:eq(0) input')[0].click()); + }, selector); + }); + + it('should show slack channel ID input as enabled when Oauth token configured', async function () { + const selector = '.page'; + testEnvironment.configOverride.Slack = {slackOauthToken: 'token'}; + testEnvironment.save(); + await page.goto('?module=ScheduledReports&action=index&idSite=1&period=day&date=yesterday'); + await page.waitForNetworkIdle(); + await captureScreen('slack_report_enabled', async () => { + await page.evaluate(() => $('#add-report').click()); + await page.waitForNetworkIdle(); + await page.evaluate(() => $('#addEditReport .matomo-form-field:eq(6) input')[0].click()); + await page.evaluate(() => $('#addEditReport .matomo-form-field:eq(6) ul li:last').click()); + await page.evaluate(() => $('#addEditReport .matomo-form-field.slack:eq(0) input')[0].click()); + await page.evaluate(() => $('#addEditReport .matomo-form-field.slack:eq(0) li:eq(1)').click()); + }, selector); + }); + + it('should show show error if channelID not set', async function () { + const selector = '.page'; + testEnvironment.configOverride.Slack = {slackOauthToken: 'token'}; + testEnvironment.save(); + await captureScreen('slack_report_error', async () => { + await page.type('textarea#report_description', 'Slack Report'); + await page.evaluate(() => $('#slackVisitsSummary_get').click()); + await page.click('.matomo-save-button input.btn'); + await page.waitForNetworkIdle(); + }, selector); + }); + + it('should show save a report successfully', async function () { + const selector = '.page'; + await captureScreen('slack_report_save_report', async () => { + await page.evaluate(() => $('#slackUserCountry_getCountry').click()); + await page.type('input#channelID', 'ChannelID'); + await page.click('.matomo-save-button input.btn'); + await page.waitForNetworkIdle(); + }, selector); + }); + + it('should show display option for reportType:pdf', async function () { + const selector = '.page'; + await captureScreen('slack_report_pdf_view', async () => { + await page.evaluate(() => $('#add-report').click()); + await page.waitForNetworkIdle(); + await page.type('textarea#report_description', 'Slack Report PDF'); + await page.evaluate(() => $('#addEditReport .matomo-form-field:eq(6) input')[0].click()); + await page.evaluate(() => $('#addEditReport .matomo-form-field:eq(6) ul li:last').click()); + }, selector); + }); + + it('should save reportType:pdf with default display options', async function () { + const selector = '.page'; + await captureScreen('slack_report_pdf_save', async () => { + await page.evaluate(() => $('#slackUserCountry_getCountry').click()); + await page.type('input#channelID', 'ChannelID'); + await page.click('.matomo-save-button input.btn'); + await page.waitForNetworkIdle(); + }, selector); + }); + + // TODO: Add tests for display options once core changes are merged + +}); \ No newline at end of file diff --git a/tests/UI/expected-ui-screenshots/SlackSystemSetting_settings_page.png b/tests/UI/expected-ui-screenshots/SlackSystemSetting_settings_page.png new file mode 100644 index 0000000..84a5135 Binary files /dev/null and b/tests/UI/expected-ui-screenshots/SlackSystemSetting_settings_page.png differ diff --git a/tests/UI/expected-ui-screenshots/Slack_empty_report.png b/tests/UI/expected-ui-screenshots/Slack_empty_report.png new file mode 100644 index 0000000..fffe648 Binary files /dev/null and b/tests/UI/expected-ui-screenshots/Slack_empty_report.png differ diff --git a/tests/UI/expected-ui-screenshots/Slack_new_scheduled_reports.png b/tests/UI/expected-ui-screenshots/Slack_new_scheduled_reports.png new file mode 100644 index 0000000..d42d646 Binary files /dev/null and b/tests/UI/expected-ui-screenshots/Slack_new_scheduled_reports.png differ diff --git a/tests/UI/expected-ui-screenshots/Slack_send_via_slack.png b/tests/UI/expected-ui-screenshots/Slack_send_via_slack.png new file mode 100644 index 0000000..ef35dd5 Binary files /dev/null and b/tests/UI/expected-ui-screenshots/Slack_send_via_slack.png differ diff --git a/tests/UI/expected-ui-screenshots/Slack_send_via_slack_new.png b/tests/UI/expected-ui-screenshots/Slack_send_via_slack_new.png new file mode 100644 index 0000000..cee410c Binary files /dev/null and b/tests/UI/expected-ui-screenshots/Slack_send_via_slack_new.png differ diff --git a/tests/UI/expected-ui-screenshots/Slack_slack_report_disabled.png b/tests/UI/expected-ui-screenshots/Slack_slack_report_disabled.png new file mode 100644 index 0000000..5a57d60 Binary files /dev/null and b/tests/UI/expected-ui-screenshots/Slack_slack_report_disabled.png differ diff --git a/tests/UI/expected-ui-screenshots/Slack_slack_report_enabled.png b/tests/UI/expected-ui-screenshots/Slack_slack_report_enabled.png new file mode 100644 index 0000000..0646f52 Binary files /dev/null and b/tests/UI/expected-ui-screenshots/Slack_slack_report_enabled.png differ diff --git a/tests/UI/expected-ui-screenshots/Slack_slack_report_error.png b/tests/UI/expected-ui-screenshots/Slack_slack_report_error.png new file mode 100644 index 0000000..6e7b3b2 Binary files /dev/null and b/tests/UI/expected-ui-screenshots/Slack_slack_report_error.png differ diff --git a/tests/UI/expected-ui-screenshots/Slack_slack_report_pdf_save.png b/tests/UI/expected-ui-screenshots/Slack_slack_report_pdf_save.png new file mode 100644 index 0000000..3769ecc Binary files /dev/null and b/tests/UI/expected-ui-screenshots/Slack_slack_report_pdf_save.png differ diff --git a/tests/UI/expected-ui-screenshots/Slack_slack_report_pdf_view.png b/tests/UI/expected-ui-screenshots/Slack_slack_report_pdf_view.png new file mode 100644 index 0000000..0fc15b5 Binary files /dev/null and b/tests/UI/expected-ui-screenshots/Slack_slack_report_pdf_view.png differ diff --git a/tests/UI/expected-ui-screenshots/Slack_slack_report_save_report.png b/tests/UI/expected-ui-screenshots/Slack_slack_report_save_report.png new file mode 100644 index 0000000..c4df29f Binary files /dev/null and b/tests/UI/expected-ui-screenshots/Slack_slack_report_save_report.png differ diff --git a/vue/dist/Slack.umd.js b/vue/dist/Slack.umd.js new file mode 100644 index 0000000..0388857 --- /dev/null +++ b/vue/dist/Slack.umd.js @@ -0,0 +1,345 @@ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(require("CoreHome"), require("vue"), require("CorePluginsAdmin")); + else if(typeof define === 'function' && define.amd) + define(["CoreHome", , "CorePluginsAdmin"], factory); + else if(typeof exports === 'object') + exports["Slack"] = factory(require("CoreHome"), require("vue"), require("CorePluginsAdmin")); + else + root["Slack"] = factory(root["CoreHome"], root["Vue"], root["CorePluginsAdmin"]); +})((typeof self !== 'undefined' ? self : this), function(__WEBPACK_EXTERNAL_MODULE__19dc__, __WEBPACK_EXTERNAL_MODULE__8bbf__, __WEBPACK_EXTERNAL_MODULE_a5a2__) { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = "plugins/Slack/vue/dist/"; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = "fae3"); +/******/ }) +/************************************************************************/ +/******/ ({ + +/***/ "19dc": +/***/ (function(module, exports) { + +module.exports = __WEBPACK_EXTERNAL_MODULE__19dc__; + +/***/ }), + +/***/ "8bbf": +/***/ (function(module, exports) { + +module.exports = __WEBPACK_EXTERNAL_MODULE__8bbf__; + +/***/ }), + +/***/ "a5a2": +/***/ (function(module, exports) { + +module.exports = __WEBPACK_EXTERNAL_MODULE_a5a2__; + +/***/ }), + +/***/ "fae3": +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +// ESM COMPAT FLAG +__webpack_require__.r(__webpack_exports__); + +// EXPORTS +__webpack_require__.d(__webpack_exports__, "ReportParameters", function() { return /* reexport */ ReportParameters; }); +__webpack_require__.d(__webpack_exports__, "SelectSlackChannel", function() { return /* reexport */ SelectSlackChannel; }); + +// CONCATENATED MODULE: ./node_modules/@vue/cli-service/lib/commands/build/setPublicPath.js +// This file is imported into lib/wc client bundles. + +if (typeof window !== 'undefined') { + var currentScript = window.document.currentScript + if (false) { var getCurrentScript; } + + var src = currentScript && currentScript.src.match(/(.+\/)[^/]+\.js(\?.*)?$/) + if (src) { + __webpack_require__.p = src[1] // eslint-disable-line + } +} + +// Indicate to webpack that this file can be concatenated +/* harmony default export */ var setPublicPath = (null); + +// EXTERNAL MODULE: external {"commonjs":"vue","commonjs2":"vue","root":"Vue"} +var external_commonjs_vue_commonjs2_vue_root_Vue_ = __webpack_require__("8bbf"); + +// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js??ref--13-0!./node_modules/@vue/cli-plugin-babel/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/templateLoader.js??ref--6!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--1-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--1-1!./plugins/Slack/vue/src/ReportParameters/ReportParameters.vue?vue&type=template&id=5f5d6546 + +const _hoisted_1 = { + key: 0 +}; +function render(_ctx, _cache, $props, $setup, $data, $options) { + var _ctx$report; + const _component_SelectSlackChannel = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("SelectSlackChannel"); + return _ctx.report && _ctx.report.type === 'slack' ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", _hoisted_1, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_SelectSlackChannel, { + "is-slack-oauth-token-added": _ctx.isSlackOauthTokenAdded, + "with-introduction": true, + "model-value": (_ctx$report = _ctx.report) === null || _ctx$report === void 0 ? void 0 : _ctx$report.slackChannelID, + "onUpdate:modelValue": _cache[0] || (_cache[0] = $event => _ctx.$emit('change', 'slackChannelID', $event)) + }, null, 8, ["is-slack-oauth-token-added", "model-value"])])) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true); +} +// CONCATENATED MODULE: ./plugins/Slack/vue/src/ReportParameters/ReportParameters.vue?vue&type=template&id=5f5d6546 + +// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js??ref--13-0!./node_modules/@vue/cli-plugin-babel/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/templateLoader.js??ref--6!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--1-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--1-1!./plugins/Slack/vue/src/SelectSlackChannel/SelectSlackChannel.vue?vue&type=template&id=65e34972 + +const SelectSlackChannelvue_type_template_id_65e34972_hoisted_1 = { + class: "slack" +}; +const _hoisted_2 = { + id: "slackChannelIDHelp", + class: "inline-help-node" +}; +const _hoisted_3 = ["innerHTML"]; +const _hoisted_4 = ["textContent"]; +function SelectSlackChannelvue_type_template_id_65e34972_render(_ctx, _cache, $props, $setup, $data, $options) { + const _component_Field = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("Field"); + return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", SelectSlackChannelvue_type_template_id_65e34972_hoisted_1, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_Field, { + uicontrol: "text", + name: "channelID", + title: _ctx.translate('Slack_ChannelId'), + class: "slack", + "model-value": _ctx.modelValue, + disabled: !_ctx.isSlackOauthTokenAdded, + "onUpdate:modelValue": _cache[0] || (_cache[0] = $event => _ctx.$emit('update:modelValue', $event)) + }, { + "inline-help": Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withCtx"])(() => [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_2, [!_ctx.isSlackOauthTokenAdded ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("span", { + key: 0, + style: { + "margin-right": "3.5px" + }, + innerHTML: _ctx.$sanitize(_ctx.getSlackOAuthTokenNotAddedHelpText) + }, null, 8, _hoisted_3)) : (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("span", { + key: 1, + textContent: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('Slack_SlackEnterYourSlackChannelIdHelpText')) + }, null, 8, _hoisted_4))])]), + _: 1 + }, 8, ["title", "model-value", "disabled"])]); +} +// CONCATENATED MODULE: ./plugins/Slack/vue/src/SelectSlackChannel/SelectSlackChannel.vue?vue&type=template&id=65e34972 + +// EXTERNAL MODULE: external "CoreHome" +var external_CoreHome_ = __webpack_require__("19dc"); + +// EXTERNAL MODULE: external "CorePluginsAdmin" +var external_CorePluginsAdmin_ = __webpack_require__("a5a2"); + +// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-typescript/node_modules/cache-loader/dist/cjs.js??ref--15-0!./node_modules/babel-loader/lib!./node_modules/@vue/cli-plugin-typescript/node_modules/ts-loader??ref--15-2!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--1-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--1-1!./plugins/Slack/vue/src/SelectSlackChannel/SelectSlackChannel.vue?vue&type=script&lang=ts + + + +/* harmony default export */ var SelectSlackChannelvue_type_script_lang_ts = (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["defineComponent"])({ + props: { + modelValue: String, + isSlackOauthTokenAdded: { + type: Boolean, + default: false + }, + withIntroduction: Boolean + }, + emits: ['update:modelValue'], + components: { + Field: external_CorePluginsAdmin_["Field"] + }, + methods: { + linkTo(params) { + return `?${external_CoreHome_["MatomoUrl"].stringify(Object.assign(Object.assign({}, external_CoreHome_["MatomoUrl"].urlParsed.value), params))}`; + } + }, + computed: { + getSlackOAuthTokenNotAddedHelpText() { + const link = this.linkTo({ + module: 'CoreAdminHome', + action: 'generalSettings', + updated: null + }); + return Object(external_CoreHome_["translate"])('Slack_NoOauthTokenAdded', ``, ''); + } + } +})); +// CONCATENATED MODULE: ./plugins/Slack/vue/src/SelectSlackChannel/SelectSlackChannel.vue?vue&type=script&lang=ts + +// CONCATENATED MODULE: ./plugins/Slack/vue/src/SelectSlackChannel/SelectSlackChannel.vue + + + +SelectSlackChannelvue_type_script_lang_ts.render = SelectSlackChannelvue_type_template_id_65e34972_render + +/* harmony default export */ var SelectSlackChannel = (SelectSlackChannelvue_type_script_lang_ts); +// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-typescript/node_modules/cache-loader/dist/cjs.js??ref--15-0!./node_modules/babel-loader/lib!./node_modules/@vue/cli-plugin-typescript/node_modules/ts-loader??ref--15-2!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--1-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--1-1!./plugins/Slack/vue/src/ReportParameters/ReportParameters.vue?vue&type=script&lang=ts + + +const REPORT_TYPE = 'slack'; +/* harmony default export */ var ReportParametersvue_type_script_lang_ts = (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["defineComponent"])({ + props: { + report: { + type: Object, + required: true + }, + isSlackOauthTokenAdded: { + type: Boolean, + default: false + }, + defaultFormat: { + type: String, + required: true + }, + defaultDisplayFormat: { + type: Number, + required: true + }, + defaultEvolutionGraph: { + type: Boolean, + required: true + } + }, + components: { + SelectSlackChannel: SelectSlackChannel + }, + emits: ['change'], + setup(props) { + const { + resetReportParametersFunctions, + updateReportParametersFunctions, + getReportParametersFunctions + } = window; + if (!resetReportParametersFunctions[REPORT_TYPE]) { + resetReportParametersFunctions[REPORT_TYPE] = report => { + report.displayFormat = props.defaultDisplayFormat; + report.evolutionGraph = props.defaultEvolutionGraph; + report.formatslack = props.defaultFormat; + report.slackChannelID = ''; + }; + } + if (!updateReportParametersFunctions[REPORT_TYPE]) { + updateReportParametersFunctions[REPORT_TYPE] = report => { + if (!(report !== null && report !== void 0 && report.parameters)) { + return; + } + ['displayFormat', 'evolutionGraph', 'slackChannelID'].forEach(field => { + if (field in report.parameters) { + report[field] = report.parameters[field]; + } + }); + }; + } + if (!getReportParametersFunctions[REPORT_TYPE]) { + getReportParametersFunctions[REPORT_TYPE] = report => ({ + displayFormat: report.displayFormat, + evolutionGraph: report.evolutionGraph, + slackChannelID: report.slackChannelID + }); + } + } +})); +// CONCATENATED MODULE: ./plugins/Slack/vue/src/ReportParameters/ReportParameters.vue?vue&type=script&lang=ts + +// CONCATENATED MODULE: ./plugins/Slack/vue/src/ReportParameters/ReportParameters.vue + + + +ReportParametersvue_type_script_lang_ts.render = render + +/* harmony default export */ var ReportParameters = (ReportParametersvue_type_script_lang_ts); +// CONCATENATED MODULE: ./plugins/Slack/vue/src/index.ts +/*! + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + + +// CONCATENATED MODULE: ./node_modules/@vue/cli-service/lib/commands/build/entry-lib-no-default.js + + + + +/***/ }) + +/******/ }); +}); +//# sourceMappingURL=Slack.umd.js.map \ No newline at end of file diff --git a/vue/dist/Slack.umd.js.map b/vue/dist/Slack.umd.js.map new file mode 100644 index 0000000..5a11a80 --- /dev/null +++ b/vue/dist/Slack.umd.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack://Slack/webpack/universalModuleDefinition","webpack://Slack/webpack/bootstrap","webpack://Slack/external \"CoreHome\"","webpack://Slack/external {\"commonjs\":\"vue\",\"commonjs2\":\"vue\",\"root\":\"Vue\"}","webpack://Slack/external \"CorePluginsAdmin\"","webpack://Slack/./node_modules/@vue/cli-service/lib/commands/build/setPublicPath.js","webpack://Slack/./plugins/Slack/vue/src/ReportParameters/ReportParameters.vue","webpack://Slack/./plugins/Slack/vue/src/SelectSlackChannel/SelectSlackChannel.vue","webpack://Slack/./plugins/Slack/vue/src/SelectSlackChannel/SelectSlackChannel.vue?3bdf","webpack://Slack/./plugins/Slack/vue/src/SelectSlackChannel/SelectSlackChannel.vue?d10e","webpack://Slack/./plugins/Slack/vue/src/SelectSlackChannel/SelectSlackChannel.vue?2e22","webpack://Slack/./plugins/Slack/vue/src/ReportParameters/ReportParameters.vue?d296","webpack://Slack/./plugins/Slack/vue/src/ReportParameters/ReportParameters.vue?91d4","webpack://Slack/./plugins/Slack/vue/src/ReportParameters/ReportParameters.vue?0a5f","webpack://Slack/./plugins/Slack/vue/src/index.ts","webpack://Slack/./node_modules/@vue/cli-service/lib/commands/build/entry-lib-no-default.js"],"names":[],"mappings":"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","file":"Slack.umd.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"CoreHome\"), require(\"vue\"), require(\"CorePluginsAdmin\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"CoreHome\", , \"CorePluginsAdmin\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"Slack\"] = factory(require(\"CoreHome\"), require(\"vue\"), require(\"CorePluginsAdmin\"));\n\telse\n\t\troot[\"Slack\"] = factory(root[\"CoreHome\"], root[\"Vue\"], root[\"CorePluginsAdmin\"]);\n})((typeof self !== 'undefined' ? self : this), function(__WEBPACK_EXTERNAL_MODULE__19dc__, __WEBPACK_EXTERNAL_MODULE__8bbf__, __WEBPACK_EXTERNAL_MODULE_a5a2__) {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"plugins/Slack/vue/dist/\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"fae3\");\n","module.exports = __WEBPACK_EXTERNAL_MODULE__19dc__;","module.exports = __WEBPACK_EXTERNAL_MODULE__8bbf__;","module.exports = __WEBPACK_EXTERNAL_MODULE_a5a2__;","// This file is imported into lib/wc client bundles.\n\nif (typeof window !== 'undefined') {\n var currentScript = window.document.currentScript\n if (process.env.NEED_CURRENTSCRIPT_POLYFILL) {\n var getCurrentScript = require('@soda/get-current-script')\n currentScript = getCurrentScript()\n\n // for backward compatibility, because previously we directly included the polyfill\n if (!('currentScript' in document)) {\n Object.defineProperty(document, 'currentScript', { get: getCurrentScript })\n }\n }\n\n var src = currentScript && currentScript.src.match(/(.+\\/)[^/]+\\.js(\\?.*)?$/)\n if (src) {\n __webpack_public_path__ = src[1] // eslint-disable-line\n }\n}\n\n// Indicate to webpack that this file can be concatenated\nexport default null\n","\n\n\n\n\n","\n\n\n\n\n","\nimport { defineComponent } from 'vue';\nimport { MatomoUrl, translate } from 'CoreHome';\nimport { Field } from 'CorePluginsAdmin';\n\nexport default defineComponent({\n props: {\n modelValue: String,\n isSlackOauthTokenAdded: {\n type: Boolean,\n default: false,\n },\n withIntroduction: Boolean,\n },\n emits: ['update:modelValue'],\n components: {\n Field,\n },\n methods: {\n linkTo(params: QueryParameters) {\n return `?${MatomoUrl.stringify({\n ...MatomoUrl.urlParsed.value,\n ...params,\n })}`;\n },\n },\n computed: {\n getSlackOAuthTokenNotAddedHelpText() {\n const link = this.linkTo({ module: 'CoreAdminHome', action: 'generalSettings', updated: null });\n return translate(\n 'Slack_NoOauthTokenAdded',\n ``,\n '',\n );\n },\n },\n});\n","export { default } from \"-!../../../../../node_modules/@vue/cli-plugin-typescript/node_modules/cache-loader/dist/cjs.js??ref--15-0!../../../../../node_modules/babel-loader/lib/index.js!../../../../../node_modules/@vue/cli-plugin-typescript/node_modules/ts-loader/index.js??ref--15-2!../../../../../node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--1-0!../../../../../node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/index.js??ref--1-1!./SelectSlackChannel.vue?vue&type=script&lang=ts\"; export * from \"-!../../../../../node_modules/@vue/cli-plugin-typescript/node_modules/cache-loader/dist/cjs.js??ref--15-0!../../../../../node_modules/babel-loader/lib/index.js!../../../../../node_modules/@vue/cli-plugin-typescript/node_modules/ts-loader/index.js??ref--15-2!../../../../../node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--1-0!../../../../../node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/index.js??ref--1-1!./SelectSlackChannel.vue?vue&type=script&lang=ts\"","import { render } from \"./SelectSlackChannel.vue?vue&type=template&id=65e34972\"\nimport script from \"./SelectSlackChannel.vue?vue&type=script&lang=ts\"\nexport * from \"./SelectSlackChannel.vue?vue&type=script&lang=ts\"\nscript.render = render\n\nexport default script","\nimport { defineComponent } from 'vue';\nimport { Report } from 'ScheduledReports';\nimport SelectSlackChannel from '../SelectSlackChannel/SelectSlackChannel.vue';\n\nconst REPORT_TYPE = 'slack';\n\nexport default defineComponent({\n props: {\n report: {\n type: Object,\n required: true,\n },\n isSlackOauthTokenAdded: {\n type: Boolean,\n default: false,\n },\n defaultFormat: {\n type: String,\n required: true,\n },\n defaultDisplayFormat: {\n type: Number,\n required: true,\n },\n defaultEvolutionGraph: {\n type: Boolean,\n required: true,\n },\n },\n components: {\n SelectSlackChannel,\n },\n emits: ['change'],\n setup(props) {\n const {\n resetReportParametersFunctions,\n updateReportParametersFunctions,\n getReportParametersFunctions,\n } = window;\n\n if (!resetReportParametersFunctions[REPORT_TYPE]) {\n resetReportParametersFunctions[REPORT_TYPE] = (report: Report) => {\n report.displayFormat = props.defaultDisplayFormat;\n report.evolutionGraph = props.defaultEvolutionGraph;\n report.formatslack = props.defaultFormat;\n report.slackChannelID = '';\n };\n }\n\n if (!updateReportParametersFunctions[REPORT_TYPE]) {\n updateReportParametersFunctions[REPORT_TYPE] = (report: Report) => {\n if (!report?.parameters) {\n return;\n }\n\n ['displayFormat', 'evolutionGraph', 'slackChannelID'].forEach((field) => {\n if (field in report.parameters) {\n report[field] = report.parameters[field];\n }\n });\n };\n }\n\n if (!getReportParametersFunctions[REPORT_TYPE]) {\n getReportParametersFunctions[REPORT_TYPE] = (report: Report) => ({\n displayFormat: report.displayFormat,\n evolutionGraph: report.evolutionGraph,\n slackChannelID: report.slackChannelID,\n });\n }\n },\n});\n","export { default } from \"-!../../../../../node_modules/@vue/cli-plugin-typescript/node_modules/cache-loader/dist/cjs.js??ref--15-0!../../../../../node_modules/babel-loader/lib/index.js!../../../../../node_modules/@vue/cli-plugin-typescript/node_modules/ts-loader/index.js??ref--15-2!../../../../../node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--1-0!../../../../../node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/index.js??ref--1-1!./ReportParameters.vue?vue&type=script&lang=ts\"; export * from \"-!../../../../../node_modules/@vue/cli-plugin-typescript/node_modules/cache-loader/dist/cjs.js??ref--15-0!../../../../../node_modules/babel-loader/lib/index.js!../../../../../node_modules/@vue/cli-plugin-typescript/node_modules/ts-loader/index.js??ref--15-2!../../../../../node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--1-0!../../../../../node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/index.js??ref--1-1!./ReportParameters.vue?vue&type=script&lang=ts\"","import { render } from \"./ReportParameters.vue?vue&type=template&id=5f5d6546\"\nimport script from \"./ReportParameters.vue?vue&type=script&lang=ts\"\nexport * from \"./ReportParameters.vue?vue&type=script&lang=ts\"\nscript.render = render\n\nexport default script","/*!\n * Matomo - free/libre analytics platform\n *\n * @link https://matomo.org\n * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later\n */\n\nexport { default as ReportParameters } from './ReportParameters/ReportParameters.vue';\nexport { default as SelectSlackChannel } from './SelectSlackChannel/SelectSlackChannel.vue';\n","import './setPublicPath'\nexport * from '~entry'\n"],"sourceRoot":""} \ No newline at end of file diff --git a/vue/dist/Slack.umd.min.js b/vue/dist/Slack.umd.min.js new file mode 100644 index 0000000..88c76ff --- /dev/null +++ b/vue/dist/Slack.umd.min.js @@ -0,0 +1,8 @@ +(function(e,t){"object"===typeof exports&&"object"===typeof module?module.exports=t(require("CoreHome"),require("vue"),require("CorePluginsAdmin")):"function"===typeof define&&define.amd?define(["CoreHome",,"CorePluginsAdmin"],t):"object"===typeof exports?exports["Slack"]=t(require("CoreHome"),require("vue"),require("CorePluginsAdmin")):e["Slack"]=t(e["CoreHome"],e["Vue"],e["CorePluginsAdmin"])})("undefined"!==typeof self?self:this,(function(e,t,n){return function(e){var t={};function n(o){if(t[o])return t[o].exports;var r=t[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,n),r.l=!0,r.exports}return n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)n.d(o,r,function(t){return e[t]}.bind(null,r));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="plugins/Slack/vue/dist/",n(n.s="fae3")}({"19dc":function(t,n){t.exports=e},"8bbf":function(e,n){e.exports=t},a5a2:function(e,t){e.exports=n},fae3:function(e,t,n){"use strict";if(n.r(t),n.d(t,"ReportParameters",(function(){return y})),n.d(t,"SelectSlackChannel",(function(){return b})),"undefined"!==typeof window){var o=window.document.currentScript,r=o&&o.src.match(/(.+\/)[^/]+\.js(\?.*)?$/);r&&(n.p=r[1])}var a=n("8bbf");const l={key:0};function i(e,t,n,o,r,i){var c;const u=Object(a["resolveComponent"])("SelectSlackChannel");return e.report&&"slack"===e.report.type?(Object(a["openBlock"])(),Object(a["createElementBlock"])("div",l,[Object(a["createVNode"])(u,{"is-slack-oauth-token-added":e.isSlackOauthTokenAdded,"with-introduction":!0,"model-value":null===(c=e.report)||void 0===c?void 0:c.slackChannelID,"onUpdate:modelValue":t[0]||(t[0]=t=>e.$emit("change","slackChannelID",t))},null,8,["is-slack-oauth-token-added","model-value"])])):Object(a["createCommentVNode"])("",!0)}const c={class:"slack"},u={id:"slackChannelIDHelp",class:"inline-help-node"},d=["innerHTML"],s=["textContent"];function p(e,t,n,o,r,l){const i=Object(a["resolveComponent"])("Field");return Object(a["openBlock"])(),Object(a["createElementBlock"])("div",c,[Object(a["createVNode"])(i,{uicontrol:"text",name:"channelID",title:e.translate("Slack_ChannelId"),class:"slack","model-value":e.modelValue,disabled:!e.isSlackOauthTokenAdded,"onUpdate:modelValue":t[0]||(t[0]=t=>e.$emit("update:modelValue",t))},{"inline-help":Object(a["withCtx"])(()=>[Object(a["createElementVNode"])("div",u,[e.isSlackOauthTokenAdded?(Object(a["openBlock"])(),Object(a["createElementBlock"])("span",{key:1,textContent:Object(a["toDisplayString"])(e.translate("Slack_SlackEnterYourSlackChannelIdHelpText"))},null,8,s)):(Object(a["openBlock"])(),Object(a["createElementBlock"])("span",{key:0,style:{"margin-right":"3.5px"},innerHTML:e.$sanitize(e.getSlackOAuthTokenNotAddedHelpText)},null,8,d))])]),_:1},8,["title","model-value","disabled"])])}var m=n("19dc"),f=n("a5a2"),k=Object(a["defineComponent"])({props:{modelValue:String,isSlackOauthTokenAdded:{type:Boolean,default:!1},withIntroduction:Boolean},emits:["update:modelValue"],components:{Field:f["Field"]},methods:{linkTo(e){return"?"+m["MatomoUrl"].stringify(Object.assign(Object.assign({},m["MatomoUrl"].urlParsed.value),e))}},computed:{getSlackOAuthTokenNotAddedHelpText(){const e=this.linkTo({module:"CoreAdminHome",action:"generalSettings",updated:null});return Object(m["translate"])("Slack_NoOauthTokenAdded",``,"")}}});k.render=p;var b=k;const h="slack";var v=Object(a["defineComponent"])({props:{report:{type:Object,required:!0},isSlackOauthTokenAdded:{type:Boolean,default:!1},defaultFormat:{type:String,required:!0},defaultDisplayFormat:{type:Number,required:!0},defaultEvolutionGraph:{type:Boolean,required:!0}},components:{SelectSlackChannel:b},emits:["change"],setup(e){const{resetReportParametersFunctions:t,updateReportParametersFunctions:n,getReportParametersFunctions:o}=window;t[h]||(t[h]=t=>{t.displayFormat=e.defaultDisplayFormat,t.evolutionGraph=e.defaultEvolutionGraph,t.formatslack=e.defaultFormat,t.slackChannelID=""}),n[h]||(n[h]=e=>{null!==e&&void 0!==e&&e.parameters&&["displayFormat","evolutionGraph","slackChannelID"].forEach(t=>{t in e.parameters&&(e[t]=e.parameters[t])})}),o[h]||(o[h]=e=>({displayFormat:e.displayFormat,evolutionGraph:e.evolutionGraph,slackChannelID:e.slackChannelID}))}});v.render=i;var y=v; +/*! + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */}})})); +//# sourceMappingURL=Slack.umd.min.js.map \ No newline at end of file diff --git a/vue/dist/Slack.umd.min.js.map b/vue/dist/Slack.umd.min.js.map new file mode 100644 index 0000000..be0a6c1 --- /dev/null +++ b/vue/dist/Slack.umd.min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack://Slack/webpack/universalModuleDefinition","webpack://Slack/webpack/bootstrap","webpack://Slack/external \"CoreHome\"","webpack://Slack/external {\"commonjs\":\"vue\",\"commonjs2\":\"vue\",\"root\":\"Vue\"}","webpack://Slack/external \"CorePluginsAdmin\"","webpack://Slack/./node_modules/@vue/cli-service/lib/commands/build/setPublicPath.js","webpack://Slack/./plugins/Slack/vue/src/ReportParameters/ReportParameters.vue","webpack://Slack/./plugins/Slack/vue/src/SelectSlackChannel/SelectSlackChannel.vue","webpack://Slack/./plugins/Slack/vue/src/SelectSlackChannel/SelectSlackChannel.vue?3bdf","webpack://Slack/./plugins/Slack/vue/src/SelectSlackChannel/SelectSlackChannel.vue?2e22","webpack://Slack/./plugins/Slack/vue/src/ReportParameters/ReportParameters.vue?d296","webpack://Slack/./plugins/Slack/vue/src/ReportParameters/ReportParameters.vue?0a5f"],"names":["root","factory","exports","module","require","define","amd","self","this","__WEBPACK_EXTERNAL_MODULE__19dc__","__WEBPACK_EXTERNAL_MODULE__8bbf__","__WEBPACK_EXTERNAL_MODULE_a5a2__","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","window","currentScript","document","src","match","report","type","is-slack-oauth-token-added","isSlackOauthTokenAdded","with-introduction","model-value","slackChannelID","$emit","$event","class","id","uicontrol","title","translate","modelValue","disabled","inline-help","style","$sanitize","getSlackOAuthTokenNotAddedHelpText","props","String","Boolean","default","withIntroduction","emits","components","Field","methods","params","stringify","urlParsed","computed","link","linkTo","action","updated","render","REPORT_TYPE","required","defaultFormat","defaultDisplayFormat","Number","defaultEvolutionGraph","SelectSlackChannel","resetReportParametersFunctions","updateReportParametersFunctions","getReportParametersFunctions","displayFormat","evolutionGraph","formatslack","parameters","forEach","field"],"mappings":"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","file":"Slack.umd.min.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"CoreHome\"), require(\"vue\"), require(\"CorePluginsAdmin\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"CoreHome\", , \"CorePluginsAdmin\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"Slack\"] = factory(require(\"CoreHome\"), require(\"vue\"), require(\"CorePluginsAdmin\"));\n\telse\n\t\troot[\"Slack\"] = factory(root[\"CoreHome\"], root[\"Vue\"], root[\"CorePluginsAdmin\"]);\n})((typeof self !== 'undefined' ? self : this), function(__WEBPACK_EXTERNAL_MODULE__19dc__, __WEBPACK_EXTERNAL_MODULE__8bbf__, __WEBPACK_EXTERNAL_MODULE_a5a2__) {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"plugins/Slack/vue/dist/\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"fae3\");\n","module.exports = __WEBPACK_EXTERNAL_MODULE__19dc__;","module.exports = __WEBPACK_EXTERNAL_MODULE__8bbf__;","module.exports = __WEBPACK_EXTERNAL_MODULE_a5a2__;","// This file is imported into lib/wc client bundles.\n\nif (typeof window !== 'undefined') {\n var currentScript = window.document.currentScript\n if (process.env.NEED_CURRENTSCRIPT_POLYFILL) {\n var getCurrentScript = require('@soda/get-current-script')\n currentScript = getCurrentScript()\n\n // for backward compatibility, because previously we directly included the polyfill\n if (!('currentScript' in document)) {\n Object.defineProperty(document, 'currentScript', { get: getCurrentScript })\n }\n }\n\n var src = currentScript && currentScript.src.match(/(.+\\/)[^/]+\\.js(\\?.*)?$/)\n if (src) {\n __webpack_public_path__ = src[1] // eslint-disable-line\n }\n}\n\n// Indicate to webpack that this file can be concatenated\nexport default null\n","\n\n\n\n\n","\n\n\n\n\n","\nimport { defineComponent } from 'vue';\nimport { MatomoUrl, translate } from 'CoreHome';\nimport { Field } from 'CorePluginsAdmin';\n\nexport default defineComponent({\n props: {\n modelValue: String,\n isSlackOauthTokenAdded: {\n type: Boolean,\n default: false,\n },\n withIntroduction: Boolean,\n },\n emits: ['update:modelValue'],\n components: {\n Field,\n },\n methods: {\n linkTo(params: QueryParameters) {\n return `?${MatomoUrl.stringify({\n ...MatomoUrl.urlParsed.value,\n ...params,\n })}`;\n },\n },\n computed: {\n getSlackOAuthTokenNotAddedHelpText() {\n const link = this.linkTo({ module: 'CoreAdminHome', action: 'generalSettings', updated: null });\n return translate(\n 'Slack_NoOauthTokenAdded',\n ``,\n '',\n );\n },\n },\n});\n","import { render } from \"./SelectSlackChannel.vue?vue&type=template&id=65e34972\"\nimport script from \"./SelectSlackChannel.vue?vue&type=script&lang=ts\"\nexport * from \"./SelectSlackChannel.vue?vue&type=script&lang=ts\"\nscript.render = render\n\nexport default script","\nimport { defineComponent } from 'vue';\nimport { Report } from 'ScheduledReports';\nimport SelectSlackChannel from '../SelectSlackChannel/SelectSlackChannel.vue';\n\nconst REPORT_TYPE = 'slack';\n\nexport default defineComponent({\n props: {\n report: {\n type: Object,\n required: true,\n },\n isSlackOauthTokenAdded: {\n type: Boolean,\n default: false,\n },\n defaultFormat: {\n type: String,\n required: true,\n },\n defaultDisplayFormat: {\n type: Number,\n required: true,\n },\n defaultEvolutionGraph: {\n type: Boolean,\n required: true,\n },\n },\n components: {\n SelectSlackChannel,\n },\n emits: ['change'],\n setup(props) {\n const {\n resetReportParametersFunctions,\n updateReportParametersFunctions,\n getReportParametersFunctions,\n } = window;\n\n if (!resetReportParametersFunctions[REPORT_TYPE]) {\n resetReportParametersFunctions[REPORT_TYPE] = (report: Report) => {\n report.displayFormat = props.defaultDisplayFormat;\n report.evolutionGraph = props.defaultEvolutionGraph;\n report.formatslack = props.defaultFormat;\n report.slackChannelID = '';\n };\n }\n\n if (!updateReportParametersFunctions[REPORT_TYPE]) {\n updateReportParametersFunctions[REPORT_TYPE] = (report: Report) => {\n if (!report?.parameters) {\n return;\n }\n\n ['displayFormat', 'evolutionGraph', 'slackChannelID'].forEach((field) => {\n if (field in report.parameters) {\n report[field] = report.parameters[field];\n }\n });\n };\n }\n\n if (!getReportParametersFunctions[REPORT_TYPE]) {\n getReportParametersFunctions[REPORT_TYPE] = (report: Report) => ({\n displayFormat: report.displayFormat,\n evolutionGraph: report.evolutionGraph,\n slackChannelID: report.slackChannelID,\n });\n }\n },\n});\n","import { render } from \"./ReportParameters.vue?vue&type=template&id=5f5d6546\"\nimport script from \"./ReportParameters.vue?vue&type=script&lang=ts\"\nexport * from \"./ReportParameters.vue?vue&type=script&lang=ts\"\nscript.render = render\n\nexport default script"],"sourceRoot":""} \ No newline at end of file diff --git a/vue/dist/umd.metadata.json b/vue/dist/umd.metadata.json new file mode 100644 index 0000000..58e29a1 --- /dev/null +++ b/vue/dist/umd.metadata.json @@ -0,0 +1,7 @@ +{ + "dependsOn": [ + "ScheduledReports", + "CoreHome", + "CorePluginsAdmin" + ] +} \ No newline at end of file diff --git a/vue/src/ReportParameters/ReportParameters.vue b/vue/src/ReportParameters/ReportParameters.vue new file mode 100644 index 0000000..9a6e051 --- /dev/null +++ b/vue/src/ReportParameters/ReportParameters.vue @@ -0,0 +1,92 @@ + + + + + diff --git a/vue/src/SelectSlackChannel/SelectSlackChannel.vue b/vue/src/SelectSlackChannel/SelectSlackChannel.vue new file mode 100644 index 0000000..22f9c30 --- /dev/null +++ b/vue/src/SelectSlackChannel/SelectSlackChannel.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/vue/src/index.ts b/vue/src/index.ts new file mode 100644 index 0000000..f7697c6 --- /dev/null +++ b/vue/src/index.ts @@ -0,0 +1,9 @@ +/*! + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +export { default as ReportParameters } from './ReportParameters/ReportParameters.vue'; +export { default as SelectSlackChannel } from './SelectSlackChannel/SelectSlackChannel.vue';