From ac952eed34713f1a0208fcf6f95610bb914f1b56 Mon Sep 17 00:00:00 2001 From: tuck1s Date: Thu, 23 Dec 2021 14:21:02 +0000 Subject: [PATCH 1/7] FE1595: Fix intra-document heading links --- .vscode/launch.json | 10 +- .../tech-resources/deep-links-self-serve.md | 123 +++++++++--------- ...-https-engagement-tracking-on-sparkpost.md | 1 + .../using-proxy-https-tracking-domain.md | 21 +-- migration-tools/fix-md-heading-links.py | 73 +++++++++++ 5 files changed, 156 insertions(+), 72 deletions(-) create mode 100755 migration-tools/fix-md-heading-links.py diff --git a/.vscode/launch.json b/.vscode/launch.json index ffbad05fb..f1f0acccf 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -24,6 +24,14 @@ "uriFormat": "%s", "action": "debugWithChrome" } - } + }, + { + "name": "Python: migration tool", + "type":"python", + "request":"launch", + "program":"${file}", + "console":"integratedTerminal", + "args": ["migration-tools/test.md"], + }, ] } diff --git a/content/docs/tech-resources/deep-links-self-serve.md b/content/docs/tech-resources/deep-links-self-serve.md index eb1c6a074..05d171730 100644 --- a/content/docs/tech-resources/deep-links-self-serve.md +++ b/content/docs/tech-resources/deep-links-self-serve.md @@ -1,5 +1,5 @@ --- -lastUpdated: "02/24/2021" +lastUpdated: "12/23/2021" title: "Using Mobile Universal and App Links with SparkPost" description: "A guide to including iOS universal links and Android App Links in your SparkPost-delivered email" --- @@ -18,31 +18,31 @@ When correctly configured, a deep link takes your user directly from the email t ## Setup requirements - Known URL path(s) that you want to deep link to your application. - - When using SparkPost Click Tracking, you choose the Tracking Domain and the custom link sub-path, explained [here](#tracking). It's best to choose a subdomain (e.g. `track.example.com`), so that subdomain can be redirected, while your website uses your organizational domain. + - When using SparkPost Click Tracking, you choose the Tracking Domain and the custom link sub-path, explained [here](#deep-links-and-click-tracking). It's best to choose a subdomain (e.g. `track.example.com`), so that subdomain can be redirected, while your website uses your organizational domain. -- Deep linking spec files hosted on your website or CDN, in the correct location for the devices to find. The spec file declares the identity of your app, and which URL paths lead to your app - described [here](#spec-file). The spec files must be accessible via HTTPS. +- Deep linking spec files hosted on your website or CDN, in the correct location for the devices to find. The spec file declares the identity of your app, and which URL paths lead to your app - described [here](#deep-linking-spec-files). The spec files must be accessible via HTTPS. -- A mobile app that is registered to handle incoming deep link requests - see [example code](#app-examples). +- A mobile app that is registered to handle incoming deep link requests - see [example code](#example-application-code). -The deep link will operate only when all of these match correctly. When you're ready, check your setup against the [summary of setup steps](#summary). +The deep link will operate only when all of these match correctly. When you're ready, check your setup against the [summary of setup steps](#summary-of-setup-steps). -## Writing your mobile app +## Writing your mobile app The following developer documentation explains the deep linking mechanisms in detail. - [Apple's Universal Links](https://developer.apple.com/library/content/documentation/General/Conceptual/AppSearch/UniversalLinks.html) - [Android App Links](https://developer.android.com/training/app-links/index.html) -## Deep linking spec files +## Deep linking spec files -The spec files must be published on your domain(s) and accessible via HTTPS. They may be hosted on a regular web server, or via a CDN - examples [here](#hosting). +The spec files must be published on your domain(s) and accessible via HTTPS. They may be hosted on a regular web server, or via a CDN - examples [here](#hosting-the-spec-files). - For iOS devices, the file is named `apple-app-site-association` - For Android devices, the file is named `assetlinks.json` These files should be placed on your website in the directory `.well-known`. -### iOS: example `apple-app-site-association` +### iOS: example `apple-app-site-association` ```javascript { @@ -70,9 +70,9 @@ Your app needs access to the [Apple "associated domains" entitlement](https://de ![](media/deep-links-self-serve/deep-links-apple-xcode-assoc-domains.png) -Configure the `paths` section to match the links in your email HTML content, depending on your chosen SparkPost click tracking setup (explained [here](#tracking)). +Configure the `paths` section to match the links in your email HTML content, depending on your chosen SparkPost click tracking setup (explained [here](#deep-links-and-click-tracking)). -### Android: example `assetlinks.json` +### Android: example `assetlinks.json` ```javascript [{ @@ -107,7 +107,7 @@ The [App Links Assistant](https://developer.android.com/studio/write/app-link-in 1. Add logic to handle the intent - This works for Java apps but not currently for Kotlin - see [here](#android) for a Kotlin example. + This works for Java apps but not currently for Kotlin - see [here](#forwarding-clicks-from-android-to-sparkpost) for a Kotlin example. 1. Associate website @@ -127,20 +127,20 @@ The [App Links Assistant](https://developer.android.com/studio/write/app-link-in 1. Deploy your app. - On first open, by default, your recipients will be prompted to select whether to select your app. Android remembers the user's preference. + On first open, by default, your recipients will be prompted to select whether to select your app. Android remembers the user's preference. ![Android App first open](media/deep-links-self-serve/deep-links-android-first-time-open.png) - 1. In `AndroidManifest.xml`, you can set your domain `intent-filter` to `autoVerify` to favor opening your app instead of asking the user - see [here](https://developer.android.com/training/app-links/verify-site-associations). + 1. In `AndroidManifest.xml`, you can set your domain `intent-filter` to `autoVerify` to favor opening your app instead of asking the user - see [here](https://developer.android.com/training/app-links/verify-site-associations). ```xml ``` - This requires your `assetlinks.json` file to be hosted on your specific tracking domain. This is explained further in the [hosting](#hosting) and [troubleshooting](#testing-auto-verify) sections. + This requires your `assetlinks.json` file to be hosted on your specific tracking domain. This is explained further in the [hosting](#hosting) and [troubleshooting](#android-testing-auto-verify) sections. --- -## Deep links and click tracking +## Deep links and click tracking Setting up a [custom tracking domain](./enabling-multiple-custom-tracking-domains) is useful for branding and email reputation. It is required for click tracking of deep links in your HTML email. @@ -226,10 +226,10 @@ http://www.example.com[[data-msys-sublink="open-in-app"]] If a custom sub-path is not used, the spec files can be configured to open on a wildcard path. -Examples for iOS and Android are shown [here](#app-examples). +Examples for iOS and Android are shown [here](#example-application-code). --- -## Summary of setup steps +## Summary of setup steps 1. Configure your CDN or reverse proxy to host your custom tracking domain. 1. Configure and verify a custom tracking domain on your SparkPost account. @@ -246,12 +246,12 @@ Examples for iOS and Android are shown [here](#app-examples). 1. Check the link launches your app on mobile devices. *To enable SparkPost to track deep links:* -1. Have your mobile app code make an HTTP GET request to the SparkPost click tracking service when it handles the incoming click event. Details and sample code for this [below](#app-examples). +1. Have your mobile app code make an HTTP GET request to the SparkPost click tracking service when it handles the incoming click event. Details and sample code for this [below](#example-application-code). 1. Have your app take action based on the original URL which SparkPost returns in its "3xx redirect" HTTP response. --- -## Example application code +## Example application code ## iOS - Swift - forwarding clicks to SparkPost @@ -287,7 +287,7 @@ This simple code gets the `Location` header and also follows the redirect to fet In SparkPost event reporting, the attribute `user_agent` carries information on app name and OS version, for example `"testlinks/1 CFNetwork/1197 Darwin/20.0.0"`. This enables you to use SparkPost analytics to find out which links are being opened via your app. -## Forwarding Clicks From Android To SparkPost +## Forwarding Clicks From Android To SparkPost When an Android email client recognizes that an app link has been clicked based on your app `AndroidManifest.xml`, it sends an `intent` which triggers the registered activity in your app. Your app can then make the HTTP(S) request, to register the "click" event in SparkPost and retrieve the original tracked URL from the message. @@ -396,7 +396,7 @@ In SparkPost event reporting, the attribute `user_agent` carries information on --- -## Hosting the spec files +## Hosting the spec files You can use a CDN or an ordinary web-server to host your spec files. Ensure you have a valid certificate for your domain, as devices need to fetch these files using HTTPS. @@ -408,14 +408,14 @@ Step-by-step instructions follow, for * [AWS CloudFront](#aws-cloudfront) * [CloudFlare](#cloudflare) * [Fastly](#fastly) -* [Google Cloud](#google-cloud) -* [Microsoft Azure](#azure) -* [Branch](#platforms) -* [AppsFlyer](#platforms) +* [Google Cloud](#google-cloud-platform) +* [Microsoft Azure](#microsoft-azure) +* [Branch](#alternative-setup-with-deep-linking-platforms) +* [AppsFlyer](#alternative-setup-with-deep-linking-platforms) If you are using a deep linking platform such as [Branch](https://branch.io/) or [AppsFlyer](https://www.appsflyer.com/), these platforms automate the spec file creation for you. -### Apache +### Apache 1. Find the directory used by your web server, known as the web root. The default is `/var/www/html`, but yours may vary. You can find this by locating the `DocumentRoot` setting in your `.conf` files. @@ -435,7 +435,7 @@ Click the padlock symbol and check the certificate is valid and as expected. Rep The above simple instructions allow deep linking to work via your website's main `/.well-known` URL. -To get Android to [auto-verify](#auto-verify) your app's domains (skipping the user ["Ask" step](#android-ask)), you need to serve spec files from your *specific* tracking domains, *while also forwarding* opens and clicks to SparkPost on that domain. Follow the steps in [this article](./using-proxy-https-tracking-domain), then modify the Apache patterns to look like this: +To get Android to [auto-verify](#auto-verify) your app's domains (skipping the user ["Ask" step](#forwarding-clicks-from-android-to-sparkpost-ask)), you need to serve spec files from your *specific* tracking domains, *while also forwarding* opens and clicks to SparkPost on that domain. Follow the steps in [this article](./using-proxy-https-tracking-domain), then modify the Apache patterns to look like this: ```apacheconf @@ -473,11 +473,11 @@ The spec files are made available under URL `https://yourtrackingdomain.example. For completeness, the same routing is configured for HTTP on port 80, although mobile devices will request the spec files via HTTPS. -To check your files are served correctly and Android auto-verify is working - see [troubleshooting tips](#troubleshooting). +To check your files are served correctly and Android auto-verify is working - see [troubleshooting tips](#troubleshooting-tips). --- -### NGINX +### NGINX 1. Follow the steps in [this article](./using-proxy-https-tracking-domain) to set up your secure tracking domain. @@ -485,7 +485,7 @@ To check your files are served correctly and Android auto-verify is working - se 1. Within this, create a directory `.well-known` if it doesn't already exist, and upload/create your spec files here. This will usually require root privilege on your server. -1. Add `location` blocks to your config to declare the spec files on your tracking domain, which will allow Android to [auto-verify](#auto-verify). Here is a complete example, including the engagement-tracking `proxy-pass` block done in step 1. +1. Add `location` blocks to your config to declare the spec files on your tracking domain, which will allow Android to [auto-verify](#in-androidmanifest-xml-you-can-set-your-domain-intent-filter-to-autoverify-to-favor-opening-your-app-instead-of-asking-the-user-see-here-https-developer-android-com-training-app-links-verify-site-associations). Here is a complete example, including the engagement-tracking `proxy-pass` block done in step 1. ``` server { @@ -524,13 +524,13 @@ To check your files are served correctly and Android auto-verify is working - se 1. Check your configuration is valid using `sudo nginx -t`. If no errors are reported, then reload using `sudo nginx -s reload`. -1. Check your files are served correctly and Android auto-verify is working - see [troubleshooting tips](#troubleshooting). +1. Check your files are served correctly and Android auto-verify is working - see [troubleshooting tips](#troubleshooting-tips). --- -### AWS CloudFront +### AWS CloudFront -> As described [here](#spec-file), it's easy to create spec files in your web site. The following steps are needed *only* if you are using a CDN for HTTPS tracking and therefore need to configure the spec files there. +> As described [here](#deep-linking-spec-files), it's easy to create spec files in your web site. The following steps are needed *only* if you are using a CDN for HTTPS tracking and therefore need to configure the spec files there. First set up your secure tracking domain using CloudFront - instructions [here](./enabling-https-engagement-tracking-on-sparkpost/#aws-create). This establishes your tracking domain routing and certificate in AWS. This section describes how to: @@ -625,15 +625,15 @@ With CloudFront we are working with the specific sub-domain used for link tracki 1. Check your S3 bucket configuration is secure using [this tool](https://console.aws.amazon.com/trustedadvisor/home?#/category/security). -1. To check your files are served correctly and Android auto-verify is working, see [troubleshooting tips](#troubleshooting). +1. To check your files are served correctly and Android auto-verify is working, see [troubleshooting tips](#troubleshooting-tips). --- -### CloudFlare +### CloudFlare -> As described [here](#spec-file), it's easy to create spec files in your web site. The following steps are needed *only* if you are using a CDN for HTTPS tracking and therefore need to configure the spec files there. +> As described [here](#deep-linking-spec-files), it's easy to create spec files in your web site. The following steps are needed *only* if you are using a CDN for HTTPS tracking and therefore need to configure the spec files there. -> Unlike AWS CloudFront, you need to already have the spec files (`apple-app-site-association` and `assetlinks.json`) hosted elsewhere, such as on a web server. When your clients request *`yourtracking.domain.com/.well-known/*`*, CloudFlare responds with a `301` "moved permanently" redirect to your files. We have found this can work, but it's not recommended by [Apple](https://developer.apple.com/library/archive/documentation/General/Conceptual/AppSearch/UniversalLinks.html) or [Google](https://developer.android.com/training/app-links/verify-site-associations). It prevents Android [auto-verifying](#auto-verify) your app. +> Unlike AWS CloudFront, you need to already have the spec files (`apple-app-site-association` and `assetlinks.json`) hosted elsewhere, such as on a web server. When your clients request *`yourtracking.domain.com/.well-known/*`*, CloudFlare responds with a `301` "moved permanently" redirect to your files. We have found this can work, but it's not recommended by [Apple](https://developer.apple.com/library/archive/documentation/General/Conceptual/AppSearch/UniversalLinks.html) or [Google](https://developer.android.com/training/app-links/verify-site-associations). It prevents Android [auto-verifying](#in-androidmanifest-xml-you-can-set-your-domain-intent-filter-to-autoverify-to-favor-opening-your-app-instead-of-asking-the-user-see-here-https-developer-android-com-training-app-links-verify-site-associations) your app. 1. In your CloudFlare dashboard, an additional page rule is necessary to serve the spec files. @@ -653,15 +653,15 @@ With CloudFront we are working with the specific sub-domain used for link tracki ![](media/deep-links-self-serve/deep-links-cloudflare-all-page-rules.png) -1. To check your files are served correctly - see [troubleshooting tips](#troubleshooting). +1. To check your files are served correctly - see [troubleshooting tips](#troubleshooting-tips). --- -### Fastly +### Fastly -> As described [here](#spec-file), it's easy to create spec files in your web site. The following steps are needed *only* if you are using a CDN for HTTPS tracking and therefore need to configure the spec files there. +> As described [here](#deep-linking-spec-files), it's easy to create spec files in your web site. The following steps are needed *only* if you are using a CDN for HTTPS tracking and therefore need to configure the spec files there. -> Unlike AWS CloudFront, you need to already have the spec files (`apple-app-site-association` and `assetlinks.json`) hosted elsewhere, such as on a web server. Fastly can serve requests for these files without sending the client a `301` "moved permanently" redirect, so it supports Android [auto-verifying](#auto-verify) your app. +> Unlike AWS CloudFront, you need to already have the spec files (`apple-app-site-association` and `assetlinks.json`) hosted elsewhere, such as on a web server. Fastly can serve requests for these files without sending the client a `301` "moved permanently" redirect, so it supports Android [auto-verifying](#in-androidmanifest-xml-you-can-set-your-domain-intent-filter-to-autoverify-to-favor-opening-your-app-instead-of-asking-the-user-see-here-https-developer-android-com-training-app-links-verify-site-associations) your app. 1. Set up your secure tracking domain - instructions [here](./enabling-https-engagement-tracking-on-sparkpost/#fastly-create). This establishes your tracking domain routing and certificate in Fastly. @@ -693,7 +693,7 @@ With CloudFront we are working with the specific sub-domain used for link tracki 1. Select "Activate" to make your new configuration live. -1. Check your files are served correctly - see [troubleshooting tips](#troubleshooting). +1. Check your files are served correctly - see [troubleshooting tips](#troubleshooting-tips). #### Background info: VCL, Fastly boilerplate and "Fiddle" @@ -719,9 +719,9 @@ Likewise, if you run a request for a tracked link from a test email sent through --- -### Google Cloud Platform +### Google Cloud Platform -Like AWS CloudFront, you can host the [spec files](#spec-file) (`apple-app-site-association` and `assetlinks.json`) directly on [Google Cloud Platform](https://cloud.google.com/) (GCP) as well as handling HTTPS tracking. +Like AWS CloudFront, you can host the [spec files](#deep-linking-spec-files) (`apple-app-site-association` and `assetlinks.json`) directly on [Google Cloud Platform](https://cloud.google.com/) (GCP) as well as handling HTTPS tracking. First, set up your secure tracking domain - instructions [here](./enabling-https-engagement-tracking-on-sparkpost/#gcp-create). This establishes your tracking domain routing via a GCP ["external" HTTPS load-balancer](https://cloud.google.com/load-balancing/docs/https) with a valid certificate for your domain, and a default routing rule to forward all incoming requests to SparkPost. @@ -836,15 +836,15 @@ First, set up your secure tracking domain - instructions [here](./enabling-https Note that GCP generated the Hosts `*` Paths `/*` rule automatically. -1. Check your files are served correctly - see [troubleshooting tips](#troubleshooting). +1. Check your files are served correctly - see [troubleshooting tips](#troubleshooting-tips). --- -### Microsoft Azure +### Microsoft Azure -Like AWS CloudFront, you can host the [spec files](#spec-file) (`apple-app-site-association` and `assetlinks.json`) directly on [Microsoft Azure](https://azure.microsoft.com/) as well as handling HTTPS tracking. +Like AWS CloudFront, you can host the [spec files](#deep-linking-spec-files) (`apple-app-site-association` and `assetlinks.json`) directly on [Microsoft Azure](https://azure.microsoft.com/) as well as handling HTTPS tracking. -First, set up your secure tracking domain - instructions [here](./enabling-https-engagement-tracking-on-sparkpost/#azure-create). This establishes your tracking domain routing via an [Azure Front Door](https://docs.microsoft.com/en-us/azure/frontdoor/front-door-overview) with a valid certificate for your domain, and a default routing rule to forward all incoming requests to SparkPost. +First, set up your secure tracking domain - instructions [here](./enabling-https-engagement-tracking-on-sparkpost/#microsoft-azure-create). This establishes your tracking domain routing via an [Azure Front Door](https://docs.microsoft.com/en-us/azure/frontdoor/front-door-overview) with a valid certificate for your domain, and a default routing rule to forward all incoming requests to SparkPost. The following instructions follow parts of [this tutorial on hosting a static website on Blob Storage](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-static-website-host), serving only the deep linking spec files rather than a full website. @@ -994,7 +994,7 @@ The following instructions follow parts of [this tutorial on hosting a static we * On the Activity Log, you can see the changes propagate. We found that it can take around 5 minutes before the files are served externally. -1. Check your files are served correctly - see [troubleshooting tips](#troubleshooting). +1. Check your files are served correctly - see [troubleshooting tips](#troubleshooting-tips). 1. Optional step: block access to your files via the direct static website URLs, i.e. access only via your custom tracking domain Front Door address. @@ -1023,7 +1023,7 @@ The following instructions follow parts of [this tutorial on hosting a static we --- -## Alternative setup with deep linking platforms +## Alternative setup with deep linking platforms If you are using a deep linking platform such as [Branch](https://branch.io/) or [AppsFlyer](https://www.appsflyer.com/), these platforms automate some of the setup process for you, while also working in a specific way. @@ -1068,7 +1068,7 @@ Clicking the gearwheel shows: ![](media/deep-links-self-serve/deep-links-branch2.png) -The [troubleshooting](#troubleshooting) tips below can also be used. For example, you can check your spec files are present on your Click Tracking Domain, and check your tracked links are resolving through Branch to SparkPost's endpoint. +The [troubleshooting](#troubleshooting-tips) tips below can also be used. For example, you can check your spec files are present on your Click Tracking Domain, and check your tracked links are resolving through Branch to SparkPost's endpoint. ### AppsFlyer @@ -1082,7 +1082,7 @@ AppsFlyer supports [deep links](https://www.appsflyer.com/product/one-link-deep- Complete the steps [here](./enabling-https-engagement-tracking-on-sparkpost/#switch-to-secure) to set your tracking domain in SparkPost to Secure mode and verify, if not verified already. -## Troubleshooting tips +## Troubleshooting tips ### Check your spec files @@ -1100,22 +1100,22 @@ curl https://your-tracking-domain-here/.well-known/assetlinks.json You can view your encoded links using Gmail, by selecting the three dots menu top-right, then "Show Original". Check the domain is as expected, and the `Android: testing auto-verify +### Android: testing auto-verify Getting your app to auto-verify requires the `assetlinks.json` file to be available on your _specific_ tracking domain rather than relying on the organizational domain (main website). -To test auto-verify works for your domain(s), start with a fresh install of your app, as mentioned in [this article](#auto-verify-article), because Android remembers the user's choice. +To test auto-verify works for your domain(s), start with a fresh install of your app, as mentioned in [this article](#article-on-android-deep-links-https-levelup-gitconnected-com-the-wrong-hacked-and-correct-way-of-android-deep-linking-for-redirected-multisite-with-autoverify-5c72fb1f8053-the-wrong-and-right-way-specifically-auto-verify-on-variations-of-your-different-domains), because Android remembers the user's choice. -If you are getting the ["ask" prompt](#android-ask) to choose which application opens the link, you can use the `adb` debugger to investigate the status of your app. If the Status is shown as `ask` then auto-verify is not working as intended. The value `always : 200000000` means it is verified. +If you are getting the ["ask" prompt](#forwarding-clicks-from-android-to-sparkpost-ask) to choose which application opens the link, you can use the `adb` debugger to investigate the status of your app. If the Status is shown as `ask` then auto-verify is not working as intended. The value `always : 200000000` means it is verified. ```bash $ adb reconnect @@ -1130,7 +1130,7 @@ App verification status: Status: always : 200000000 ``` -If your app has more than one associated domain, the status will be "`ask`" if _any_ of them fail to auto-verify. You can use `adb` to check your setup from Android Studio without having to delete/reinstall. For more information on using the `adb` debugger, see [this article](#adb). +If your app has more than one associated domain, the status will be "`ask`" if _any_ of them fail to auto-verify. You can use `adb` to check your setup from Android Studio without having to delete/reinstall. For more information on using the `adb` debugger, see [this article](#article-on-investigating-android-deep-link-problems-with-adb-https-medium-com-mobile-app-development-publication-unrealized-deeplink-bug-on-many-apps-6ac78a557702). > Note: [CloudFlare](#cloudflare) CDN is problematic for Android auto-verify, owing to its use of 301 redirect for files. @@ -1145,7 +1145,8 @@ If your app has more than one associated domain, the status will be "`ask`" if _ 1. NGINX [Location](https://docs.nginx.com/nginx/admin-guide/web-server/web-server/#locations) block 1. [Understanding and Configuring Cloudflare Page Rules](https://support.cloudflare.com/hc/en-us/articles/218411427-Understanding-and-Configuring-Cloudflare-Page-Rules-Page-Rules-Tutorial-) 1. [Android App Links documentation](https://developer.android.com/training/app-links/verify-site-associations) on auto-verify -1. Article on [Android deep links](https://levelup.gitconnected.com/the-wrong-hacked-and-correct-way-of-android-deep-linking-for-redirected-multisite-with-autoverify-5c72fb1f8053) the wrong and right way (specifically, auto-verify on variations of your different domains) -1. Article on [investigating Android deep-link problems with adb](https://medium.com/mobile-app-development-publication/unrealized-deeplink-bug-on-many-apps-6ac78a557702) +1. Article on [Android deep links](https://levelup.gitconnected.com/the-wrong-hacked-and-correct-way-of-android-deep-linking-for-redirected-multisite-with-autoverify-5c72fb1f8053) the wrong and right way (specifically, auto-verify on variations of your different domains) +1. Article on [investigating Android deep-link problems with adb](https://medium.com/mobile-app-development-publication/unrealized-deeplink-bug-on-many-apps-6ac78a557702) 1. Android Studio [App Links Assistant](https://developer.android.com/studio/write/app-link-indexing) tool + diff --git a/content/docs/tech-resources/enabling-https-engagement-tracking-on-sparkpost.md b/content/docs/tech-resources/enabling-https-engagement-tracking-on-sparkpost.md index a7e902cc1..8dc37d77c 100644 --- a/content/docs/tech-resources/enabling-https-engagement-tracking-on-sparkpost.md +++ b/content/docs/tech-resources/enabling-https-engagement-tracking-on-sparkpost.md @@ -138,6 +138,7 @@ _Updated December 2021. Uses a simpler forwarding method without the need for cu Cloudflare does not offer control of cache "time to live" (TTL) on free accounts. This may mask repeat opens/clicks, as described [here](#cache-time-to-live-ttl-settings). If you have a paid account, under Caching, check and set your TTL value. + 1. Follow [these steps](#switch-tracking-domain-to-secure-and-validate) to update and verify your tracking domain. --- diff --git a/content/docs/tech-resources/using-proxy-https-tracking-domain.md b/content/docs/tech-resources/using-proxy-https-tracking-domain.md index 63b3f606e..2591f237f 100644 --- a/content/docs/tech-resources/using-proxy-https-tracking-domain.md +++ b/content/docs/tech-resources/using-proxy-https-tracking-domain.md @@ -25,8 +25,8 @@ This post covers how to configure a SparkPost tracking domain, provision an SSL This example uses a t2.micro Ubuntu instance on Amazon Web Services and a tracking domain of click.nddurant.com that is CNAME'd to the instance public IPv4 DNS. Step-by-step instructions follow, for: -* [nginx](#nginx) -* [Apache](#apache) +* [nginx](#configuring-nginx) +* [Apache](#configuring-apache) ## Migration planning @@ -40,7 +40,7 @@ If you want to end up with your proxy serving the original domain: * You need to consider your certificates (which may be specific to your subdomain, or may use subdomain wild-card) * You need to change your DNS setting on the original tracking domain(s) to point to the proxy, only when your proxy is tested and working. -## Configuring nginx +## Configuring nginx This section uses [nginx](https://www.nginx.com/). It is easy to get installed and configured as a reverse proxy and Let’s Encrypt for SSL certificates has support for it. To install nginx, follow the guidelines for your Linux distribution. @@ -73,7 +73,7 @@ Creating this file in **/etc/nginx/conf.d** and executing a nginx reload will ma sudo nginx -s reload ``` -## Verify tracking domain, send test email +## Verify tracking domain, send test email At this point, if your DNS is pointing to this nginx server, you should be able to verify the tracking domain in SparkPost. Add your desired tracking domain to your SparkPost account, either through the user interface or [API](https://developers.sparkpost.com/api/tracking-domains/). Once verified, you can associate the tracking domain with a [sending domain](https://developers.sparkpost.com/api/tracking-domains/#header-association-to-sending-domains-and-defaults) and manually test the tracking links with cURL commands. The following example is a simple cURL command to send an email through SparkPost with engagement tracking enabled: @@ -149,7 +149,7 @@ After completing this, you will have free SSL certificates installed on your ngi After the certificate is created, you will be asked if you wish to redirect **http** to **https**. It is recommended that you do not redirect, as you may wish to change your tracking domain back to **http** in the future if it becomes necessary. -## Set SparkPost tracking domain to "secure" +## Set SparkPost tracking domain to "secure" Once completed, set your tracking domain to “secure” using the [tracking domains API](https://developers.sparkpost.com/api/tracking-domains/#tracking-domains-put-update-a-tracking-domain). This will make any new emails using your associated tracking domains to use **https** instead of the **http** protocol; instructions [here](enabling-https-engagement-tracking-on-sparkpost.md#switch-to-secure). @@ -247,12 +247,12 @@ This shows: * A GET request from a mail client (in this case via Google Image Proxy), fetching a SparkPost open pixel. The request was forwarded to SparkPost and received a `200` (OK) response. * The second GET request is a link click. The IP address is of the mail client (in this case, Gmail in Safari). Again it's forwarded to SparkPost and received a `302` (Found) response, redirecting the client to the landing page. -Finally, [check your client IP address](#client_ip) and user_agent is reported in SparkPost. +Finally, [check your client IP address](#nginx-and-apache-check-client-ip-address) and user_agent is reported in SparkPost. --- -## Configuring Apache +## Configuring Apache This section describes how to use [Apache](https://httpd.apache.org/) as a reverse proxy for SparkPost HTTPS engagement tracking. @@ -268,7 +268,7 @@ Add the following configuration (putting your own tracking domain into the `Serv ``` -* [Verify](#verify) tracking domain, and send test email. +* [Verify](#verify-tracking-domain-send-test-email) tracking domain, and send test email. * Get SSL certificate. Letsencrypt certificates can be issued using "certbot", which automates the process - see [here](https://certbot.eff.org/all-instructions) for detailed steps on many platforms. @@ -291,7 +291,7 @@ Create an additional port 443 proxy configuration as follows. Set the certifica Ensure your have `https:` in the `ProxyPass` and `ProxyPassReverse` lines. -* [Set SparkPost](#set-sec) tracking domain to "secure" and verify. Continue steps below when done. +* [Set SparkPost](#set-sparkpost-tracking-domain-to-secure) tracking domain to "secure" and verify. Continue steps below when done. * If you are going to use HTTPS tracking _only_, you could remove the initial `_default_:80` configuration block. @@ -326,7 +326,7 @@ This shows: --- -### NGINX and Apache: Check Client IP address +### NGINX and Apache: Check Client IP address Both proxies set the `X-Forwarded-For` header, which enables SparkPost to report the original client IP address. If you look in your SparkPost events, you should see this reported as client `ip_address` and `user_agent`, useful for your analytics. @@ -342,3 +342,4 @@ Both proxies set the `X-Forwarded-For` header, which enables SparkPost to report * Set up engagement tracking with the [SMTP API](https://www.sparkpost.com/docs/tech-resources/smtp-engagement-tracking/) for your SMTP traffic to SparkPost. * If you have a mobile app, and want to enable it to open when a recipient clicks an email link, see [this article](./deep-links-self-serve.md). + diff --git a/migration-tools/fix-md-heading-links.py b/migration-tools/fix-md-heading-links.py new file mode 100755 index 000000000..ebdfc6223 --- /dev/null +++ b/migration-tools/fix-md-heading-links.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 +import argparse, sys, re + +# this is a heuristic based on what we see in output files - not definitive +def markdown_title_name(t): + # Strip leading and trailing spaces, use lowercase + title = t.lower().strip() + # change non-alphanumeric to dash -, unless we already have a dash + for i in range(0, len(title)): + if not title[i].isalnum(): + title = title[0:i] + '-' + title[i+1:] + # replace any repeated dashes + while '--' in title: + title = title.replace('--', '-') + # remove any leading & trailing dashes + title = title.strip('-') + return title + + +class markup_doc: + def __init__(self, f): + self.text = f.readlines() # Store as separate lines, for ease of processing + self.labels = {} + + def scan_labels(self): + for i in range(0, len(self.text)): + line = self.text[i] + find_anchor = r'(.*)' + # re.I= case-insensitive search + anchor = re.search(find_anchor, line, flags=re.I) + if anchor: + # Assume at most one anchor per line. Keep the content before and after. + before = line[0:anchor.start()] + after = line[anchor.end():] + find_name = r'name=\"(.*)\"' + name = re.search(find_name, anchor[0]) + if name: + self.labels[name[1]] = markdown_title_name(after) + # Remove the anchor from the markdown text. Trim any double space that's left + if before.endswith(' ') and after.startswith(' '): + after = after.lstrip() + self.text[i] = before + after + return + + def replace_labels(self): + for i in range(0, len(self.text)): + line = self.text[i] + for k,v in self.labels.items(): + # Find intra-document link references such as (#ref) + find_link_ref = r'\#(' + k + ')' + doc_link = re.search(find_link_ref, line, flags=re.I) + if doc_link: + before = line[0:doc_link.start()] + after = line[doc_link.end():] + self.text[i] = before + '#' + v + after + return + + def as_text(self): + return ''.join(self.text) + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Find and replace type links with inter document heading links') + parser.add_argument('file', type=str, nargs='?', default=None, help='filename to read. If file is absent, reads from the standard input (acts as a filter).') + args = parser.parse_args() + + if args.file: + with open(args.file) as f: + d = markup_doc(f) + else: + d = markup_doc(sys.stdin) + d.scan_labels() + d.replace_labels() + print(d.as_text()) From 84435fad533f72bde62b37528a45ee5830f6420d Mon Sep 17 00:00:00 2001 From: tuck1s Date: Thu, 23 Dec 2021 15:00:24 +0000 Subject: [PATCH 2/7] lastUpdated --- .../docs/tech-resources/using-proxy-https-tracking-domain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/tech-resources/using-proxy-https-tracking-domain.md b/content/docs/tech-resources/using-proxy-https-tracking-domain.md index 2591f237f..a9413449e 100644 --- a/content/docs/tech-resources/using-proxy-https-tracking-domain.md +++ b/content/docs/tech-resources/using-proxy-https-tracking-domain.md @@ -1,5 +1,5 @@ --- -lastUpdated: "04/13/2021" +lastUpdated: "12/23/2021" title: "Using a Reverse Proxy for HTTPS Tracking Domain" description: "SparkPost supports HTTPS engagement tracking for customers via self-service for all SparkPost customers. To enable SSL engagement tracking for a domain, additional configuration for SSL keys is required. This resource outlines the use of a reverse proxy to host SSL certificates" --- From 999ef9ab43c8832bd88a71c525d102e3f42e9ded Mon Sep 17 00:00:00 2001 From: tuck1s Date: Thu, 23 Dec 2021 15:26:02 +0000 Subject: [PATCH 3/7] Revert lastUpdated --- .../docs/tech-resources/using-proxy-https-tracking-domain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/tech-resources/using-proxy-https-tracking-domain.md b/content/docs/tech-resources/using-proxy-https-tracking-domain.md index a9413449e..2591f237f 100644 --- a/content/docs/tech-resources/using-proxy-https-tracking-domain.md +++ b/content/docs/tech-resources/using-proxy-https-tracking-domain.md @@ -1,5 +1,5 @@ --- -lastUpdated: "12/23/2021" +lastUpdated: "04/13/2021" title: "Using a Reverse Proxy for HTTPS Tracking Domain" description: "SparkPost supports HTTPS engagement tracking for customers via self-service for all SparkPost customers. To enable SSL engagement tracking for a domain, additional configuration for SSL keys is required. This resource outlines the use of a reverse proxy to host SSL certificates" --- From e31b0dfed87b92f3a5b40fa8e01829c88c5298d4 Mon Sep 17 00:00:00 2001 From: tuck1s Date: Fri, 24 Dec 2021 16:12:56 +0000 Subject: [PATCH 4/7] Inter-doc link fixes, script testcase,improvements --- .../tech-resources/deep-links-self-serve.md | 20 +++++------ .../using-proxy-https-tracking-domain.md | 4 +-- migration-tools/Pipfile | 12 +++++++ migration-tools/Pipfile.lock | 36 +++++++++++++++++++ migration-tools/fix-md-heading-links.py | 18 ++-------- migration-tools/test.md | 9 +++++ migration-tools/test.sh | 1 + 7 files changed, 72 insertions(+), 28 deletions(-) create mode 100644 migration-tools/Pipfile create mode 100644 migration-tools/Pipfile.lock create mode 100644 migration-tools/test.md create mode 100755 migration-tools/test.sh diff --git a/content/docs/tech-resources/deep-links-self-serve.md b/content/docs/tech-resources/deep-links-self-serve.md index 05d171730..ce92a4342 100644 --- a/content/docs/tech-resources/deep-links-self-serve.md +++ b/content/docs/tech-resources/deep-links-self-serve.md @@ -485,7 +485,7 @@ To check your files are served correctly and Android auto-verify is working - se 1. Within this, create a directory `.well-known` if it doesn't already exist, and upload/create your spec files here. This will usually require root privilege on your server. -1. Add `location` blocks to your config to declare the spec files on your tracking domain, which will allow Android to [auto-verify](#in-androidmanifest-xml-you-can-set-your-domain-intent-filter-to-autoverify-to-favor-opening-your-app-instead-of-asking-the-user-see-here-https-developer-android-com-training-app-links-verify-site-associations). Here is a complete example, including the engagement-tracking `proxy-pass` block done in step 1. +1. Add `location` blocks to your config to declare the spec files on your tracking domain, which will allow Android to [auto-verify](#android-testing-auto-verify). Here is a complete example, including the engagement-tracking `proxy-pass` block done in step 1. ``` server { @@ -532,7 +532,7 @@ To check your files are served correctly and Android auto-verify is working - se > As described [here](#deep-linking-spec-files), it's easy to create spec files in your web site. The following steps are needed *only* if you are using a CDN for HTTPS tracking and therefore need to configure the spec files there. -First set up your secure tracking domain using CloudFront - instructions [here](./enabling-https-engagement-tracking-on-sparkpost/#aws-create). This establishes your tracking domain routing and certificate in AWS. This section describes how to: +First set up your secure tracking domain using CloudFront - instructions [here](./enabling-https-engagement-tracking-on-sparkpost/#step-by-step-guide-with-aws-cloudfront). This establishes your tracking domain routing and certificate in AWS. This section describes how to: * Create an S3 bucket for the spec files; * Set up our CloudFront distribution to selectively serve requests on our tracking domain from the bucket; @@ -633,7 +633,7 @@ With CloudFront we are working with the specific sub-domain used for link tracki > As described [here](#deep-linking-spec-files), it's easy to create spec files in your web site. The following steps are needed *only* if you are using a CDN for HTTPS tracking and therefore need to configure the spec files there. -> Unlike AWS CloudFront, you need to already have the spec files (`apple-app-site-association` and `assetlinks.json`) hosted elsewhere, such as on a web server. When your clients request *`yourtracking.domain.com/.well-known/*`*, CloudFlare responds with a `301` "moved permanently" redirect to your files. We have found this can work, but it's not recommended by [Apple](https://developer.apple.com/library/archive/documentation/General/Conceptual/AppSearch/UniversalLinks.html) or [Google](https://developer.android.com/training/app-links/verify-site-associations). It prevents Android [auto-verifying](#in-androidmanifest-xml-you-can-set-your-domain-intent-filter-to-autoverify-to-favor-opening-your-app-instead-of-asking-the-user-see-here-https-developer-android-com-training-app-links-verify-site-associations) your app. +> Unlike AWS CloudFront, you need to already have the spec files (`apple-app-site-association` and `assetlinks.json`) hosted elsewhere, such as on a web server. When your clients request *`yourtracking.domain.com/.well-known/*`*, CloudFlare responds with a `301` "moved permanently" redirect to your files. We have found this can work, but it's not recommended by [Apple](https://developer.apple.com/library/archive/documentation/General/Conceptual/AppSearch/UniversalLinks.html) or [Google](https://developer.android.com/training/app-links/verify-site-associations). It prevents Android [auto-verifying](#android-testing-auto-verify) your app. 1. In your CloudFlare dashboard, an additional page rule is necessary to serve the spec files. @@ -663,7 +663,7 @@ With CloudFront we are working with the specific sub-domain used for link tracki > Unlike AWS CloudFront, you need to already have the spec files (`apple-app-site-association` and `assetlinks.json`) hosted elsewhere, such as on a web server. Fastly can serve requests for these files without sending the client a `301` "moved permanently" redirect, so it supports Android [auto-verifying](#in-androidmanifest-xml-you-can-set-your-domain-intent-filter-to-autoverify-to-favor-opening-your-app-instead-of-asking-the-user-see-here-https-developer-android-com-training-app-links-verify-site-associations) your app. -1. Set up your secure tracking domain - instructions [here](./enabling-https-engagement-tracking-on-sparkpost/#fastly-create). This establishes your tracking domain routing and certificate in Fastly. +1. Set up your secure tracking domain - instructions [here](./enabling-https-engagement-tracking-on-sparkpost/#step-by-step-guide-with-fastly). This establishes your tracking domain routing and certificate in Fastly. 1. "Clone" your current configuration. This gives a draft config to edit. The version number increments, while your previous version continues to be active. @@ -723,7 +723,7 @@ Likewise, if you run a request for a tracked link from a test email sent through Like AWS CloudFront, you can host the [spec files](#deep-linking-spec-files) (`apple-app-site-association` and `assetlinks.json`) directly on [Google Cloud Platform](https://cloud.google.com/) (GCP) as well as handling HTTPS tracking. -First, set up your secure tracking domain - instructions [here](./enabling-https-engagement-tracking-on-sparkpost/#gcp-create). This establishes your tracking domain routing via a GCP ["external" HTTPS load-balancer](https://cloud.google.com/load-balancing/docs/https) with a valid certificate for your domain, and a default routing rule to forward all incoming requests to SparkPost. +First, set up your secure tracking domain - instructions [here](./enabling-https-engagement-tracking-on-sparkpost/#step-by-step-guide-with-google-cloud-platform). This establishes your tracking domain routing via a GCP ["external" HTTPS load-balancer](https://cloud.google.com/load-balancing/docs/https) with a valid certificate for your domain, and a default routing rule to forward all incoming requests to SparkPost. 1. From the top menu, select your existing project. On the main menu, top left, select "Network Services" then "Load balancing". You can pin the "Network Services" menu for easy access later. @@ -844,7 +844,7 @@ First, set up your secure tracking domain - instructions [here](./enabling-https Like AWS CloudFront, you can host the [spec files](#deep-linking-spec-files) (`apple-app-site-association` and `assetlinks.json`) directly on [Microsoft Azure](https://azure.microsoft.com/) as well as handling HTTPS tracking. -First, set up your secure tracking domain - instructions [here](./enabling-https-engagement-tracking-on-sparkpost/#microsoft-azure-create). This establishes your tracking domain routing via an [Azure Front Door](https://docs.microsoft.com/en-us/azure/frontdoor/front-door-overview) with a valid certificate for your domain, and a default routing rule to forward all incoming requests to SparkPost. +First, set up your secure tracking domain - instructions [here](./enabling-https-engagement-tracking-on-sparkpost/#step-by-step-guide-with-microsoft-azure). This establishes your tracking domain routing via an [Azure Front Door](https://docs.microsoft.com/en-us/azure/frontdoor/front-door-overview) with a valid certificate for your domain, and a default routing rule to forward all incoming requests to SparkPost. The following instructions follow parts of [this tutorial on hosting a static website on Blob Storage](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-static-website-host), serving only the deep linking spec files rather than a full website. @@ -1052,11 +1052,11 @@ Here are the steps to get your app running with Branch and SparkPost. Your sourc 1. Follow the Branch [Universal Email Integration Guide](https://help.branch.io/using-branch/docs/universal-email-integration-guide) to set up your Click Tracking Domain(s) in the Branch dashboard. - This example shows the standard SparkPost US endpoint address. Be sure to use the address for your SparkPost account region and type, see [here](./enabling-https-engagement-tracking-on-sparkpost/#endpoints). + This example shows the standard SparkPost US endpoint address. Be sure to use the address for your SparkPost account region and type, see [here](./enabling-https-engagement-tracking-on-sparkpost/#sparkpost-tracking-endpoints). ![](media/deep-links-self-serve/deep-links-branch-sparkpost-endpoint.png) -1. The guide directs you to "Point DNS CNAME to Branch". Once this is done, follow the steps [here](./enabling-https-engagement-tracking-on-sparkpost/#switch-to-secure) to set your tracking domain in SparkPost to Secure mode and verify, if not verified already. +1. The guide directs you to "Point DNS CNAME to Branch". Once this is done, follow the steps [here](./enabling-https-engagement-tracking-on-sparkpost/#switch-tracking-domain-to-secure-and-validate) to set your tracking domain in SparkPost to Secure mode and verify, if not verified already. 1. You can now send email using the Branch-hosted Click Tracking Domain for your links. These should open as usual on a desktop browser, and open your app on mobile devices. @@ -1080,7 +1080,7 @@ AppsFlyer supports [deep links](https://www.appsflyer.com/product/one-link-deep- - For email integration, follow these [step by step instructions](https://support.appsflyer.com/hc/en-us/articles/360014381317) for SparkPost. AppsFlyer supports [Braze+SparkPost](https://support.appsflyer.com/hc/en-us/articles/360001437497-Braze) in the same way. -Complete the steps [here](./enabling-https-engagement-tracking-on-sparkpost/#switch-to-secure) to set your tracking domain in SparkPost to Secure mode and verify, if not verified already. +Complete the steps [here](./enabling-https-engagement-tracking-on-sparkpost/#switch-tracking-domain-to-secure-and-validate) to set your tracking domain in SparkPost to Secure mode and verify, if not verified already. ## Troubleshooting tips @@ -1132,8 +1132,6 @@ App verification status: If your app has more than one associated domain, the status will be "`ask`" if _any_ of them fail to auto-verify. You can use `adb` to check your setup from Android Studio without having to delete/reinstall. For more information on using the `adb` debugger, see [this article](#article-on-investigating-android-deep-link-problems-with-adb-https-medium-com-mobile-app-development-publication-unrealized-deeplink-bug-on-many-apps-6ac78a557702). -> Note: [CloudFlare](#cloudflare) CDN is problematic for Android auto-verify, owing to its use of 301 redirect for files. - ## Further reading 1. [Branch.io](https://blog.branch.io/how-to-setup-universal-links-to-deep-link-on-apple-ios/) article on setting up iOS Universal Links diff --git a/content/docs/tech-resources/using-proxy-https-tracking-domain.md b/content/docs/tech-resources/using-proxy-https-tracking-domain.md index 2591f237f..d414d6cb6 100644 --- a/content/docs/tech-resources/using-proxy-https-tracking-domain.md +++ b/content/docs/tech-resources/using-proxy-https-tracking-domain.md @@ -8,7 +8,7 @@ description: "SparkPost supports HTTPS engagement tracking for customers via sel SparkPost supports secure tracking domains through the use of content delivery networks (CDNs), reverse proxies, or any method where the customer can host the necessary SSL/TLS certificates. It is recommended that our customers use SSL as it provides secure transport for engagement data. It's also necessary to support SparkPost engagement tracking with Google’s AMP for Email. -> Alternative: to configure HTTPS engagement tracking using a CDN, see [this article](./enabling-https-engagement-tracking-on-sparkpost.md). +> Alternative: to configure HTTPS engagement tracking using a CDN, see [this article](./enabling-https-engagement-tracking-on-sparkpost). This post covers how to configure a SparkPost tracking domain, provision an SSL certificate, and be able to use it immediately at SparkPost using a simple reverse proxy. @@ -341,5 +341,5 @@ Both proxies set the `X-Forwarded-For` header, which enables SparkPost to report * Set up engagement tracking with the [SMTP API](https://www.sparkpost.com/docs/tech-resources/smtp-engagement-tracking/) for your SMTP traffic to SparkPost. -* If you have a mobile app, and want to enable it to open when a recipient clicks an email link, see [this article](./deep-links-self-serve.md). +* If you have a mobile app, and want to enable it to open when a recipient clicks an email link, see [this article](./deep-links-self-serve). diff --git a/migration-tools/Pipfile b/migration-tools/Pipfile new file mode 100644 index 000000000..623726baa --- /dev/null +++ b/migration-tools/Pipfile @@ -0,0 +1,12 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +python-slugify = "*" + +[dev-packages] + +[requires] +python_version = "3.9" diff --git a/migration-tools/Pipfile.lock b/migration-tools/Pipfile.lock new file mode 100644 index 000000000..a207273f5 --- /dev/null +++ b/migration-tools/Pipfile.lock @@ -0,0 +1,36 @@ +{ + "_meta": { + "hash": { + "sha256": "649f2a246b2aa890ec48fb21f64079732856f03390fac338815d6b257e22b9e2" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.9" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "python-slugify": { + "hashes": [ + "sha256:6d8c5df75cd4a7c3a2d21e257633de53f52ab0265cd2d1dc62a730e8194a7380", + "sha256:f13383a0b9fcbe649a1892b9c8eb4f8eab1d6d84b84bb7a624317afa98159cab" + ], + "index": "pypi", + "version": "==5.0.2" + }, + "text-unidecode": { + "hashes": [ + "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8", + "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93" + ], + "version": "==1.3" + } + }, + "develop": {} +} diff --git a/migration-tools/fix-md-heading-links.py b/migration-tools/fix-md-heading-links.py index ebdfc6223..cfda6d24d 100755 --- a/migration-tools/fix-md-heading-links.py +++ b/migration-tools/fix-md-heading-links.py @@ -1,21 +1,9 @@ #!/usr/bin/env python3 -import argparse, sys, re +import argparse, sys, re, slugify -# this is a heuristic based on what we see in output files - not definitive +# Return a "slug" (HTTP safe) name - https://stackoverflow.com/questions/19335215/what-is-a-slug def markdown_title_name(t): - # Strip leading and trailing spaces, use lowercase - title = t.lower().strip() - # change non-alphanumeric to dash -, unless we already have a dash - for i in range(0, len(title)): - if not title[i].isalnum(): - title = title[0:i] + '-' + title[i+1:] - # replace any repeated dashes - while '--' in title: - title = title.replace('--', '-') - # remove any leading & trailing dashes - title = title.strip('-') - return title - + return slugify.slugify(t) class markup_doc: def __init__(self, f): diff --git a/migration-tools/test.md b/migration-tools/test.md new file mode 100644 index 000000000..7ee17702e --- /dev/null +++ b/migration-tools/test.md @@ -0,0 +1,9 @@ +--- +description: a test file +--- + +## Overview + +Here is a [reference](#mig) + +## Migration planning!With@very Str&nge Char*cters \ No newline at end of file diff --git a/migration-tools/test.sh b/migration-tools/test.sh new file mode 100755 index 000000000..309ff7f6a --- /dev/null +++ b/migration-tools/test.sh @@ -0,0 +1 @@ +pipenv run ./fix-md-heading-links.py test.md From c2aa5741f78c49c9f6fdb21123e86c682679c5ed Mon Sep 17 00:00:00 2001 From: tuck1s Date: Thu, 30 Dec 2021 22:55:29 +0000 Subject: [PATCH 5/7] Addressed review comments --- .../tech-resources/deep-links-self-serve.md | 4 +- migration-tools/Pipfile | 12 ---- migration-tools/Pipfile.lock | 36 ----------- migration-tools/fix-md-heading-links.py | 61 ------------------- migration-tools/test.md | 9 --- migration-tools/test.sh | 1 - 6 files changed, 2 insertions(+), 121 deletions(-) delete mode 100644 migration-tools/Pipfile delete mode 100644 migration-tools/Pipfile.lock delete mode 100755 migration-tools/fix-md-heading-links.py delete mode 100644 migration-tools/test.md delete mode 100755 migration-tools/test.sh diff --git a/content/docs/tech-resources/deep-links-self-serve.md b/content/docs/tech-resources/deep-links-self-serve.md index ce92a4342..a855c851f 100644 --- a/content/docs/tech-resources/deep-links-self-serve.md +++ b/content/docs/tech-resources/deep-links-self-serve.md @@ -1113,7 +1113,7 @@ The domains entitlement in your app(s) must match your tracking domain. This can Getting your app to auto-verify requires the `assetlinks.json` file to be available on your _specific_ tracking domain rather than relying on the organizational domain (main website). -To test auto-verify works for your domain(s), start with a fresh install of your app, as mentioned in [this article](#article-on-android-deep-links-https-levelup-gitconnected-com-the-wrong-hacked-and-correct-way-of-android-deep-linking-for-redirected-multisite-with-autoverify-5c72fb1f8053-the-wrong-and-right-way-specifically-auto-verify-on-variations-of-your-different-domains), because Android remembers the user's choice. +To test auto-verify works for your domain(s), start with a fresh install of your app, as mentioned in [this article](https://levelup.gitconnected.com/the-wrong-hacked-and-correct-way-of-android-deep-linking-for-redirected-multisite-with-autoverify-5c72fb1f8053), because Android remembers the user's choice. If you are getting the ["ask" prompt](#forwarding-clicks-from-android-to-sparkpost-ask) to choose which application opens the link, you can use the `adb` debugger to investigate the status of your app. If the Status is shown as `ask` then auto-verify is not working as intended. The value `always : 200000000` means it is verified. @@ -1130,7 +1130,7 @@ App verification status: Status: always : 200000000 ``` -If your app has more than one associated domain, the status will be "`ask`" if _any_ of them fail to auto-verify. You can use `adb` to check your setup from Android Studio without having to delete/reinstall. For more information on using the `adb` debugger, see [this article](#article-on-investigating-android-deep-link-problems-with-adb-https-medium-com-mobile-app-development-publication-unrealized-deeplink-bug-on-many-apps-6ac78a557702). +If your app has more than one associated domain, the status will be "`ask`" if _any_ of them fail to auto-verify. You can use `adb` to check your setup from Android Studio without having to delete/reinstall. For more information on using the `adb` debugger, see [this article](https://medium.com/mobile-app-development-publication/unrealized-deeplink-bug-on-many-apps-6ac78a557702). ## Further reading diff --git a/migration-tools/Pipfile b/migration-tools/Pipfile deleted file mode 100644 index 623726baa..000000000 --- a/migration-tools/Pipfile +++ /dev/null @@ -1,12 +0,0 @@ -[[source]] -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - -[packages] -python-slugify = "*" - -[dev-packages] - -[requires] -python_version = "3.9" diff --git a/migration-tools/Pipfile.lock b/migration-tools/Pipfile.lock deleted file mode 100644 index a207273f5..000000000 --- a/migration-tools/Pipfile.lock +++ /dev/null @@ -1,36 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "649f2a246b2aa890ec48fb21f64079732856f03390fac338815d6b257e22b9e2" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.9" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "python-slugify": { - "hashes": [ - "sha256:6d8c5df75cd4a7c3a2d21e257633de53f52ab0265cd2d1dc62a730e8194a7380", - "sha256:f13383a0b9fcbe649a1892b9c8eb4f8eab1d6d84b84bb7a624317afa98159cab" - ], - "index": "pypi", - "version": "==5.0.2" - }, - "text-unidecode": { - "hashes": [ - "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8", - "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93" - ], - "version": "==1.3" - } - }, - "develop": {} -} diff --git a/migration-tools/fix-md-heading-links.py b/migration-tools/fix-md-heading-links.py deleted file mode 100755 index cfda6d24d..000000000 --- a/migration-tools/fix-md-heading-links.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python3 -import argparse, sys, re, slugify - -# Return a "slug" (HTTP safe) name - https://stackoverflow.com/questions/19335215/what-is-a-slug -def markdown_title_name(t): - return slugify.slugify(t) - -class markup_doc: - def __init__(self, f): - self.text = f.readlines() # Store as separate lines, for ease of processing - self.labels = {} - - def scan_labels(self): - for i in range(0, len(self.text)): - line = self.text[i] - find_anchor = r'(.*)' - # re.I= case-insensitive search - anchor = re.search(find_anchor, line, flags=re.I) - if anchor: - # Assume at most one anchor per line. Keep the content before and after. - before = line[0:anchor.start()] - after = line[anchor.end():] - find_name = r'name=\"(.*)\"' - name = re.search(find_name, anchor[0]) - if name: - self.labels[name[1]] = markdown_title_name(after) - # Remove the anchor from the markdown text. Trim any double space that's left - if before.endswith(' ') and after.startswith(' '): - after = after.lstrip() - self.text[i] = before + after - return - - def replace_labels(self): - for i in range(0, len(self.text)): - line = self.text[i] - for k,v in self.labels.items(): - # Find intra-document link references such as (#ref) - find_link_ref = r'\#(' + k + ')' - doc_link = re.search(find_link_ref, line, flags=re.I) - if doc_link: - before = line[0:doc_link.start()] - after = line[doc_link.end():] - self.text[i] = before + '#' + v + after - return - - def as_text(self): - return ''.join(self.text) - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='Find and replace type links with inter document heading links') - parser.add_argument('file', type=str, nargs='?', default=None, help='filename to read. If file is absent, reads from the standard input (acts as a filter).') - args = parser.parse_args() - - if args.file: - with open(args.file) as f: - d = markup_doc(f) - else: - d = markup_doc(sys.stdin) - d.scan_labels() - d.replace_labels() - print(d.as_text()) diff --git a/migration-tools/test.md b/migration-tools/test.md deleted file mode 100644 index 7ee17702e..000000000 --- a/migration-tools/test.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -description: a test file ---- - -## Overview - -Here is a [reference](#mig) - -## Migration planning!With@very Str&nge Char*cters \ No newline at end of file diff --git a/migration-tools/test.sh b/migration-tools/test.sh deleted file mode 100755 index 309ff7f6a..000000000 --- a/migration-tools/test.sh +++ /dev/null @@ -1 +0,0 @@ -pipenv run ./fix-md-heading-links.py test.md From 777e6cec941da9ce27117d1bc97ad870cc085f1f Mon Sep 17 00:00:00 2001 From: tuck1s Date: Thu, 30 Dec 2021 23:09:32 +0000 Subject: [PATCH 6/7] Remove python --- .vscode/launch.json | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index f1f0acccf..ffbad05fb 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -24,14 +24,6 @@ "uriFormat": "%s", "action": "debugWithChrome" } - }, - { - "name": "Python: migration tool", - "type":"python", - "request":"launch", - "program":"${file}", - "console":"integratedTerminal", - "args": ["migration-tools/test.md"], - }, + } ] } From e778a8fb27fa8dace9e7744692133c340ed3fdbb Mon Sep 17 00:00:00 2001 From: tuck1s Date: Thu, 30 Dec 2021 23:30:14 +0000 Subject: [PATCH 7/7] revert date --- content/docs/tech-resources/deep-links-self-serve.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/tech-resources/deep-links-self-serve.md b/content/docs/tech-resources/deep-links-self-serve.md index a855c851f..34070cbe3 100644 --- a/content/docs/tech-resources/deep-links-self-serve.md +++ b/content/docs/tech-resources/deep-links-self-serve.md @@ -1,5 +1,5 @@ --- -lastUpdated: "12/23/2021" +lastUpdated: "02/24/2021" title: "Using Mobile Universal and App Links with SparkPost" description: "A guide to including iOS universal links and Android App Links in your SparkPost-delivered email" ---