diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..31188f6 --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +IFTTT_WEBHOOK_URL= + +INTEGROMAT_WEBHOOK_URL= diff --git a/.environment b/.environment new file mode 100644 index 0000000..f55ecf9 --- /dev/null +++ b/.environment @@ -0,0 +1,4 @@ +unset NPM_CONFIG_PREFIX +export NO_UPDATE_NOTIFIER=1 +export NVM_DIR="$PLATFORM_APP_DIR/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" diff --git a/.gitignore b/.gitignore index 20e9122..2276127 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,12 @@ !/**/.gitkeep !/.docker.env.example !/.dockerignore +!/.env.example +!/.environment !/.github/** !/.idea/ +!/.platform/** +!/.platform.app.yaml !/assets/** !/bin/ !/config/** @@ -21,8 +25,10 @@ !/web/sites/default/environments/settings.*.php !/web/sites/default/settings.php !/web/sites/default/settings.docker.php +!/web/sites/default/settings.platformsh.php !/web/themes/custom/** /.idea/workspace.xml +/.platform/local/ /node_modules/ /tools/ansible/.roles/ /vendor/ diff --git a/.platform.app.yaml b/.platform.app.yaml new file mode 100644 index 0000000..3f2b7ec --- /dev/null +++ b/.platform.app.yaml @@ -0,0 +1,123 @@ +name: 'app' +type: 'php:7.4' + +variables: + env: + NODE_VERSION: v14.13.1 + NVM_VERSION: v0.36.0 + +dependencies: + nodejs: + npm: 6.14.10 + php: + composer/composer: '^2' + +runtime: + extensions: + - redis + +relationships: + database: 'db:mysql' + redis: 'cache:redis' + +disk: 2048 + +mounts: + '/web/sites/default/files': + source: local + source_path: 'files' + '/tmp': + source: local + source_path: 'tmp' + '/private': + source: local + source_path: 'private' + '/.drush': + source: local + source_path: 'drush' + '/drush-backups': + source: local + source_path: 'drush-backups' + +build: + flavor: none + +hooks: + build: | + set -e + export PATH=/app/bin:$PATH + + curl -sS https://platform.sh/cli/installer | php + # source ~/.environment + + composer --no-ansi --no-interaction install --no-progress --prefer-dist --optimize-autoloader --no-dev + + # platform sql 'SELECT body_value FROM block_content__body UNION SELECT body_value FROM node__body' > /tmp/body-field-values.txt + + cd web/themes/custom/opdavies + + unset NPM_CONFIG_PREFIX + export NVM_DIR="$PLATFORM_APP_DIR/.nvm" + curl -f -o- https://raw.githubusercontent.com/nvm-sh/nvm/$NVM_VERSION/install.sh | bash + [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" + + npm clean-install + npm run production + rm -fr node_modules + + unset NPM_CONFIG_PREFIX + deploy: | + set -e + export PATH=/app/bin:$PATH + drush -y cache-rebuild + drush -y updatedb + drush -y config-import + +web: + locations: + '/': + root: 'web' + expires: 5m + passthru: '/index.php' + allow: false + rules: + '\.(jpe?g|png|gif|svgz?|css|js|map|ico|bmp|eot|woff2?|otf|ttf)$': + allow: true + '^/robots\.txt$': + allow: true + '^/sitemap\.xml$': + allow: true + '^/sites/sites\.php$': + scripts: false + '^/sites/[^/]+/settings.*?\.php$': + scripts: false + + '/sites/default/files': + allow: true + expires: 5m + passthru: '/index.php' + root: 'web/sites/default/files' + scripts: false + rules: + '^/sites/default/files/(css|js)': + expires: 2w + +crons: + drupal: + spec: '*/19 * * * *' + cmd: 'cd web && drush core-cron' + + snapshot: + spec: '0 5 * * *' + cmd: | + if [ "$PLATFORM_BRANCH" = production ]; then + platform snapshot:create --yes --no-wait + fi + + renewcert: + # Force a redeploy at 5am (UTC) on the 1st and 15th of every month. + spec: '0 5 1,15 * *' + cmd: | + if [ "$PLATFORM_BRANCH" = production ]; then + platform redeploy --yes --no-wait + fi diff --git a/.platform/routes.yaml b/.platform/routes.yaml new file mode 100644 index 0000000..a876694 --- /dev/null +++ b/.platform/routes.yaml @@ -0,0 +1,10 @@ +"https://{default}/": + type: upstream + upstream: "app:http" + cache: + enabled: true + cookies: ['/^SS?ESS/', '/^Drupal.visitor/'] + +"https://www.{default}/": + type: redirect + to: "https://{default}/" diff --git a/.platform/services.yaml b/.platform/services.yaml new file mode 100644 index 0000000..6ffaa3b --- /dev/null +++ b/.platform/services.yaml @@ -0,0 +1,6 @@ +db: + type: mariadb:10.4 + disk: 2048 + +cache: + type: redis:6.0 diff --git a/composer.json b/composer.json index 7bfef65..bb271c2 100644 --- a/composer.json +++ b/composer.json @@ -42,6 +42,7 @@ "drupal/stage_file_proxy": "^1.0", "drush/drush": "^10", "nesbot/carbon": "^2.33", + "platformsh/config-reader": "^2.4", "symfony/config": "^3.4", "tightenco/collect": "^8.17" }, diff --git a/composer.lock b/composer.lock index db6767e..d1cb789 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "2cd7a735076f7c850d3e2541afa139e0", + "content-hash": "af63f9fcebff0e2607c7d31c00d10c3c", "packages": [ { "name": "asm89/stack-cors", @@ -3531,6 +3531,9 @@ "status": "not-covered", "message": "Project has not opted into security advisory coverage!" } + }, + "patches_applied": { + "Return early if user is not anonymous": "tools/patches/plausible/return-if-authenticated.patch" } }, "notification-url": "https://packages.drupal.org/8/downloads", @@ -5531,6 +5534,45 @@ }, "time": "2019-12-10T10:24:42+00:00" }, + { + "name": "platformsh/config-reader", + "version": "2.4.0", + "source": { + "type": "git", + "url": "https://github.com/platformsh/config-reader-php.git", + "reference": "5511abfdb673ccfcf0eac9eaf65204f73edd90fd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/platformsh/config-reader-php/zipball/5511abfdb673ccfcf0eac9eaf65204f73edd90fd", + "reference": "5511abfdb673ccfcf0eac9eaf65204f73edd90fd", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Platformsh\\ConfigReader\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Larry Garfield", + "email": "larry@platform.sh" + } + ], + "description": "Small helper to access Platform.sh environment variables", + "time": "2020-12-10T20:50:12+00:00" + }, { "name": "psr/container", "version": "1.0.0", @@ -8327,8 +8369,8 @@ "validate" ], "support": { - "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.9.1" + "issues": "https://github.com/webmozart/assert/issues", + "source": "https://github.com/webmozart/assert/tree/master" }, "time": "2020-07-08T17:02:28+00:00" }, @@ -11923,5 +11965,5 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "2.0.0" + "plugin-api-version": "1.1.0" } diff --git a/web/sites/default/settings.php b/web/sites/default/settings.php index e1b5d02..3bbbc8a 100644 --- a/web/sites/default/settings.php +++ b/web/sites/default/settings.php @@ -760,6 +760,13 @@ $settings['entity_update_backup'] = TRUE; $settings["config_sync_directory"] = '../config'; +$config['opdavies_blog.settings']['integromat_webhook_url'] = getenv('INTEGROMAT_WEBHOOK_URL'); +$config['opdavies_blog.settings']['post_tweet_webhook_url'] = getenv('IFTTT_WEBHOOK_URL'); + +if (file_exists($app_root . '/' . $site_path . '/settings.platformsh.php')) { + include $app_root . '/' . $site_path . '/settings.platformsh.php'; +} + if (file_exists($app_root . '/' . $site_path . '/settings.local.php')) { include $app_root . '/' . $site_path . '/settings.local.php'; } diff --git a/web/sites/default/settings.platformsh.php b/web/sites/default/settings.platformsh.php new file mode 100644 index 0000000..adf5ec9 --- /dev/null +++ b/web/sites/default/settings.platformsh.php @@ -0,0 +1,170 @@ +hasRelationship('database')) { + $creds = $platformsh->credentials('database'); + $databases['default']['default'] = [ + 'driver' => $creds['scheme'], + 'database' => $creds['path'], + 'username' => $creds['username'], + 'password' => $creds['password'], + 'host' => $creds['host'], + 'port' => $creds['port'], + 'pdo' => [PDO::MYSQL_ATTR_COMPRESS => !empty($creds['query']['compression'])] + ]; +} + +// Enable verbose error messages on development branches, but not on the production branch. +// You may add more debug-centric settings here if desired to have them automatically enable +// on development but not production. +if (isset($platformsh->branch)) { + // Production type environment. + if ($platformsh->branch == 'master' || $platformsh->onDedicated()) { + $config['system.logging']['error_level'] = 'hide'; + } // Development type environment. + else { + $config['system.logging']['error_level'] = 'verbose'; + } +} + +// Enable Redis caching. +if ($platformsh->hasRelationship('redis') && !InstallerKernel::installationAttempted() && extension_loaded('redis') && class_exists('Drupal\redis\ClientFactory')) { + $redis = $platformsh->credentials('redis'); + + // Set Redis as the default backend for any cache bin not otherwise specified. + $settings['cache']['default'] = 'cache.backend.redis'; + $settings['redis.connection']['host'] = $redis['host']; + $settings['redis.connection']['port'] = $redis['port']; + + // Apply changes to the container configuration to better leverage Redis. + // This includes using Redis for the lock and flood control systems, as well + // as the cache tag checksum. Alternatively, copy the contents of that file + // to your project-specific services.yml file, modify as appropriate, and + // remove this line. + $settings['container_yamls'][] = 'modules/contrib/redis/example.services.yml'; + + // Allow the services to work before the Redis module itself is enabled. + $settings['container_yamls'][] = 'modules/contrib/redis/redis.services.yml'; + + // Manually add the classloader path, this is required for the container cache bin definition below + // and allows to use it without the redis module being enabled. + $class_loader->addPsr4('Drupal\\redis\\', 'modules/contrib/redis/src'); + + // Use redis for container cache. + // The container cache is used to load the container definition itself, and + // thus any configuration stored in the container itself is not available + // yet. These lines force the container cache to use Redis rather than the + // default SQL cache. + $settings['bootstrap_container_definition'] = [ + 'parameters' => [], + 'services' => [ + 'redis.factory' => [ + 'class' => 'Drupal\redis\ClientFactory', + ], + 'cache.backend.redis' => [ + 'class' => 'Drupal\redis\Cache\CacheBackendFactory', + 'arguments' => ['@redis.factory', '@cache_tags_provider.container', '@serialization.phpserialize'], + ], + 'cache.container' => [ + 'class' => '\Drupal\redis\Cache\PhpRedis', + 'factory' => ['@cache.backend.redis', 'get'], + 'arguments' => ['container'], + ], + 'cache_tags_provider.container' => [ + 'class' => 'Drupal\redis\Cache\RedisCacheTagsChecksum', + 'arguments' => ['@redis.factory'], + ], + 'serialization.phpserialize' => [ + 'class' => 'Drupal\Component\Serialization\PhpSerialize', + ], + ], + ]; +} + +if ($platformsh->inRuntime()) { + // Configure private and temporary file paths. + if (!isset($settings['file_private_path'])) { + $settings['file_private_path'] = $platformsh->appDir . '/private'; + } + if (!isset($settings['file_temp_path'])) { + $settings['file_temp_path'] = $platformsh->appDir . '/tmp'; + } + + // Configure the default PhpStorage and Twig template cache directories. + if (!isset($settings['php_storage']['default'])) { + $settings['php_storage']['default']['directory'] = $settings['file_private_path']; + } + if (!isset($settings['php_storage']['twig'])) { + $settings['php_storage']['twig']['directory'] = $settings['file_private_path']; + } + + // Set the project-specific entropy value, used for generating one-time + // keys and such. + $settings['hash_salt'] = $settings['hash_salt'] ?? $platformsh->projectEntropy; + + // Set the deployment identifier, which is used by some Drupal cache systems. + $settings['deployment_identifier'] = $settings['deployment_identifier'] ?? $platformsh->treeId; +} + +// The 'trusted_hosts_pattern' setting allows an admin to restrict the Host header values +// that are considered trusted. If an attacker sends a request with a custom-crafted Host +// header then it can be an injection vector, depending on how the Host header is used. +// However, Platform.sh already replaces the Host header with the route that was used to reach +// Platform.sh, so it is guaranteed to be safe. The following line explicitly allows all +// Host headers, as the only possible Host header is already guaranteed safe. +$settings['trusted_host_patterns'] = ['.*']; + +// Import variables prefixed with 'd8settings:' into $settings +// and 'd8config:' into $config. +foreach ($platformsh->variables() as $name => $value) { + $parts = explode(':', $name); + list($prefix, $key) = array_pad($parts, 3, null); + switch ($prefix) { + // Variables that begin with `d8settings` or `drupal` get mapped + // to the $settings array verbatim, even if the value is an array. + // For example, a variable named d8settings:example-setting' with + // value 'foo' becomes $settings['example-setting'] = 'foo'; + case 'd8settings': + case 'drupal': + $settings[$key] = $value; + break; + // Variables that begin with `d8config` get mapped to the $config + // array. Deeply nested variable names, with colon delimiters, + // get mapped to deeply nested array elements. Array values + // get added to the end just like a scalar. Variables without + // both a config object name and property are skipped. + // Example: Variable `d8config:conf_file:prop` with value `foo` becomes + // $config['conf_file']['prop'] = 'foo'; + // Example: Variable `d8config:conf_file:prop:subprop` with value `foo` becomes + // $config['conf_file']['prop']['subprop'] = 'foo'; + // Example: Variable `d8config:conf_file:prop:subprop` with value ['foo' => 'bar'] becomes + // $config['conf_file']['prop']['subprop']['foo'] = 'bar'; + // Example: Variable `d8config:prop` is ignored. + case 'd8config': + if (count($parts) > 2) { + $temp = &$config[$key]; + foreach (array_slice($parts, 2) as $n) { + $prev = &$temp; + $temp = &$temp[$n]; + } + $prev[$n] = $value; + } + break; + } +} + +if (!empty($_ENV['PLATFORM_BRANCH'])) { + switch ($_ENV['PLATFORM_BRANCH']) { + case 'production': + $config['config_split.config_split.live']['status'] = TRUE; + break; + } +} diff --git a/web/themes/custom/opdavies/.nvmrc b/web/themes/custom/opdavies/.nvmrc new file mode 100644 index 0000000..a1f8f33 --- /dev/null +++ b/web/themes/custom/opdavies/.nvmrc @@ -0,0 +1 @@ +v12.20.1 diff --git a/web/themes/custom/opdavies/tailwind.config.js b/web/themes/custom/opdavies/tailwind.config.js index 3392c03..3e7d35a 100644 --- a/web/themes/custom/opdavies/tailwind.config.js +++ b/web/themes/custom/opdavies/tailwind.config.js @@ -11,9 +11,9 @@ module.exports = { purge: { content: [ '../../../../config/**/*.yml', - 'body-field-values.txt', 'opdavies.theme', - 'templates/**/*.twig' + 'templates/**/*.twig', + '/tmp/body-field-values.txt' ], options: { safelist: [