From 62b1b7dfa1982ea7d9729fb5bd11d1e5221b2b58 Mon Sep 17 00:00:00 2001 From: Dan Grebb Date: Fri, 22 Dec 2023 22:51:50 -0500 Subject: [PATCH 1/5] wip(back): removes legacy hero fields --- ...uration_content_types##api##post.post.json | 56 +++---------------- .../api/post/content-types/post/schema.json | 6 -- 2 files changed, 9 insertions(+), 53 deletions(-) diff --git a/back/config/sync/core-store.plugin_content_manager_configuration_content_types##api##post.post.json b/back/config/sync/core-store.plugin_content_manager_configuration_content_types##api##post.post.json index 5646fcd6b..806c98a8c 100644 --- a/back/config/sync/core-store.plugin_content_manager_configuration_content_types##api##post.post.json +++ b/back/config/sync/core-store.plugin_content_manager_configuration_content_types##api##post.post.json @@ -90,34 +90,6 @@ "sortable": true } }, - "heroAuthor": { - "edit": { - "label": "Hero Attribution", - "description": "", - "placeholder": "", - "visible": true, - "editable": true - }, - "list": { - "label": "heroAuthor", - "searchable": true, - "sortable": true - } - }, - "heroAuthorLink": { - "edit": { - "label": "Hero Attribution Link", - "description": "", - "placeholder": "", - "visible": true, - "editable": true - }, - "list": { - "label": "heroAuthorLink", - "searchable": true, - "sortable": true - } - }, "content": { "edit": { "label": "Content", @@ -250,6 +222,15 @@ } }, "layouts": { + "list": [ + "title", + "categories", + "related", + "hero", + "createdAt", + "updatedAt", + "slug" + ], "edit": [ [ { @@ -297,31 +278,12 @@ "size": 12 } ], - [ - { - "name": "heroAuthor", - "size": 4 - }, - { - "name": "heroAuthorLink", - "size": 4 - } - ], [ { "name": "seo", "size": 12 } ] - ], - "list": [ - "title", - "categories", - "related", - "hero", - "createdAt", - "updatedAt", - "slug" ] } }, diff --git a/back/src/api/post/content-types/post/schema.json b/back/src/api/post/content-types/post/schema.json index a9424a509..852365bfd 100644 --- a/back/src/api/post/content-types/post/schema.json +++ b/back/src/api/post/content-types/post/schema.json @@ -47,12 +47,6 @@ "right bottom" ] }, - "heroAuthor": { - "type": "string" - }, - "heroAuthorLink": { - "type": "string" - }, "content": { "type": "dynamiczone", "components": [ From b6ae648d27622fe45232a7d593c3b345afa3eaf8 Mon Sep 17 00:00:00 2001 From: Dan Grebb Date: Fri, 22 Dec 2023 23:44:18 -0500 Subject: [PATCH 2/5] feat(terraform): redirects naked domain to www (#1093) Closes: #1093 --- _tf/modules/cdn/cdn.tf | 31 +++++++++-- _tf/modules/cdn/inputs.tf | 1 + _tf/modules/cdn/ref/naked-redirect.js | 77 ++++++++++++++++++++++++++ _tf/modules/network/cdn-dns/cdn-dns.tf | 56 +------------------ _tf/modules/network/inputs.tf | 1 + _tf/prd/main.tf | 4 ++ _tf/stg/main.tf | 4 ++ 7 files changed, 116 insertions(+), 58 deletions(-) create mode 100644 _tf/modules/cdn/ref/naked-redirect.js diff --git a/_tf/modules/cdn/cdn.tf b/_tf/modules/cdn/cdn.tf index 0f5dcd66b..a89df86a7 100644 --- a/_tf/modules/cdn/cdn.tf +++ b/_tf/modules/cdn/cdn.tf @@ -13,12 +13,22 @@ resource "aws_cloudfront_origin_access_identity" "this" { resource "aws_cloudfront_function" "subdir" { name = "subdir-index-${var.dashed_domain}" - runtime = "cloudfront-js-1.0" + runtime = "cloudfront-js-2.0" comment = "Redirect subdirectory root to index.html" publish = true code = file("${path.module}/ref/subdir-index.js") } +resource "aws_cloudfront_function" "redirect" { + count = var.redirect ? 1 : 0 + name = "naked-redirect-${var.dashed_domain}" + runtime = "cloudfront-js-2.0" + comment = "Redirect naked domain to www" + publish = true + code = file("${path.module}/ref/naked-redirect.js") +} + + resource "aws_cloudfront_distribution" "this" { comment = var.domain price_class = "PriceClass_100" @@ -70,9 +80,22 @@ resource "aws_cloudfront_distribution" "this" { ] } - function_association { - event_type = "viewer-request" - function_arn = aws_cloudfront_function.subdir.arn + # Replaced by naked-redirect below, when redirect is true + dynamic "function_association" { + for_each = var.redirect ? [] : [1] + content { + event_type = "viewer-request" + function_arn = aws_cloudfront_function.subdir.arn + } + } + + # Test this on STG by first setting redirect = true on `www_cdn` in main.tf + dynamic "function_association" { + for_each = var.redirect ? [1] : [] + content { + event_type = "viewer-request" + function_arn = aws_cloudfront_function.redirect[0].arn + } } compress = true diff --git a/_tf/modules/cdn/inputs.tf b/_tf/modules/cdn/inputs.tf index 8f691f353..a9ffef672 100644 --- a/_tf/modules/cdn/inputs.tf +++ b/_tf/modules/cdn/inputs.tf @@ -4,3 +4,4 @@ variable "bucket" {} variable "log_enabled" {} variable "log_bucket" {} variable "cert" {} +variable "redirect" {} diff --git a/_tf/modules/cdn/ref/naked-redirect.js b/_tf/modules/cdn/ref/naked-redirect.js new file mode 100644 index 000000000..64fb31c4c --- /dev/null +++ b/_tf/modules/cdn/ref/naked-redirect.js @@ -0,0 +1,77 @@ +/** + * @description: Handler entry point. + * - Note AWS CloudFront Functions use a modified ECMAScript 5.1 compatible runtime and NOT NodeJS. + * - Use var, not const or let + * - Use string concatenation and not template literals + * - Beware that the CloudFront Functions Console editor and test environment do NOT mimic CloudFront 100% + * @date 2022-01-26 + * @param {object} event: A CloudFront Function event (expecting a Viewer Request event) + * @return {object}: A CloudFront response or request object (depends whether conditions allow pass through or 301 redirect) + */ +function handler(event) { + var request = event.request; + var queryString = queryStringObjectToString(request.querystring); + var uri = request.uri; + + // Copy request.headers since it is read-only and we want to return a modified set of headers + var headers = JSON.parse(JSON.stringify(request.headers)); + var host = headers.host.value; + + // Check to see if we have a properly formed or naked domain request + if (host.startsWith("www.")) { + // All good, nothing to change, pass on the request as is + + // Check whether the URI is missing a file name. + if (uri.endsWith("/")) { + request.uri += "index.html"; + } + // Check whether the URI is missing a file extension. + else if (!uri.includes(".")) { + request.uri += "/index.html"; + } + + return request; + } else { + // Prefix the host with the missing www. + host = "www." + host; + // Construct the url with assumed/forced https://www. prefix plus, path and any query string parameters + var url = "https://" + host + uri + queryString; + // Append the new 301 location header + headers.location = { value: url }; + // Remove the original host header to avoid a circular reference of never ending redirects + delete headers.host; + + // Return a CloudFront specific response object that includes original path, query string, (most) headers and cookies + return { + statusCode: 301, + statusDescription: "Moved Permanently", + headers, + cookies: request.cookies, + }; + } +} + +/** + * @description: Converts an event.request.querystring object back to a query string + * @date 2022-01-26 + * @param {object} queryStringObject: Query string object as provided by event.request + * @return {string}: A normalised query string in the form ?key1=valn&key2=val2... + */ +function queryStringObjectToString(queryStringObject) { + // Convert the query string object to an array of entries and reduce to a single string + return ( + Object.entries(queryStringObject) + .reduce((p, q) => { + if (!q[1].multiValue) { + // Process a single key/value property + return (p += q[0] + "=" + q[1].value + "&"); + } else { + // Process multiValue properties. E.g arrays + return (p += + q[1].multiValue.map((v) => q[0] + "=" + v.value).join("&") + "&"); + } + }, "?") + // Remove the trailing ampersand + .slice(0, -1) + ); +} diff --git a/_tf/modules/network/cdn-dns/cdn-dns.tf b/_tf/modules/network/cdn-dns/cdn-dns.tf index 55c70b8fe..4faeb6f15 100644 --- a/_tf/modules/network/cdn-dns/cdn-dns.tf +++ b/_tf/modules/network/cdn-dns/cdn-dns.tf @@ -32,7 +32,7 @@ resource "aws_route53_record" "this" { } resource "aws_route53_record" "wildcard_validation" { - provider = aws.acm_provider + provider = aws.acm_provider for_each = { for dvo in aws_acm_certificate.wildcard.domain_validation_options : dvo.domain_name => { @@ -53,60 +53,8 @@ resource "aws_route53_record" "wildcard_validation" { } resource "aws_acm_certificate_validation" "wildcard" { - provider = aws.acm_provider + provider = aws.acm_provider certificate_arn = aws_acm_certificate.wildcard.arn validation_record_fqdns = [for record in aws_route53_record.wildcard_validation : record.fqdn] } - - -# resource "aws_route53_record" "this" { -# allow_overwrite = true -# name = var.domain -# type = "A" -# zone_id = var.zone.zone_id -# alias { -# name = var.distribution.domain_name -# zone_id = var.distribution.hosted_zone_id -# evaluate_target_health = false -# } -# } - -# resource "aws_acm_certificate" "this" { -# # CloudFront Certs MUST be in us-east-1 -# provider = aws.acm_provider -# domain_name = var.domain -# validation_method = "DNS" - -# lifecycle { -# create_before_destroy = true -# } - -# tags = { -# Name = var.domain -# } -# } - -# resource "aws_route53_record" "validation" { -# for_each = { -# for dvo in aws_acm_certificate.this.domain_validation_options : dvo.domain_name => { -# name = dvo.resource_record_name -# record = dvo.resource_record_value -# type = dvo.resource_record_type -# } -# } - -# allow_overwrite = true -# name = each.value.name -# records = [each.value.record] -# ttl = 60 -# type = each.value.type -# zone_id = var.zone.zone_id -# } - -# resource "aws_acm_certificate_validation" "this" { -# provider = aws.acm_provider -# certificate_arn = aws_acm_certificate.this.arn - -# validation_record_fqdns = [for record in aws_route53_record.validation : record.fqdn] -# } diff --git a/_tf/modules/network/inputs.tf b/_tf/modules/network/inputs.tf index ef4196550..47b3e41ac 100644 --- a/_tf/modules/network/inputs.tf +++ b/_tf/modules/network/inputs.tf @@ -13,3 +13,4 @@ variable "www_cdn" {} variable "uploads_cdn" {} variable "www_record_overwrite" {} variable "reports_cdn" {} +variable "redirect" {} diff --git a/_tf/prd/main.tf b/_tf/prd/main.tf index db7dd76d8..2c8412730 100644 --- a/_tf/prd/main.tf +++ b/_tf/prd/main.tf @@ -14,6 +14,7 @@ module "www_cdn" { log_enabled = true log_bucket = module.www_cdn_bucket.log_bucket cert = module.network.wildcard_cert + redirect = true } module "uploads_cdn" { @@ -24,6 +25,7 @@ module "uploads_cdn" { log_enabled = true log_bucket = module.uploads_cdn_bucket.log_bucket cert = module.network.uploads_cert + redirect = false } module "containers" { @@ -71,6 +73,7 @@ module "network" { uploads_cdn = module.uploads_cdn.cf_distribution reports_cdn = module.reports_cdn.cf_distribution www_record_overwrite = true + redirect = false } module "scaling" { @@ -128,6 +131,7 @@ module "reports_cdn" { log_enabled = false log_bucket = false cert = module.network.reports_cert + redirect = false } module "reports_bucket" { diff --git a/_tf/stg/main.tf b/_tf/stg/main.tf index a7d1809a7..2a06c5078 100644 --- a/_tf/stg/main.tf +++ b/_tf/stg/main.tf @@ -20,6 +20,7 @@ module "www_cdn" { log_enabled = true log_bucket = module.www_cdn_bucket.log_bucket cert = module.network.wildcard_cert + redirect = false } module "uploads_cdn" { @@ -30,6 +31,7 @@ module "uploads_cdn" { log_enabled = true log_bucket = module.uploads_cdn_bucket.log_bucket cert = module.network.uploads_cert + redirect = false } module "containers" { @@ -77,6 +79,7 @@ module "network" { uploads_cdn = module.uploads_cdn.cf_distribution reports_cdn = module.reports_cdn.cf_distribution www_record_overwrite = true + redirect = false } module "scaling" { @@ -135,6 +138,7 @@ module "reports_cdn" { log_enabled = false log_bucket = false cert = module.network.reports_cert + redirect = false } module "reports_bucket" { From 18646264227e84de4ddf503878d0fc8b87689823 Mon Sep 17 00:00:00 2001 From: Dan Grebb Date: Sat, 23 Dec 2023 00:29:35 -0500 Subject: [PATCH 3/5] feat(front): adds event to animated image play actions (#1101) Closes: #1101 --- front/src/lib/_utils/uiHelpers.js | 22 ++++++++++++++----- .../components/content/AnimatedImage.svelte | 22 +++++++++++++++---- front/src/lib/components/posts/Post.svelte | 1 + 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/front/src/lib/_utils/uiHelpers.js b/front/src/lib/_utils/uiHelpers.js index b5319fb8e..b45729654 100644 --- a/front/src/lib/_utils/uiHelpers.js +++ b/front/src/lib/_utils/uiHelpers.js @@ -35,27 +35,39 @@ export const themeToggleClick = (theme) => { /** * Track a click on the code copy button. * @param {string} pageTitle - The title of the page containing the code. - * @param {string} pageSlug - The slug of the page containing the code. + * @param {string} page - The slug of the page containing the code. * @param {string} [codeTitle='Untitled'] - The title of the code being copied. * @param {string} componentInstanceID - The unique identifier of the code component instance. */ export const codeCopyClick = ( pageTitle, - pageSlug, + page, codeTitle = 'Untitled', componentInstanceID ) => { - trackPlausible('Code Copy', { + trackPlausible('Copied Code', { pageTitle, - pageSlug, + page, codeTitle, - codeIdentifier: `code_copy__${pageSlug.replace( + codeIdentifier: `code_copy__${page.replace( /-/g, '_' )}__${componentInstanceID}`, }); }; +/** + * Track a click on the code copy button. + * @param {string} altText - The title of the page containing the code. + * @param {string} page - The slug of the page containing the code. + */ +export const animatedImagePlay = (altText, page) => { + trackPlausible('Played Animated Image', { + altText, + page, + }); +}; + /** * Helper function to track Plausible events. * @param {string} eventName - The name of the Plausible event to track. diff --git a/front/src/lib/components/content/AnimatedImage.svelte b/front/src/lib/components/content/AnimatedImage.svelte index 2dfcd7958..ab12a0d4b 100644 --- a/front/src/lib/components/content/AnimatedImage.svelte +++ b/front/src/lib/components/content/AnimatedImage.svelte @@ -1,6 +1,13 @@
@@ -13,8 +20,15 @@ alt="Still frame{sAlt === null ? '' : `: ${sAlt}`}" loading="lazy" /> -
- +
+
diff --git a/front/src/lib/components/posts/Post.svelte b/front/src/lib/components/posts/Post.svelte index 647a5d897..0e0c9ab0b 100644 --- a/front/src/lib/components/posts/Post.svelte +++ b/front/src/lib/components/posts/Post.svelte @@ -171,6 +171,7 @@ {still} {sAlt} {figcaption} + {slug} /> {/if} {#if c.__component === 'posts.columns'} From df0a02da1e38927cdd7d755918a97c8756c80d94 Mon Sep 17 00:00:00 2001 From: Dan Grebb Date: Sat, 23 Dec 2023 01:18:08 -0500 Subject: [PATCH 4/5] chore(release): prepare for 3.12.0 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a2851476..a7e8af6f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. +## [3.12.0] - 2023-12-23 + +### 💡 Features + +- ***(front)*** Adds event to animated image play actions (#1101) +- ***(terraform)*** Redirects naked domain to www (#1093) + ## [3.11.2] - 2023-12-22 ### ✅ Testing From 9643e80783c7a5ba4983d4d5067b8605649c46a8 Mon Sep 17 00:00:00 2001 From: Dan Grebb Date: Sat, 23 Dec 2023 01:18:22 -0500 Subject: [PATCH 5/5] =?UTF-8?q?release=203.11.2=20=E2=86=92=203.12.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cz.json | 2 +- back/package-lock.json | 4 ++-- back/package.json | 2 +- front/package-lock.json | 4 ++-- front/package.json | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.cz.json b/.cz.json index 9d5b8c0c5..25ff9eb34 100644 --- a/.cz.json +++ b/.cz.json @@ -1,7 +1,7 @@ { "commitizen": { "name": "cz_customize", - "version": "3.11.2", + "version": "3.12.0", "gpg_sign": true, "tag_format": "$major.$minor.$patch$prerelease", "version_type": "semver", diff --git a/back/package-lock.json b/back/package-lock.json index 04499401c..2db583382 100644 --- a/back/package-lock.json +++ b/back/package-lock.json @@ -1,12 +1,12 @@ { "name": "cms.dgrebb.com", - "version": "3.11.2", + "version": "3.12.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cms.dgrebb.com", - "version": "3.11.2", + "version": "3.12.0", "license": "MIT", "dependencies": { "@strapi/plugin-i18n": "4.16.0", diff --git a/back/package.json b/back/package.json index 16fc483f5..78e214ce2 100644 --- a/back/package.json +++ b/back/package.json @@ -1,6 +1,6 @@ { "name": "cms.dgrebb.com", - "version": "3.11.2", + "version": "3.12.0", "private": true, "description": "cms.dgrebb.com", "license": "MIT", diff --git a/front/package-lock.json b/front/package-lock.json index 793861f3f..11fb57b16 100644 --- a/front/package-lock.json +++ b/front/package-lock.json @@ -1,12 +1,12 @@ { "name": "dgrebb.com", - "version": "3.11.2", + "version": "3.12.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "dgrebb.com", - "version": "3.11.2", + "version": "3.12.0", "hasInstallScript": true, "devDependencies": { "@accuser/svelte-plausible-analytics": "dgrebb/svelte-plausible-analytics#downstream/feature/support-custom-pageview-properties", diff --git a/front/package.json b/front/package.json index a551f6da8..5fe934368 100644 --- a/front/package.json +++ b/front/package.json @@ -1,6 +1,6 @@ { "name": "dgrebb.com", - "version": "3.11.2", + "version": "3.12.0", "private": true, "scripts": { "check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json",