closes https://linear.app/tryghost/issue/ANAL-23/filtering-by-logged-out-logged-in-traffic
- Updated all of our tinybird datasources and pipes to handle member status
- Added member_status as an array query param to the API endpoints
- Added a really dodgy power select multiple to the stats page to demonstrate it works (needs styling)
- Added all of the wiring so each chart updates
- This was done pretty fast, and may not be 100% right yet
closes https://linear.app/tryghost/issue/PLG-190
- often when adding portal links to your own site pages the URLs are added as absolute on the site's homepage due to copy+paste from displayed URLs in Admin
- when clicking absolute portal URLs the homepage is first loaded before the Portal popup is shown resulting in a slower and flashier experience
- added a transform for all local portal URLs on the page when Portal is initialized so links open the Portal popup immediately on the current page
ref https://linear.app/tryghost/issue/DEV-20/faster-builds
- this was previously causing duplicate builds of the TS projects
because Nx was building all projects with `build` targets, and we were
also calling `build:ts`
- this cuts 12 compilation jobs from the archive process, which should
help with container build times
closes
https://linear.app/tryghost/issue/ANAL-9/initial-tracker-in-ghost-head
- Given that all of the correct config is in place, output a tracking
script
- This allows us to send pageview events into tinybird
- All of the details (location of the script, destination etc) are kept
in config so that it's easy to change for different environments
ref DES-706
* After a user publishes or schedules a post, they are directed to the post list
* If a post is sent as an email, they are directed to the Analytics page
* In both cases, a confirmation modal is shown
* If a post is published, they can share it directly from the confirmation modal
* Added a "Share" button and some additional functions (view, edit, and delete post) to
published posts in post analytics
* Added a manual "Refresh" button to post analytics so that there is
no need to reload the whole app to update the data
---------
Co-authored-by: Sag <guptazy@gmail.com>
no ref
This service can get rather noisy when doing local development with our
data generator, as we do not use real urls, and therefore generate a lot
of not found errors in the console.
ref https://linear.app/tryghost/issue/ANAL-27/setup-tinybird-project-and-cicd
- Tinybird has a system for managing it's configuration as code, with full ci/cd support
- The tinybird CLI tool uses python, so we'll run that using docker, via `yarn tb`
- Some of the files tinybird adds should not be in source control, so we've added those to git ignore
- Everything in /ghost/tinybird is tinybird's init config
closes
https://linear.app/tryghost/issue/ANAL-10/stats-page-in-ghost-admin
- Adds all the structure, logic and permissions tests for the Stats page
to check we're loading the right thing at the right time
- Adds @tinybirdco/charts as a dependency, and has a single example of a
chart setup using the right config
closes https://linear.app/tryghost/issue/ANAL-8/flag-and-config
- This checks if tinybird:stats is set, and if so passes through the
config that is set via the config API
- This is used by Ghost admin to configure where to pull charts from
- we added NestJS to Ghost as a way forwards for a new framework within
Ghost but we haven't added much to it
- requiring all the NestJS code adds about 6-9% to our boot time, so if
we're not using it, it's just time we're burning for no benefit
- for now, I've gated this behind an env var to prevent it from loading
- we can't use labs flags in the boot process, so I've gone for an env
var
ref https://linear.app/tryghost/issue/ONC-274
This fix is done at the endpoint layer, which isn't ideal, but has the smallest
surface area for the change. I think we may want to move it up a layer though,
despite the extra complications. If we move the check _into_ the MembersAPI
class however, we start to run into issues with circular dependncies due to the
mess that is our dependency injection approach with the Members service
ref https://linear.app/tryghost/issue/ONC-274
This test checks that a welcome email is not sent when adding a member via the
Admin API if the site is in need of email verification, regardless of whether
or not the flag to send an email is set.
It is currently failing to demonstrate the whole in our logic.
All tests after this one were in a non-sending email state, which luckily
doesn't affect these tests, but it will affect future ones! This just cleans up
the settings so that they're back to a standard default.
ref DES-756, DES-757
- made the email property to make the refresh work properly for published-only posts
- included sentiment in the query to update the feedback percentage when refreshed
- Swap the e2e config API test to use our newer framework, and match against a
snapshot for the default case
- Move the individual test cases to unit tests (new file) - there are more to add
here, but this is parity with what we had before
- We use unit tests for checking through various cases for how config
changes modify the output as this is faster and more explicit
ref
639be25f1d
ref
f705dda314
- These items are never returned from the API as they've been removed
from the serializer
- The tests also check that they are not present
- They were removed by the referenced commits, which changed how these
things were built
ref PLG-160
- Refactored donation handling logic to be processed within the
`checkout.session.completed` webhook event.
- Added support for capturing and storing donation messages from Stripe
sessions.
- Integrated donation messages into the email notifications sent to
staff.
- Added database integration.
- Removed redundant donation logic from the invoice.payment_succeeded
webhook, since custom fields isn't supported.
- Updated and added new tests
---------
Co-authored-by: Sanne de Vries <sannedv@protonmail.com>
no issue
- when redirecting from Stripe back to Ghost after making a donation the URL contained a double slash (`//#/portal/...`) which triggered browser security errors when Portal modified the browser history stack when navigating
- the above could prevent the donation success modal from closing
ref DES-709
- when refresh button is clicked, the numbers in the analytics will be animated if changed
- for the animation to be performant, added a new dependency "animejs"
- to minimize the flash and layout shift, the analytics data is kept as it is while loading
- once finished loading, it will be replaced with the new data
ref https://linear.app/tryghost/issue/ENG-1518
After releasing the analytics job improvements, it appears for large
sites we're awfully close to missing some Mailgun events because of an
unexpected behavior of the aggregateStats call for just the opened
events job. This is taking 2-5x(+) the amount of time that the aggregate
queries take for the other jobs, despite not being dependent on the
events.
To err on the side of caution, we're going to roll this back and look to
optimize the aggregation queries before re-implementing. And we may be a
bit more cautious in giving _some_ but not _all_ priority to the
`opened` events.
ref https://linear.app/tryghost/issue/ENG-1518
After releasing the analytics job improvements, it appears for large
sites we're awfully close to missing some Mailgun events because of an
unexpected behavior of the aggregateStats call for just the opened
events job. This is taking 2-5x(+) the amount of time that the aggregate
queries take for the other jobs, despite not being dependent on the
events.
To err on the side of caution, we're going to roll this back and look to
optimize the aggregation queries before re-implementing. And we may be a
bit more cautious in giving _some_ but not _all_ priority to the
`opened` events.
Buttons were previously part of the bookmark card, but that's no longer
the case. This makes it easier to scale between different types of
posts/emails.
ref PLG-196
- Added comprehensive unit tests to cover various scenarios for the
createDonationCheckoutSession function.
- Verified correct handling of customer object, customerEmail and
metadata.
- Ensured accurate parameter passing to Stripe API, including
success_url and cancel_url.
ref DES-731
- improved mobile styles for the social buttons in the modal
- fixed the flow for publishing/scheduling pages
- redirect to post list only when a post doesn't involve any email
Comprehensive, context aware, Bosnian translations for all available
strings.
Informal addressing of users (as is widely accepted in Bosnia and
Herzegovina).
Minor text fixes.
ref
https://linear.app/tryghost/issue/ENG-1505/start-monitoring-event-loop-utilization-in-production-with
- The two main constraints we've observed in Ghost are the database connection pool and the CPU usage. However, there is a third constraint that we may be hitting, but can't currently observe: the event loop.
- This commit re-enabled OpenTelemetry (behind a config flag), removes the problematic tracing instrumentation which was breaking the frontend, and adds a Prometheus endpoint to export the eventLoopUtilization metric.
- This should give us visibility into whether we are hitting constraints in the event loop and address the root cause if we are.
ref KTLO-1
These tokens should prevent untargeted attacks, as the magic link
endpoint needs a token that was generated by the server, similar to a
CSRF token, but without needing any server-side state, or a cookie to
be set for unauthenticated users.
ref https://linear.app/tryghost/issue/ENG-952
- added persistence to the job timestamps
This set of changes reduces the potential for gaps in our email event
processing by adding persistence to the job timestamps. This avoids
expensive queries on the `email_recipients` table after every boot, and
reduces reliance on fallbacks in periods of heavy processing or reboot.
This is our first use of the jobs table to create a persistent line,
instead of its initial use case of single-run jobs. We may expand this
capability and move to use of the jobs model over knex.raw in order to
make this a bit friendlier.
Note: this works with sqlite but datetimes are stored as ints. It still
works fine. https://github.com/knex/knex/pull/5272
ref https://linear.app/tryghost/issue/ENG-1489/
The changes to improve posts loading in admin broke the shift selection
functionality. This restores that, as we need to be able to crawl across
the (now) three models when present.
The new modal for the updated publishing flow has an entirely new
layout, based on feedback previously received. In addition, this PR
includes a few tweaks to the underlying logic.
ref https://linear.app/tryghost/issue/ONC-263/
- labels dropdown in sign up card was not successfully fetching labels
- offers dropdown suffered the same fate
When introducing the second editor instance, it appears we ran into some
race conditions with the Ember tasks used to fetch the resources. The
init instance was beating the other to the punch, and so the state was
never successfully updated, as it is only fetched once on mounting the
card.
ref PLG-153
- Scoped one-time payments (`donation_event`) under the "payments"
category in the member activity feed filter.
- Updated `toggleEventType` logic to ensure that toggling "payments"
also toggles one-time payments when the `tipsAndDonations` feature is
enabled.
- Refactored event type handling into utility functions for easier
testing.
- Added unit tests for the new utility functions to ensure correct
behaviour.
- Added acceptance testing.
ref
https://linear.app/tryghost/issue/ONC-242/frontend-routing-prioritizes-collections-over-taxonomies
- Under a fairly specific edge case with a collection route that conflicts with a default, built-in route ("taxonomy" — like tags, authors, etc), the frontend routing would prioritize the collection over the taxonomy.
- For example, with the following in a custom `routes.yaml`:
```
collections:
/:
permalink: /{primary_tag}/{slug}/
template: index
```
If a post exists with the same slug as its primary tag's slug, the frontend routing would redirect the `/tag/{slug}/` route to the post in the collection, rather than serving the tag itself.
- This commit changes that, so if a collection's route conflicts with e.g. a `/tag/{slug}/` default route, Ghost will still return the built in route, rather than the collection.
no issue
- Safari's `innerText` sometimes includes a trailing `\n` depending on the markup used so we need to use `.to.have.rendered.trimmed.text()`
- reproducible when running tests via http://localhost:4200/tests (we don't yet run in Safari via our testem config)
closes https://linear.app/tryghost/issue/PLG-176
The editor files were previously stubbed for testing because we didn't have a way to load the externally-hosted files. This made testing slow and difficult because the only way to test the Admin integration was via Ghost's e2e browser tests.
- unstubbed the editor globals so `fetchKoenigLexical()` actually tries to import the external assets
- updated `ember-cli-build` to copy the Koenig UMD file over to the assets directory in development/test builds
- updated `environment.js` to set the required filename for the default asset import to successfully hit the test environment hosted files
- updated lexical editor acceptance tests to demonstrate the editor loads successfully for new and existing posts
ref https://linear.app/tryghost/issue/ONC-261
- Previous method of hiding the second Lexical instance using `width:
0`, `height: 0`, and `overflow: hidden` caused CPU usage to spike,
likely due to CodeMirror continuously processing the element.
ref https://linear.app/tryghost/issue/ONC-261
- Previous method of hiding the second Lexical instance using `width:
0`, `height: 0`, and `overflow: hidden` caused CPU usage to spike,
likely due to CodeMirror continuously processing the element.
ref https://linear.app/tryghost/issue/ENG-1477
- updated email analytics job to prioritize open events
- put limits on non-open event fetching
- updated job to now restart itself until processing is at a
sufficiently low volume
Previously the EmailAnalytics job would process all event data equally.
When there's sufficient recipients (>20k), we could see delays in the
open rate data in Admin because of all the delivered events being
processed. Open events are far more important to users, so we've now
prioritized processing those events before any others.
Processing of events shouldn't be any faster or slower with this as this
doesn't change throughput, just order.
NOTE: Use the mailgun-mock-server in TryGhost/Toolbox for testing.
ref DES-697
- used client side navigation on the flow instead of hard refresh
- reduced layout shift on the analytics screen
- made the modal transition a bit smoother
ref https://github.com/TryGhost/Ghost/pull/20793
- now that there's a non-zero suggested value amount Stripe's UI shows a button to change the amount rather than showing the amount input field immediately
- added extra click to the tests and an expectation that the default value is set correctly
closes https://linear.app/tryghost/issue/PLG-156
- updated all default fixtures to use `500` ($5) as the default suggested donation value
- added migration to update existing settings using the old default of `0` to `500`
- this is fine to apply because the feature hasn't been released so there's no explicit `0` values in the wild
- added an acceptance test for the adminx-settings tips & donations section
ref DES-609
- On top of bookmark card, this update adds default background color and font to file, audio, and product cards
- The main purpose of this is keeping embedded look across these cards consistencly regardless of the theme background color and default font
- Themes can still override the styles
ref https://linear.app/tryghost/issue/PLG-174
- forcing autosave on excerpt blur caused posts to revert to `draft` and save immediately even when they were published/scheduled
- updated the save-on-excerpt-blur to only autosave drafts
- added acceptance tests for title and excerpt change+blur on published posts
ref [ENG-661](https://linear.app/tryghost/issue/ENG-661/)
ref [ONC-253](https://linear.app/tryghost/issue/ONC-253/)
ref [PLG-174](https://linear.app/tryghost/issue/PLG-174/)
- restored the original but reverted fix for unsaved changes modal from https://github.com/TryGhost/Ghost/pull/20687
- updated code to remove some incorrect early-falsy-return logic in `editorController.hasDirtyAttributes` that prevented save of unsaved changes on the underlying model (e.g. excerpt)
- updated unit tests so they are testing real post model instances and therefore are testing what we expect them to test
- added acceptance tests to ensure autosave is working for title and excerpt fields
---------
Co-authored-by: Ronald Langeveld <hi@ronaldlangeveld.com>
ref https://linear.app/tryghost/issue/PLG-176
- we recently had to revert code because it caused unexpected problems despite the unit tests passing
- the setup for the editor unit tests was very basic and did not represent the real world because it tested a simple EmberObject instance rather than an Ember Model instance meaning the tests weren't covering the real code paths
- updated the unit test with a more realistic environment ready for re-working the reverted code+tests
ref https://linear.app/tryghost/issue/PLG-174
- added `blur` handler to excerpt field so it acts the same as the title field and triggers a save when it loses focus
ref https://linear.app/tryghost/issue/PLG-174
- forcing autosave on excerpt blur caused posts to revert to `draft` and save immediately even when they were published/scheduled
- updated the save-on-excerpt-blur to only autosave drafts
- added acceptance tests for title and excerpt change+blur on published posts
ref [ENG-661](https://linear.app/tryghost/issue/ENG-661/)
ref [ONC-253](https://linear.app/tryghost/issue/ONC-253/)
ref [PLG-174](https://linear.app/tryghost/issue/PLG-174/)
- restored the original but reverted fix for unsaved changes modal from https://github.com/TryGhost/Ghost/pull/20687
- updated code to remove some incorrect early-falsy-return logic in `editorController.hasDirtyAttributes` that prevented save of unsaved changes on the underlying model (e.g. excerpt)
- updated unit tests so they are testing real post model instances and therefore are testing what we expect them to test
- added acceptance tests to ensure autosave is working for title and excerpt fields
---------
Co-authored-by: Ronald Langeveld <hi@ronaldlangeveld.com>
ref https://linear.app/tryghost/issue/PLG-176
- we recently had to revert code because it caused unexpected problems despite the unit tests passing
- the setup for the editor unit tests was very basic and did not represent the real world because it tested a simple EmberObject instance rather than an Ember Model instance meaning the tests weren't covering the real code paths
- updated the unit test with a more realistic environment ready for re-working the reverted code+tests
ref https://linear.app/tryghost/issue/PLG-174
- added `blur` handler to excerpt field so it acts the same as the title field and triggers a save when it loses focus
DES-696
We upgraded the AdminX Design System to use Radix UI components. However
browser tests fail for checkboxes at the moment which must be fixed for
release.
ref [ENG-661](https://linear.app/tryghost/issue/ENG-661/) ONC-253
- Reverts the revert of
93cbb94b90
of the intial bug fix.
- Updated hasDirtyAttributes logic to ensure the dirty state changes
when typing a draft, despite not title.
- Updated tests and added tests missing from the hasDirtyAttributes
logic
REF DES-321
- Added a "Copy post link" button to the context menu to copy the post URL for published posts, and a "Copy preview link" for draft and scheduled posts.
---------
Co-authored-by: Kevin Ansfield <kevin@lookingsideways.co.uk>
ref ENG-1490
- Regression from the secondary lexical instance.
- Replaced the visibility and positioning styles with width, height, and
overflow to prevent layout space issues.
- Ensured the element takes up no space and is not visible, while
allowing proper initialisation.
fixes https://linear.app/tryghost/issue/ENG-1484
- in Ghost release
[v5.89.0](https://github.com/TryGhost/Ghost/releases/tag/v5.89.0), we
have added a safeguard around bulk member deletion, due to a limitation
in NQL for member filters (commit: 2484a77)
- with this change, we limit the safeguard to only the cases we know are
problematic, and remove it for other useful and safe queries
- more precisely, the safeguard is in place only when:
- Multiple newsletters exist, and the filter contains 2 or more
newsletter filters
- If any of the following stripe filters are used even once:
- Billing period
- Stripe subscription status
- Paid start date
- Next billing date
- Subscription started on post/page
- Offers
no issue
- added passthrough of `feature.contentVisibility` when rendering Lexical to HTML to allow for labs-feature specific rendering of HTML cards
- updated golden post email render test to account for labs flags being on/off
ref PLG-109
- Added a boolean config property `stripeEnabled` to the configuration.
- This property is now passed down to the Koenig Editor to manage
features based on Stripe connectivity.
closes https://linear.app/tryghost/issue/PLG-15
- removed `internalLinking` GA labs flag
- renamed search providers to `flex` and `basic`
- keeps old search provider around as it can handle non-English languages unlike the faster flex provider
- updated `search` service to switch from `flex` to `basic` when the site's locale is not english
- bumped Koenig packages to switch from a feature flag for toggling internal linking features to the presence of the `searchLinks` function in card config
- updated tests to correctly switch between flex and basic providers in respective suites
fixes
https://linear.app/tryghost/issue/DES-435/excerpt-in-post-settings-has-an-inconsistent-error-state
The excerpt form field seemed to not be properly handling errors.
However, it was a case of the error styling being overruled by the
regular styling, causing the red border to only show upon `:focus` when
there is an error in the excerpt.
I've rewritten the logic to be slightly less obfuscated and added some
CSS to circumvent the issue.
ref ONC-225
- Wires up the `editor_default_email_recipients` key to the settings
public / content api endpoint.
- This key is then wired up to Portal to determine whether it's hiding or
showing the Member subscribe toggle
refs https://ghost-foundation.sentry.io/issues/4907452370/
- we want to ignore these errors but the caret is stopping us from doing
so because the errors usually start with AbortError
- we can remove the caret to do so and clean up Sentry
refs ENG-661
Fixes a long-standing issue where an outdated Lexical schema in the
database triggered the unsaved changes confirmation dialog incorrectly.
Implemented a secondary hidden Lexical instance that loads the state
from the database, renders it, and uses this updated state to compare
with the live editor's scratch.
This ensures the unsaved changes prompt appears only when there are real
changes from the user.
ref
https://linear.app/tryghost/issue/ENG-1440/backfill-offer-redemption-data-with-a-migration
There was a bug that caused offer redemptions to not be recorded in the
database for some subscriptions that were created with an offer.
However, we still have the `offer_id` attached to the subscriptions, so
we are able to backfill the missing redemptions. The bug was fixed in
bf895e6e99
This commit only contains a migration, which queries for subscriptions
that have an `offer_id` but do not have any offer redemptions recorded,
and adds any missing redemptions to the `offer_redemptions` table.
ref https://linear.app/tryghost/issue/ONC-197
- YouTube has started responding to video page requests with localised content when requested from certain IPs, with that localised content not containing the required `<link rel="alternate" ...>` tag pointing to the oembed endpoint
- we were fetching video pages rather than the oembed endpoint for YouTube Live URLs because they are not recognised by the oembed extraction library we use
- by modifying the URL from a live URL to a watch URL before we perform oembed lookup/extraction we are able to bypass the (localised) page fetch and instead grab the oembed content directly
ref https://linear.app/tryghost/issue/ONC-199
The `updateSubscriptionItemPrice()` method in our Stripe library used by the importer when moving a subscription over to a Ghost product/price was setting `proration_behavior: 'always_invoice'`. This resulted in invoices being created when changing the subscription (even though no prices were changing as far as the customer is concerned) and in some cases where a customer previously had a one-off discount the customer was incorrectly charged the proration difference because the discount was no longer applied to the new invoice.
- updated `updateSubscriptionItemPrice()` to accept an `options` param allowing the `proration_behavior` property passed to the Stripe API to be overridden on a per-call basis
- updated the `forceStripeSubscriptionToProduct()` method used by the importer to pass an options object with `prorationBehavior: 'none'` when updating the subscription item price so that no invoice and no unexpected charges occur when importing
ref https://linear.app/tryghost/issue/ONC-199
The `updateSubscriptionItemPrice()` method in our Stripe library used by the importer when moving a subscription over to a Ghost product/price was setting `proration_behavior: 'always_invoice'`. This resulted in invoices being created when changing the subscription (even though no prices were changing as far as the customer is concerned) and in some cases where a customer previously had a one-off discount the customer was incorrectly charged the proration difference because the discount was no longer applied to the new invoice.
- updated `updateSubscriptionItemPrice()` to accept an `options` param allowing the `proration_behavior` property passed to the Stripe API to be overridden on a per-call basis
- updated the `forceStripeSubscriptionToProduct()` method used by the importer to pass an options object with `prorationBehavior: 'none'` when updating the subscription item price so that no invoice and no unexpected charges occur when importing
Ref https://linear.app/tryghost/issue/SLO-193/optimise-count-query-skip-distinct-from-count-query-for-members-events
The member events endpoint have many queries like:-
select count(distinct members_subscribe_events.id) as aggregate
from `members_subscribe_events`
where `members_subscribe_events`.`created_at` < '2024-07-30 11:30:39'
In these queries, distinct is not required as id is a primary key. Skipping distinct would improve the performance.
This PR will changed the query to:-
select count(*) as aggregate
from `members_subscribe_events`
where `members_subscribe_events`.`created_at` < '2024-07-30 11:30:39'
ref 8ea1dfb
ref https://linear.app/tryghost/issue/ONC-111
* undid the reversion for the performance improvements
* built upon new tests for the posts list functionality in admin,
including right click actions
* added tests for pages view in Admin
This was reverted because it broke the Pages list view in Admin, which
is a thin extension of the Posts functionality in admin (route &
controller). That has been fixed and tests added.
This was originally reverted because the changes to improve loading
response times broke right click (bulk) actions in the posts list. This
was not caught because it turned out we had near-zero test coverage of
that part of the codebase. Test coverage has been expanded for the posts
list, and while not comprehensive, is a much better place for us to be
in.
fixes https://linear.app/tryghost/issue/ONC-206
ref https://app.incident.io/ghost/incidents/90
- when multiple member filters are used in combination, NQL sometimes
hit a limitation that results in the wrong members being returned
- while we work on the NQL limitation, we are temporarily disabling bulk
member deletion when more than one member filter has been applied
no ref
- while reviewing the newsletter flows, it was apparent that we were
missing test coverage
Some of the tests in Portal are a bit redundant with tests added for
child components, but it didn't seem worth removing them after getting
them to work. There was a bug in our Portal fixture data that requires a
few changes, as well as some small adjustments for making tests easier
(testing-lib-react has `getByTestId` and simply a `querySelector` to use
alternate test attributes).
ref
https://linear.app/tryghost/issue/PA-71/remove-cache-bust-from-projs-in-admin
ref
15ed2eb245
- This cache buster was added in March to mitigate a client side error in pro.js,
to effectively force browsers to redownload the fixed version of the file.
- It's not needed anymore, as the error has been fixed for a few months
now, so we can safely remove it.
ref https://linear.app/tryghost/issue/SLO-160
- in the Members list, we were using VerticalCollection with
`@bufferSize` set to 20, which means that 20 additional items before and
after the visible items in the viewport were pre-loaded
- however, scrolling down too quickly (e.g. dragging the scrollbar thumb
to the bottom) breaks the list
- with this fix, we adjust `@estimateHeight` parameter to the correct
item size, and reduce the `@bufferSize`
REF MOM-315
- Changed to column layout
- Fixed broken currency dropdown
- Included a link to Stripe terms & conditions
- Renamed from "Tips or donations" to "Tips & donations"
Right now identity tokens can only be fetched by the Owner, which means they
implicitly have the Owner role, but we want to expand that. The first step is
adding the role to the token, and then we need to update each place which uses
the token and add an assertion that the role is correct.