refs https://github.com/TryGhost/Team/issues/694
- The canary schedules controller was refactored to use newly introduced post-scheduling service in a previous commit. This is a follow up to match v2/v3 controllers as they had identical code to the canary one.
refs https://github.com/TryGhost/Team/issues/694
- The controller code is not meant to contain complex business logic.
- Kept the pattern used in all modules under services/themes. The install module shold be refactored into a class with DI pattern when touched next.
refs https://github.com/TryGhost/Team/issues/694
- Additional try/catch block needed in async/await implementation increased method complexity and broke the complexity linting rule. This is a dirty way to fix the warning. Ideally the implementation should stay with async/await syntax and instead move the custom error handling logic into some different layer. For example we could introduce a separate "stage" in the API framework's "pipeline" where we'd catch and handle in a generic way all of the "unique" types of errors. It would make sense to have a generic handler because this same code happens in labels, member and few more places.
refs baccbb4942
refs https://github.com/TryGhost/Team/issues/694
- The change is here to remove yet another ESLint method complexity error
- The custom error handling complexity was introduced here in a referenced commit without an obvious reason. The specifics of how the "sendTestEmail" method handles errors should not leak out from the method, if there are errors in the response they should be handled internally and the method would uniformly reject with a single error.
refs https://github.com/TryGhost/Team/issues/694
- The code complexity in the email preview's read controller method was breaking the complexity rule in ESLint. To reduce the complexity extracted common parts into mega service
refs https://github.com/TryGhost/Team/issues/694
- async/await has been a standard way to handle async code throughout the codebase. Refactoring it before moving code makes it way easier to reason about similarities between multiple controllers
refs https://github.com/TryGhost/Team/issues/947
- During the work of the UI and moving `email_only` flag to publish menu it created the situation where the publishing of the post was at the same time as adding `email_only` flag, resulted in not picking up teh `sent` status as the `posts_meta` model and record were's available during save.
- Adding the incoming attribute check for email_only flag covers this situation
no-issue
Writing code outside of Ghost which deals with the models is currently
done by passing the models which are needed to the external module,
rather than the instance of ghostBookshelf. This does not give us a way
to create transaction to run queries in. This method is designed as a
simple way to give all models the power to create a transaction for
themselves.
This will be used in @tryghost/members-api for example to ensure that
failures in communication with the Stripe API will rollback the related
inserts in the database.
refs https://github.com/TryGhost/Team/issues/873
This includes the update to @tryghost/members-api which includes the new
MemberBREADService which is used to handle the logic for controller
methods outside of the controller.
With it, we've introduced the concept of a dummy subscription for comped
members. This gives API consumers a way to get the created_at date for a
comped members access to a product.
no-issue
The @tryghost/members-api module is being updated to export a BREAD
service which will be used to move the logic from the controller into.
This service is currently designed to returns objects rather than
models, as it has to do manipulation of the returned data at the object
level. This update to the serializer will allow a seamless transition to
the use of the BREAD service and allow us to pull out the logic from the
controller sooner!
refs 3f0bab4389
- the internal `request` lib we had was replaced with `@tryghost/request` in
the referenced commit
- this lib was not deleted, so it's still lingering around
- this commit deletes that file to clean it up
no-issue
The bluebird library is unecessary in this module, as all uses of it
were wrapped in `async` functions which will return a native Promise
rather than a bluebird one.
refs https://ghost.slack.com/archives/C02G9E68C/p1629822160273500
refs https://github.com/TryGhost/Team/issues/1007
- `:root` selector wasn't working as expected and ended up matching HRs within content
- switched to wrapping the post html inside a `<body>` element before parsing so that we have a proper top-level element for direct child selectors to match against
refs https://github.com/TryGhost/Team/issues/1007
- the new `email-cta` card allows surrounding dividers to be added when rendering, however if the card is at the beginning or end of the post then these would double-up with the already existing dividers at the beginning and end of the post content in the email template
- not wanting leading/trailing HR's is specific to the email template so it made sense to adjust the renderer output in Ghost's email generating rather than forcing all mobiledoc->html rendering to remove leading/trailing HR's
refs https://github.com/TryGhost/Team/issues/873
The @tryghost/members-api module needs access to this model in order to
create events when members access to products are updated.
refs https://github.com/TryGhost/Team/issues/873
We need a relation between members and their product events so that we
can pull out the events for a particular member to generate the start
date of their comped access to a product.
refs https://github.com/TryGhost/Team/issues/946
This adds the initial bulk actions endpoint used for the members
filtering feature. The idea is to eventually move bulk destroy into this
endpoint to and provide a consistent interface for applying bulk actions
to members.
The @tryghost/members-api package has been bumped to include the new
bulkEdit method.
The sinon.restore in tests was moved to an afterEach so that stubs did
not effect other tests.
refs https://github.com/TryGhost/Team/issues/946
In order to bulk remove relations between members and labels we need a
way to get hold of all of the existing relations between a label and a
set of members.
refs https://github.com/TryGhost/Team/issues/873
This table is to track events related to members be given or having
removed access to products. It will allow us to provide start dates for
access for complimentary members, as well as being able to track access
to products over time, either for individual members or for aggregates.
no issue
- The method was super hard to read with unintuitive catches in multiple places and lots of conditional logic. There's still more to reshuffle here, but that would be for the next time. At least now the data flow is clear within the method
no issue
- Logic with slightly more complex structure belongs to the service. Extracting it there also show's how little of an API the oembed service should actually expose
refs https://github.com/TryGhost/Team/issues/714
In order to order products by their monthly price we need to apply a
join with the stripe_prices table when querying so we have access to the
amount column of stripe_prices.
As this ordering is core to how the tiers feature is intended to work,
we have added it as the default order. But this can be overriden by
manually passing the order option.
Also ensured that we do not create duplicate products in test fixtures
refs https://github.com/TryGhost/Team/issues/990
- Relying on uuid instead of slug makes the posts less discoverable and partially soves discoverability through overriden robots.txt files
refs https://github.com/TryGhost/Team/issues/958
- The module contains a service class and not an api index as index.js file should. This rename also fixes an ESLint warning around index.js file being too complicated.
- The serivice should ideally be extracted into the member repository in the future iteration
refs 9e2b21578a
Since the ref'd commit the labs middleware was moved to the shared labs module
and this require path no longer exists. This does not break anything as any module
still using this would error when reading the labs property
- Unquestionably, at some point we need to rework the API code so that we have less stuff everywhere
- However, the max-lines index.js rule exists as a proxy to find index.js files which are not exposing Public API, but rather contain logic
- These 6 cases are all valid index.js files as the expose the Public API of the module
- Therefore, I've added an override and an override notice explaining.
refs https://github.com/TryGhost/Team/issues/946
This refactor pulls out the core logic so that we can easily add other
bulk operations without having to duplicate even more logic.
It also gives a consistent return value between bulk operations, renaming
`unsuccessfulIds` and `unsuccessfulRecords` to `unsuccessfulData`
We also add a bulkEdit method which will be used to bulk unsubscribe members
from the newsletter.
refs https://github.com/TryGhost/Team/issues/959
Since we had a bug where members with a canceled subscription would have
a status of 'comped' we must fix any existing members in this state.
We update all members which have no products to a status of 'free',
which is the definition of a 'free' member.
refs https://github.com/TryGhost/Team/issues/899
- The internal API is needed to be able to fetch email-only posts through email router. The concept is similar to Preview API with a difference that only posts with `sent` status are accessible and there is content-gating present.
refs https://github.com/TryGhost/Team/issues/953
- We need to track email-only posts that have been sent out. New status was chosen as a way to differenciate such posts.
- Introducing a new "email post" type, conceptually like "page", was considered. Because there is no clear roadmap for "email post" becoming a bigger part of the product yet and a lot of uncertainty around this concept, overhead needed to introduce a new type was just too much to do at this moment. It's still a possibility in the future
no-issue
This moves the logic out of the controller and into the members-api
member repository. Removing complexity from the controllers and
out into services is desirable to reduce code in the Ghost codebase
and move logic into modules which can be tested easier.
closes https://github.com/TryGhost/Team/issues/952
- The `/email/` route will be a home for email only posts. We are adding the route preemptively to have the crowlers update their caches before the feature sees the light of The Internet
refs https://github.com/TryGhost/Team/issues/948
- The frontend route `/email/:uuid` is aliased to the preview as a temporary solution. It fulfills the premise of the email-only post anyway - not being accessible publicly and only shared through email.
- The tests for the new route are missing as adding them was way more problematic than I envisoned. They are in the works and will be added as a follow up commit next.
refs https://github.com/TryGhost/Team/issues/949
- When post is marked as "email-only" we can send it out to the selected audience when publishing without making the post publicly available
- The feature is available for experimentation behind "email only" alpha flag available in labs
refs https://github.com/TryGhost/Team/issues/949
- Initializing PostsService with almost identical parameters is burdensome, having a single factory method in create instances is far more maintainable
refs https://github.com/TryGhost/Team/issues/949
- It's relly hard to grasp what's going on in ifs with multiple conditions that are written down in a signle, gazzilion-line format. Having a nice column as way more readable
refs https://github.com/TryGhost/Team/issues/949
- The post model handling related to newsletter sending and email recipient filter logic were duplicating across v3/v4(canary) APIs and it made sense to extract it into a posts service.
- This will allow for a central place to handle about to land logic for email_only newsletter handling.
refs https://github.com/TryGhost/Team/issues/949
- The code is exactly the same in six (!) places. It's beyond unmaintainable to add another line to any of these place, which will be needed for `email_only` handling.
- The newly created posts service is a temporary, slightly better solution that complies with codebase's best practice of extracting new services using class with DI pattern
refs https://github.com/TryGhost/Team/issues/949
refs e64274bb45
- This refactor is needed to bring the code in line with the rest of pages API controllers
- Next step will extract shared code patterns into a separate module
refs https://github.com/TryGhost/Team/issues/949
refs e64274bb45
- This refactor is needed to bring the code in line with the rest of pages API controllers
- Next step will extract shared code patterns into a separate module
refs https://github.com/TryGhost/Team/issues/949
- This refactor is needed to bring the code in line with the rest of post API controllers
- Next step will extract shared code patterns into a separate module
https://github.com/TryGhost/Team/issues/893
- The assignment is not that obvious and might be confusing without wider context, which is why it warrants to have a clarifying comment. This became apparent during code review
refs https://github.com/TryGhost/framework/pull/19
The @tryghost/bookshelf-filter plugin no longer bundles hardcoded
relations and expansion definitions, instead leaving it up to the
library consumer to implement.
This PR adds the preexisting relations and expansions to the relevant
models, in order to preserve our existing filtering functionality.
refs https://github.com/TryGhost/Team/issues/560
refs 69b773d112
The endpoint `/members/api/session/` is used by Portal for fetching member session while setting up and redirecting to Stripe Checkout flow. The status code returned by API for logged out member is changed from 4xx Unauthorized to 204 No Content, which is consistent with the status code returned while fetching member data when logged out. This API is made just before initiating the checkout session, and is not noticable in most cases due to redirect to Stripe Checkout and got missed.
refs https://github.com/TryGhost/Team/issues/928
- applied same darkening of accent color in emails as we use in editor when there's insufficient contrast of accent color against a white background
refs https://github.com/TryGhost/Team/issues/928
- duplicated email template so email-cta changes can go into the labs version
- added `accentContrastColor` to template settings for using white/black depending on the accent color
- added `.gh-btn-accent` styles to the email template (email-cta card already uses those for the button)
refs https://github.com/TryGhost/Team/issues/912
- When the improt acceedes the threshold for the first time we need a way to notify configured escalationAddress to verify the instance owner's email address.
closes https://github.com/TryGhost/Team/issues/913
- Having a limit service rule triggered was a temporary hack to get a basic email blocking version working
- As the freeze value is now persisted in the DB it's possible to read and rely on it to throw an error straight from MEGA.
refs https://github.com/TryGhost/Team/issues/912
- Previous logic was a bit misleading because it prevented from reading the real threshold configured with an instance once the verified flag was present in the config.
- The reshuffle made here allows to check the freeze logic based on the threshold and then process the returned result accordingly instead of having hidden logic behind "importThreshold" config value
refs https://github.com/TryGhost/Team/issues/912
- The email freeze state has to be stored somewhere to make it through the instance restart and settings table is the best place for it.
refs https://github.com/TryGhost/Team/issues/912
- We need a place to persist the email freeze state between instance restarts - settings table record is the best place for it
refs https://github.com/TryGhost/Team/issues/927
- the `email-cta` card can be segmented so only free or paid members can see the content, it should be possible for authors to preview what that will look like in either case
refs https://github.com/TryGhost/Team/issues/912
- The membersApi variable can be in uninitialized state. It should be accessed through membersService getter to make sure it's always correctly referenced
refs https://github.com/TryGhost/Team/issues/935
The problem was incorrect operator precedence when multiple statements existed in the filter original filter when we transform it to enforce `subscribed:true` before sending.
- free only - subscribed:true+status:free - no issue
- paid only - subscribed:true+status:-free - no issue
- all - subscribed:true+status:-free,status:free - the ,status:free part is treated as a separate OR statement meaning the subscribed:true is not applied to it and free members that are unsubscribed will receive the email
- extracted the filter transform into a separate function so it can be unit tested
- updated the transform to use `()` for operator precedence, eg: `subscribed:true+(status:-free,status:free)`
- used transform function in `addEmail()` and `getEmailMemberRows()`
- fixed `sent/send` typo in error message
refs d60d348c88
- When the import triggers a background job the meta response should contain no data otherwise the client can mistake it for completed import
refs a7dd7bb64b
- The error was introduced in the refed commit. Object.assign method only works when the first parameter is an object otherwise it fails.
refs https://github.com/TryGhost/Team/issues/912
- Exposing a single method out of the service makes the API surface smaller - more readable.
- Additionlally having a wrapping method in service will be helpful for other triggers that are going to be executed in later iterations
refs https://github.com/TryGhost/Team/issues/907
The theme middleware makes several calls to the content api in order to
populate global theme data for use in templates. By adding this
middleware after the static theme files, we remove redundant calls.
refs https://github.com/TryGhost/Team/issues/916
- The constructor API should have as small of a surface as possible, there's no need to pass around whole ghostMailer instance
refs https://github.com/TryGhost/Team/issues/916
- The constructor API should have as small of a surface as possible, there's no need to pass around whole settingsCache instance
refs https://github.com/TryGhost/Team/issues/916
- The refactor was done follow the DI Constructor pattern with single options Object parameter
- It didn't make sense to have a "config" object inside of options object containing just one property
issue https://github.com/TryGhost/Team/issues/614
- The feature flag was called `oauthLogin` instead of simply `oauth` to avoid clashes in the frontend `feature` service as it is merging the config and labs properties.
refs https://github.com/TryGhost/Team/issues/916
- While investigating members importer related codebase this legacy module was spotted. It's not used anywhere and doesn't serve any particular purpose.
refs https://github.com/TryGhost/Team/issues/664
The new WellKnownController and middleware handles exposing a JSON Web
Key Set for us.
In order to serve the keys on /members/.well-known/jwks.json without a
trailing slash, we must mount the wellKnown middleware before the
frontend.
refs 2f1123d6ca
Usage of the raw Error class has been deprecated in favour of our own
errors, which are more descriptive and have built in HTTP status codes.
This also updates the same errors to use @tryghost/tpl for the error
messages, which is the new pattern we are following in order for us to
deprecate the i18n module.
no issue
- i18n is deprecated in favour of `tpl`
- normalized method syntax so `add` matches the rest of the controller's methods (fixed a complexity warning but was not the primary intention)
refs 2f1123d6ca
refs 6f1a3e1774
- As per refed commits, we are removing deprecated use of `new Error()` in the codebase
- Exposed few internal from commands module methods for easier testing, otherwise it was turning into neverending mocking show
refs https://github.com/TryGhost/Team/issues/696
The userAuth spam prevention logic is reused, but a new piece of
middleware has to be created so that we can use a custom lookup key to
conatin the member email.
We must also add json parsing middleware to the route so that the brute
middleware can read the email.
The express body-parser middleware handles multiple instances on the
same route, so this doesn't cause problems upstream.
https://github.com/expressjs/body-parser/blob/1.19.0/lib/types/json.js#L99-L103
closes https://github.com/TryGhost/Team/issues/743
Unlike tags, a label has a unique constraint on its `name`. So saving a new label on member with the same name as existing label fails with error due to unique constraint error.
- adds id for new label to match existing label if they are the same name, which avoids creating a new label
refs https://github.com/TryGhost/Team/issues/880
The aggregate for `paid_delta` was incorrect as it did not handle the
case where an event went from paid->comped or from comped->paid. This
resulted in an overcount for paid members.
refs https://github.com/TryGhost/Team/issues/860
- Slow unit tests cause longer waiting time to deliver code to main. Before this fix the test was taking a whooping 6s on average
- The main cause of the delay was a downstream's package (got) default retry logic that was taking up a lot of time bypassing the retry logic present in the default scheduler itself
refs https://github.com/TryGhost/Team/issues/756
When running the tests it was possible for this middleware to be
instantiated before the settings cache, resulting in an undefined
'session_secret' setting being passed. This would cause tests to fail.
Tracking this down proved difficult, so the fix was made here, by
instantiating the express-session middleware only once a request needs
to use it, we can be confident that Ghost has completely started.
refs 2f1123d6ca
refs 6f1a3e1774
- As per refed commits, we are removing deprecated use of `new Error()` in the codebase
- This bit cleans up the rest of `new Error()` usage in MEGA service
no issue
- Exposing internal methods out of the module is a non-standard practice. Adding `_` prefix allows to signal that this method is not for general use.
- When mega is refactored into a proper class this method will become exposed anyways
refs 2f1123d6ca
refs 6f1a3e1774
- As per refed commits, we are removing deprecated use of `new Error()` in the codebase
- This bit cleans up `new Error()` usage in MEGA service
refs 2f1123d6ca
refs 6f1a3e1774
- The use of new Error() has been deprecated. Refactoring the migration to use `createIrreversibleMigration` made most sense to have central error handling for migration which are not meant to be reverted.
no issue
- This mehod has an important `tableSpec` parameter which MUST be present when creating a new table migration. Having a description in form of the JSDoc somewhat helps this cause
- Next best improvement would be throwing an error if the parameter wasn't present, but that would require a bigger refactor backporting all usages of `addTable` method
refs https://github.com/TryGhost/Team/issues/841
When using our development tooling Ghost should always start, instead of
exiting with an error. This check for the WEBHOOK_SECRET env var was the
primary cause of Ghost erroring in development, so it's been switched
with a warning.
refs: f9a3f7d955
- The test for overriding a theme (uploading a theme with the same name as the currently active theme) doesn't test the right codepath
- It incorrectly assumes uploading the same theme twice results in an override, but this is only true for the active theme
- This change splits the override test out into it's own test, and only tests overriding by changing the active theme first
- Also fixed a minor comment type whilst here
refs https://github.com/TryGhost/action-deploy-theme/issues/45
- added missing `throw error` in the `setFromZip()` catch which was hiding the underlying error when a theme uploaded and saved successfully but other code had failed
- fixed incorrect method name `activator.activateFromOverride` -> `activator.activateFromAPIOverride`
refs https://github.com/TryGhost/action-deploy-theme/issues/45
- added missing `throw error` in the `setFromZip()` catch which was hiding the underlying error when a theme uploaded and saved successfully but other code had failed
- fixed incorrect method name `activator.activateFromOverride` -> `activator.activateFromAPIOverride`
no issue
- In the current iteration of the gated email project, we are returning a null segment instead of returning the correct list of segmented users as a temporary measure. The expectation was to clear all segmented cards and it's now the case.
- This isn't really a "service" - it's a set of utilities for working with labs flags
- It's also required all over the place, and doesn't require anything that isn't shared
- Therefore, it should live in shared
- Replaced requiring SafeString all the way from the theme engine, with using express-hbs directly
- This is quite a big require, just for the safe string function, but without this we have to tie labs to our theme layer
- Also removed i18n and updated the jsdoc for enabledHelper
- The labs service can be moved to shared now!
- This isn't really a "service" - it's a set of utilities for working with labs flags
- It's also required all over the place, and doesn't require anything that isn't shared
- Therefore, it should live in shared
- Replaced requiring SafeString all the way from the theme engine, with using express-hbs directly
- This is quite a big require, just for the safe string function, but without this we have to tie labs to our theme layer
- Also removed i18n and updated the jsdoc for enabledHelper
- The labs service can be moved to shared now!
- This stops the mounting of the admin and frontend from being buried deep in express initialisation
- Instead it's explicit, which makes two things almost possible:
1. we can potentially boot the frontend or backend independently
2. we can pass services and settings loaded during boot into the frontend
- This needs more work, but we can start to group all the frontend code together
- Meanwhile we also need to rip apart the routing and url services to decouple the frontend from the backend fully
- BABY STEPS!
closes https://github.com/TryGhost/Team/issues/737
- without an explicit `width: auto` on images Gmail on Android will make not make the image responsive, instead it was keeping the 1200px intrinsic width of the image and shrinking other content around it to match
closes https://github.com/TryGhost/Team/issues/819
- adds guard for an empty buffer when reading file from storage for resizing, if a blank image is loaded then redirect to the original file
issue https://github.com/TryGhost/Team/issues/859
- Added invalidation to PUT /authentication/setup
- Added invalidation to POST /db
- Added invalidation to DELETE /db
- Added invalidation to GET /slugs/:type/:name
- Removed invalidation from PUT /users/:id/token
- This is a precursor to trying to split apart into:
- model events + webhooks system which makes sense
- frontend events which should be independent or removed
- maybe some concept of a settings manager that we can use in various places to bind logic 🤔
- other usages of events that should be refactored to not use events
refs https://github.com/TryGhost/Team/issues/856
- The default internal version of the API is expected to be the latest one available which is v4/canary at the moment.
- There will be more information posted in the referenced issue later around how to approach the "default version", for now it's just a change to make a small step into a right direction.
refs https://github.com/TryGhost/Team/issues/856
- There were two problems with routes.js files defining API routes:
- First, the module requires wen too deep into the "api" module and used specific api modules directly. We have an "index.js" file which defines an API for whole API, it should be used as an entry point to anything to do with the API.
- Second, The naming was inconsistent between the routes.js files for "api", "apiV2", "apiCanary" - it is an extra maintenance burden to go on and change each "api" name when the new version is introduced. The only thing that should be changed within these files is a single line on very top that "requires" a specific API version like so: "const api = require('../../../../api').canary;" - way less maintenance to change that canary to v5 instead of doing an extra rename for all "apiCanary" to "apiV5"
refs: https://github.com/TryGhost/Team/issues/831
- This ultimately fixes the index.js file
- It also makes it super clear what methods in the themeService are used by the API, and which are part of the service loading logic
- It also moves the activate and init function into a single file in a way that highlights they are very similar
- They are also very similar to what happens in storage.setFromZip but that code is mixed up with storage code at the moment
- This is a slightly weird thing, but the intention is to highlight that there are 3 different code paths that can activate a theme
- Ideally we want to unify all the codepaths more, but for now this at least helps us see what is happening where
- All the code for creating these errors is now replaced with a single function
- This is useful DRY as it helps make code more readable
- This gets rid of the override of the error type to ThemeWorksButHasErrors - which is both weird and afaict not used anywhere
refs: 076ad99593
- as of 076ad99593 we no longer use the error property of the active theme anywhere
- cleaning up and removing this usage reduces the code pathways and makes the init fn a bit clearer
- We use bluebird inconsistently throughout the codebase now
- The original reason why we needed to use it so heavily was so that all promises returned had the bluebird behaviour, including catch predicates
- Most other usage is explicit, but this is really hard to detect and hasn't made it to standard promises, so we should get rid of this pattern
- The router bootstrap is no longer allowed to fetch it's own settings, but rather is passed them
- This moves the call to the site routes.js file, which isn't much better but it's a start
- The goal is to always pass these in from the boot process, or from the bridge reloader
- Reduced the number of levels in our debug naming in the frontend
- Unified components like "themes" and "routing" under one name
- Should help to make debug slightly more useful again
refs https://github.com/TryGhost/Team/issues/726
- The refed feature got broken during the refactors. Even though this area is covered by unit tests the "this context" testing should probably done on an integration test level, which we don't have a clear pattern for just yet
refs https://github.com/TryGhost/Team/issues/790
The schema validations are used at the model layer to validate inputs
and need to be updated in order for us to reintroduce the 'comped'
status.
refs https://github.com/TryGhost/Team/issues/790
Since version 4.6 the 'comped' status has not been used. Any members
which were given complimentary plans since then will have had a `status`
of 'paid', and therefore the corresponding members_status_events row
would have a `to_status` of 'paid'.
This migration is designed to fix these members_status_events rows by
ensuring that the last (chronologically) members_status_event row for a
comped member has a to status of 'comped'.
Unfortuantely this migration loses information which makes writing a
perfect inverse migraion impossible. Alternative down migrations were
considered, but these would lose further information.
refs https://github.com/TryGhost/Team/issues/790
In order to track when a member was comped, as well as to differentiate
paid members from comped, we are reintroducing the 'comped' status. This
migration will updated members with a Complimentary Stripe Subscription
to a status of 'comped'. It is essentially a reversal of the 4.6
migration.
no issue
- incorrect syntax was used in the error handlers inside of the `for` loop, by using `return` when logging the whole for-loop was aborted whereas we want to log and continue processing the rest of the items
refs https://github.com/TryGhost/Team/issues/853
A refactor of `urlUtils` usage in 4.6.1 left a buggy 4.0 migration that did not transform URLs inside of mobiledoc cards. Anyone upgrading from 3.x to 4.6.1-4.8.4 would end up with inconsistent URL formats and potentially broken images.
- fixed 4.0 migration by passing our mobiledoc cards list in when transforming mobiledoc urls
- added a new migration that re-applies the missed URL transforms and content re-generation for any site that did a 3.x upgrade to a buggy 4.x version
refs 8a1fd1f57f
refs 5584430ddc
- The change to async/await in the original commit 558443 was causing problems in downstream dependencies (create-error package) where it was loosing a context of "this". It's not a direct dependency so I didn't go yak shaving into where exacly the context is lost.
- The fix to keep a correct context of "this" was sticking to an existing pattern using regular function returning promises. Once we need to redo them into async/await we can investigate if there's a way around create-error's context prolbem
closes https://github.com/TryGhost/Team/issues/817
refs 6d083ee00e/packages/bookshelf-pagination/lib/bookshelf-pagination.js (L256)
- The 500 error is not the best we can do in this situation and throwing a 400 just like we doo in a referenced commit would keep the convention
- The underlying problem of the bug is bigger - we allow the fields named the same way as relations to leak into the db query and that causes an incorrect SQL syntax. It's a bigger problem which would need a separate, holistic approach
refs https://github.com/TryGhost/Team/issues/849
As part of work for segmented post access with multiple products, the custom filter for post access is stored in `visibility` field on posts but passed with `visibility_filter` property on API. This change -
- updates input serializer of posts to transform `visibility` and `visibility_filter` properties correctly
- updates output serializer for canary to transform and send `visibility_filter` attribute with filter value
- updates output serializer for v3 to ignore any custom filter on visibility and return `paid` instead as v3 didn't have a concept of custom filter
refs https://github.com/TryGhost/Team/issues/849
Custom post visibility (behind alpha flag) is added to the API using new `visibility_filter` attribute that stores the custom filter. This change -
- updates validator for visibility to check new `visibility_filter` property
- cleans usage of i18n in favor of tpl
refs https://github.com/TryGhost/Team/issues/727
- The version was forgotten to get a bump durin g 4.0 release. The API version used by update check should be the same as internal default.
- Because the current internal default is mistakenly set to v3 API it's still not optimal but will need a holistic solution in the future
no refs
- adds `price` data on subscription from related `stripe_price` on updating a member via frontend
- removes inconsistency between `GET` and `PUT` data for logged in member on a site
refs https://github.com/TryGhost/Team/issues/828
- Previous method had a bug where it didn't take into account cases when onlya single card with a segment filter has been used leaving the members not covered by that filter without an email
refs https://github.com/TryGhost/Team/issues/828
- Before sending out batches with members we need to partition all members based on the segment they belong to. Special segment "unsegmented" is used in case none of the segments used in the emal cards cover part of the members set (for example only free members card used when emailing all members)
refs https://github.com/TryGhost/Team/issues/839
It's now possible to set alt and caption for post feature images using `feature_image_alt` and `feature_image_caption` fields on a post resource.
- `feature_image_alt` - plain text, limited to 191 chars (alt text is not recommended to be longer than 125 chars, screen readers may cut the description off at that point)
- `feature_image_caption` - basic HTML, limited to 65535 chars
Alt and caption will be automatically used inside of newsletter content, for your website content make sure your theme is updated to use the v4 API and make use of the new properties.
---
- removed `featureImageMeta` labs flag
- This is part of the quest to separate the frontend and server & get rid of all the places where there are cross-requires
- At the moment the settings cache is one big shared cache used by the frontend and server liberally
- This change doesn't really solve the fundamental problems, as we still depend on events, and requires from inside frontend
- However it allows us to control the misuse slightly better by getting rid of restricted requires and turning on that eslint ruleset
- requiring lib/common/events makes the settings cache tightly coupled to the server
- moving this up to settings index means the cache itself can be moved to a shared component/moved out of Ghost
- the index then becomes the settings manager
- questionable whether the event listeners & updater part of this shouldn't be part of a manager, independent of the actual cache 🤔
refs https://github.com/TryGhost/Team/issues/828
- We need a way to recreate a filter that was used to create an email content for specific email_recipient. By saving member_segment value for each email_batch we can traverse back to the filter that was applied during email creation.
- shutdown removed listeners, which should really be done before adding them anyway!
- reset sets the cache back to an empty object, which was already done by init
- merge these into one reset function that fully resets the cache
- all instances of shutdown were called before an init call, and now called during init, therefore these can be removed
- acceptance utils had an instance of calling shutdown and reset together as part of stopping Ghost, reworked that to be clearer
refs https://github.com/TryGhost/Team/issues/828
- When sending email batches out they need to be created without mixing different member segments. This allows for easier reasoning about what data has been sent out to each specific email recipient
- Modified email batches to chunk based on segments defined in the HTML content of the post
refs https://github.com/TryGhost/Team/issues/828
- When detecting email segments and later creating a member filter out of this data we only care about unique segments otherwise we'd be creating multiple batches with the same segment filter
refs https://github.com/TryGhost/Team/issues/828
- This is experimental segment extraction logic, more to follow. Alllows to extract arrays of email segments used in the email's HTML content
- The main goal here is getting this settings related code out of the routing service as it really doesn't belong there
- This settings file is used purely by the API to get and set files - its not really anything to do with actual routing
- This file calls out to the bridge to do a reload, which helps decouple slightly
- More refactoring is needed to get rid of the urlService dependency
- Note this file is really similar to the redirects one, it would be good to merge them
- At the moment the bootstrap.start method asks the settings service for its settings
- This couples the routing and settings services together - when maybe we want to use a different method to generate settings
- By passing the settings to the routing service at the right time, we open up possibilities for refactoring
- Allows for slight decoupling of API and frontend with route settings being updated
- Activate theme now calls the same codepath to reload the frontend
- Yet another step on the path to make it possible to init/reload/run the frontend independently from the server
refs https://github.com/TryGhost/Team/issues/806
This relation sets up the ability to both read and write relations via
the Product model, allowing us to expose benefits via the Admin Product
API.
refs https://github.com/TryGhost/Team/issues/806
This is the model to represent the Benefit resource stored in the
`benefits` table. The `onSaving` method has been copied from the Tag
model and ensures that we have a unique slug.
fixes https://github.com/TryGhost/Team/issues/834
- see referenced issue for context
- there are times when `parentPort` can be null and the job crashes
because `parentPort.postMessage` won't work
- this commit adds guards around `parentPort`, or moves code inside
existing guards, to protect against this
refs https://github.com/TryGhost/Ghost/pull/13091
- When the job is run under Node v14 with SQLite DB the parentPort is `null` in some of the environments. The guarding code protects from the job crashing in such situation.
- The most probable cause is running btrheds with `BTHREADS_BACKEND = 'child_process';` configuration for SQLite. Should be fixed once https://github.com/mapbox/node-sqlite3/issues/1386 is properly resolved
- Makes the logic for determining the admin and frontend vhost args independent and easier to test
- Moved the tests to specifically test the vhost utils & removed proxyquire as a dependency
- We want to breakdown the current parent app into the existing core/app.js and boot code, allowing us to decouple the backend and frontend further
- This is all part of the refactoring to separate server and frontend completely
fixes https://github.com/TryGhost/Team/issues/818
- validation on query parameters should be wrapped in `options` within
`validation`
- this is missing from the theme install API endpoint so we don't force
the parameters to be passed in
- Ghost throws a 500 if `ref` is not supplied because following code
assumes we've checked the existence
- this commit wraps the two query parameter validation statements in
an `options` object to ensure they exist - Ghost returns a 422 if
missing
refs d9ddc2db6a
refs https://github.com/TryGhost/Team/issues/754
- The tests were written with falsy assumptions and validation added in refed commit have uncovered it!
- A secondary issue touched here is additional JSON object serialization that is used in the "input serializer" -d9ddc2db6a/core/server/api/v2/utils/serializers/input/settings.js (L107-L110)
- The additional stringification should not be there at all. It covers for a mistaken internal use of Settings API where raw objects are passed around instead of serialized JSON Objects (see commets left with this changeset for details)
refs https://github.com/TryGhost/Team/issues/754
refs a7dec233ba
- Additional validation protects from problems like the ones in refed commit from even getting through to the database.
- At the moment only used notificatons and couple more settings to ensure they are arrays when passed into the API. This is to avoid making big change in settings straight away - this is a problematic area which needs cautious approach.
- Ideally in the future the list of settings to check the "array" type (and other types) should be automatically generated based on the default-settings.json (or whatever way we define settings in the db a that moment)
- There's an ugly code-tripplication going on in this change. This is a separate topic that will be addressed once we work on API cleanup.
refs https://github.com/TryGhost/Team/issues/804
The associative table is used to implement the many-to-many relationship
between Products and Benefits. The `sort_order` column is needed because
a product's benefits should be orderable by an admin.
refs https://github.com/TryGhost/Team/issues/804
Benefits are tag-like resources which will be associated with Products.
The first iteration just requires a name for the benefit, which will be
stored as plaintext.
refs 188de00489
- this fix was incorrect - the function should have been on the
prototype but I'd moved it over incorrectly into the static class functions
- this commit moves `defaultColumnsToFetch` to the prototype functions
and reverts the referenced commit back to `this.prototype` as expected
- this wasn't including the custom columns from the `post` model, which
was causing tests to fail
- pro tip: run tests!
refs https://github.com/TryGhost/Team/issues/754
closes https://github.com/TryGhost/Ghost/issues/13088
refs a7dec233ba
- The corrupted data recovery mechanism for notifications is needed to be able to fix the data stored in `settings` table under `notifications` key. There was no validation in place, which has caused some instances to store data in unreadable/writable state
- The recovery mechanism is in place to avoid adding migrations every time we spot a broken notifications data (will be fixed by validation soon).
- The notification data is also NOT critical but valuable for system functioning properly, that's the reason why the data "healing" happens in less secure "fire-and-forget" way
- The referenced commit is where the "bigger" problem that was causing the data corruption was at. This change is a "cleanup" after what has happened there - storing Ghost error object in `value` for `notifications` key
refs a457631a20
- `defaultColumnsToFetch` was moved to the CRUD plugin in the referenced
commit, which makes it a function on `this` instead of `this.prototype`
- this means the function doesn't exist and Admin throws an error when
you start typing in the search bar because the API 500s
- this commit switches it to `this.defaultColumnsToFetch()`
refs https://github.com/TryGhost/Team/issues/808
- see referenced issue for context, but turning this function into
async-await seems to have broken error handling when deleting things
that don't exist
- i'm really not sure why - but my running theory is that it's something
to do with Bluebird Promises vs native Promises
- this should keep the same functionality until I can investigate what
is going on
fixes https://github.com/TryGhost/Team/issues/809
- Bookshelf won't throw a `NotFoundError` unless `require=true` in the
options
- this is present in most other API endpoints, so it's just simply
missing from the snippet one
- without this, Ghost will crash with a 500 saying `Cannot read property
'destroy' of null`
- this commit adds `require=true` to the destroy options for both the canary +
v3 endpoints
refs: #12808
- we need to use the uuid, not the id, so that e.g. unsubscribe urls are set correctly
- this is only for test emails, but it's still important to be able to test things fully!
refs https://github.com/TryGhost/Team/issues/754
- The logging wasn't working for the update check when run from the scheduled job. Fixed package method signature to allow for "logging" parameter. The sideeffect of this change was such that we need to instantiate a new instance of the UpdateCheckService on every method call to differentiate the call from within the code (controller) or from the job level
- Also added an await before returning the check method call as it didn't execute properly on the job level - the `await` wasn't waiting for the update check to actually do it's job!
issue https://github.com/TryGhost/Team/issues/750
- Only accessible by admins
- Resets all staff users' passwords and prevents them to log-in
- Sends them a reset email password to give them back access to their account
- Closes all existing staff user sessions
refs https://github.com/TryGhost/Team/issues/765
This supercedes the `complimentary_plan` flag, as it is more precise
because it determines _which_ product(s) a member has access to. Because
of this, if the `products` column is present the `complimentary_plan`
column is not used.
refs https://github.com/TryGhost/Team/issues/765
Since Members can be given complimentary access to one of many products,
we must include which products a member has access to when exporting
from Ghost. This will allow us to reimport without losing information.
refs https://github.com/TryGhost/Team/issues/765
As part of the multiple products feature, we're not longer using Stripe
subscriptions to denote Complimentary access, instead we're linking
members directly to products. Here we update the importer to follow
suit, so long as the flag is enabled.
refs https://github.com/TryGhost/Team/issues/754
- This is a minor cleanup. There should be no logic in the boot.js file other than calling services to "initialize themselves"
refs 474e6c4c45
- The method was not easy to understand after skimming through it.
- As we are working on developing a similar pattern for upcoming similar featured created a basic test suited to see input/output relation clearly
no issue
- idex.js files are meant to expose the API of the module and not contain code
- Next step would be reworking the code to use class/injection pattern
refs https://github.com/TryGhost/Team/issues/793
New settings added for newsletter customisation options:
- `newsletter_header_image` - `null/"$url"`
- `newsletter_show_header_icon` - `"true/false"`
- `newsletter_show_header_title` - `"true/false"`
- `newsletter_title_alignment` - `"center/left"`
- `newsletter_title_font_category` - `"serif/sans_serif"`
- `newsletter_show_feature_image` - `"true/false"`
`newsletter_show_header` has been dropped because the same functionality can be achieved by setting both `newsletter_show_header_icon` and `newsletter_show_header_title` to `false`
---
- migration to convert and delete `newsletter_show_header` setting
- removed `newsletter_show_header` from default settings to ensure it doesn't get re-created
- replaced main labs template and template settings generation with the labs template
- deleted labs template
refs https://github.com/TryGhost/Team/issues/768
- `portal_products` stores list of products available in Portal
- adds new `portal_products` setting to default settings
- adds migration to populate `portal_products` with current product so its available by default
- update tests
no issue
- when feature image redesign flag is enabled add the caption under the feature image when available
- adds extra class for feature image so spacing can be adjusted when the caption is present
no issue
- `setId` is only used within the `events` plugin and it makes sense to
keep code together
- we don't lose anything by putting it here, but it should make it
easier to test in the future
refs https://github.com/TryGhost/Team/issues/748
This updates the @tryghost/members-api MemberRepository to stop ignoring
the `products` data passed to write operations, and to attach products
directly to members. As this logic is part of a new feature, we are
maintaining existing functionality by deleting the products data when
the feature flag is not enabled.
This functionality allows us to give members complimentary access to a
product without needing to use a Stripe Subscription internally.
no issue
- `formatOnWrite` doesn't override anything in Bookshelf but we use it
within the `override` plugin and sub-models may override it, so it's
easier to keep these things together
no issue
- we were only importing the `db` to access the `knex` instance, but
we can get this through the Bookshelf instance
- switches to pulling out `knex` from Bookshelf so we can remove the
remaining local require
no issue
- this commit extracts code relating to bulk DB operations into a
separate plugin
- it __could__ go into the CRUD one but these operations are a little
more involved
no issue
- this commit extracts event related code from the Base model into a plugin
- in particular:
- events initialization
- the `on*` events
- `emitChange` - I'm not sure about this one but it __is__ event
related
no issue
- this commit extracts code related to Actions from the Base model into
a separate plugin
- `api-key.js` contained the exact same helper function as the Base
model so that has been de-duplicated
no issue
- I'm working on pulling apart the base index.js and this code is
specific to setting up Bookshelf + the plugins, which is pretty
contained and can stay in one file
- it only has one local require so it might be a good candidate for
extracting out of Ghost in the future
refs https://github.com/TryGhost/Team/issues/775
As we currently do not delete canceled subscriptions and they are
exposed via the API, this functionality has been added to the
editSubscription controller method under the PUT HTTP method.
The cancelSubscription method in @tryghost/members-api was updated to
handle deleting by member id
- Part of the effort to split Ghost down into smaller, decoupled pieces
- Moved out our internal validator tooling to a separate library
- Replaced all usage of our own tooling and validatorjs directly with @tryghost/validator
- Removed the validatorjs dependency and removed the renovate pin
- This gives us a consistant, smaller, clearer public API for validations
- It will eventually be used on Ghost Admin too
- This way we can start getting up to date with validator whilst not increasing build size
no issue
- we're going to pull this out into the framework monorepo but
refactoring it here first makes it a lot easier to extract without
losing the history
no issue
The only pieces of Ghost-Ignition used in Ghost were debug and
logging. Both of these modules have been superceded by the Framework
monorepo, and all usages of Ignition have now been removed, replaced
with @tryghost/debug and @tryghost/logging.
no issue
- we're going to pull this out into the `framework` monorepo but
refactoring it here first makes it a lot easier to extract without
losing the history
- note: this is very temporary and will be extracted soon
- renamed our internal validation library to "validator" - which is the same as the tool it wraps
- updated the public api so that validator methods are directly exposed
- this will make it a drop-in replacement for validator-js
- in turn, this allows us to pull this out into @tryghost/validator, and use our own wrapper instead of the 3rd party library
- General code cleanup
- Removed unused notContains rule
- Swapped custom empty rule for builtin isEmpty rule
- Dropped usage of .extend on validator, as this was removed 2 years ago!
- This will allow us to upgrade the validator dependency to a much newer version
- Changed our internal validator module to only expose the functions we use.
- This gives us a clearer Public API
- It makes it easier to see if we are affected by changes in validator
- It's still easy to add another validator, we just have to update what we require
- We can potentially use this to make smaller builds esp for client-side usage
- Once ripped out into a module we can use ES imports :D
- Rejigged and _slightly_ improved the tests
no issue
Part of the effort to split ghost into smaller, decoupled parts. The
@root-utils package lets us avoid hard-coding a path to package.json,
and means that the ghost-version.js file could eventually be moved
into a separate module.
This commit uses a patched version of @tryghost/root-utils which
checks for the existence of a `current` directory, as used in
Ghost-CLI. Since this is very specific to Ghost and Ghost CLI, there's
a new method called "getGhostRoot" for this purpose.
refs:
- cf15f60085
- dd20cc649b
- ccf27f7009
- abf146d61f
- 2b54c92a14
- bb029a53f6
- 95bd7ee675
- 9018b4df22
- df01a6e5f4
- d313726b34
- these plugins were in a state where they were independent enough to be
pulled out into their own packages, which is what we did in the
referenced commits above
- each package is named like `@tryghost/bookshelf-<plugin>`
- to avoid requiring multiple packages into Ghost, we've also created a
wrapper package called `@tryghost/bookshelf-plugins` which re-exports
all these plugins, so the changes in Ghost are very simple - dbebdd43b5
- this commit deletes the plugins + tests, and replaces with our new
package with some minor code changes
- This is super specific code relating only to validating passwords.
- It's needed as a shared validator as we use other funnels to help people setup Ghost on Pro, but currently it's hard-baked into Ghost
- It's also not the greatest code. It'd be nice to be able to rework it and know that would automatically update everywhere passwords are set
- This is a really specific piece of code related to validating models against our internal schema.js format
- This doesn't make sense without a schema.js file
- It does depend on the internal validator and validate tools - but those are used elsewhere too, and can reasonably be moved out of the codebase
- I don't see schema.js moving out of the codebase any time soon. We can move the validator but it would be a class that requires schema via DI
- For now my focus is on getting the data/validation tooling separated and making clear sense
- Improving data/schema can come later :)
no issue
- `options` is not a correct type, so changed it to `Object` - maybe we
could introduce an `options` type at some point
- also fixed another case of incorrect subtype extraction from
`bookshelf`
no refs
- adding/changing products needs cache invalidation header otherwise frontend endpoints like `/members/api/site` use cached product data
- adds cache invalidation for both add and edit endpoints for products
refs d783a8d2d4
- we're removing i18n from Ghost core because it no longer meets our
needs
- this switches out i18n in the base Bookshelf model for our
`tryghost/tpl` package with a `messages` object of strings sprinkled
through the code
no issue
- eager-load: turned param import into typedef for reusability and fixed
attribute typing
- pagination:
- removed typing on helper function object - this was incorrect and
tsserver can pick up the real types a lot better, so removing it
reduces maintenance overhead
- `fetchPage` actually returns a Promise, so this fixes the typing
on the docs
- The data/validation module is made up of several loosely related things with lots of dependencies
- Separating out the various components makes it possible to see what's what, and importantly what has complex dependencies
- validator + validate probably go togetheri in an external module, the other two files should probably have their own homes in related areas of ghost e.g. schema -> data/schema/validate.js
no issue
Part of the effort to split ghost into smaller, decoupled parts. The
@root-utils package lets us avoid hard-coding a path to package.json,
and means that the ghost-version.js file could eventually be moved
into a separate module.
no issue
- the `Bookshelf` type wasn't being imported anywhere and editors were
showing warnings for the missing type
- also fixes use of `Bookshelf.Model` - this doesn't work if we declare
`Bookshelf` using a `@typedef` and the preferred syntax is using an
array index
- note: it still complains because we're calling functions that are only
declared in our custom Bookshelf Model but this is a step in the right
direction
no issue
- i18n is eventually going away in Ghost so we want to remove uses of it
- Bookshelf plugins are also getting extraced out of Ghost so we need to
remove all local requires
- i18n is being replaced by inline templating with strings stored in the
`messages` object
- this commit switches out the use of i18n in the Bookshelf plugins and
replaces the templating function with our `@tryghost/tpl` package
refs https://github.com/TryGhost/Team/issues/770
We want post feature image functionality to better match what's available inside the editor, to do that we'll need somewhere to store alt and caption meta data. `posts_meta` chosen because even though we want to make this generic for other tables in the future those tables also have a `feature_image` (or closely related) field.
- updated schema with new columns
- added migration to create columns
- cleaned new columns from API output
- not output on v2/v3
- conditionally output on v4/canary output based on labs flag
- bumped `@tryghost/admin-api-schema` to allow new columns through in canary API requests
- silently clean properties from input when labs flag is disabled
- updated acceptance tests so they fail if `admin-api-schema` is not letting the new fields through
no issue
`post.clean()` implementation was expecting a flat structure representing final API output but was being called before the flatten operation for `posts_meta` meaning the structure looked like `attrs.posts_meta.property` instead
- adjusted order in output serializers to call `clean()` after flattening the `posts_meta` object
- in `v2` output serializer, moved removal of properties from the serializer into `clean()` for consistency
no issue
Shows impact of new code behind labs flags through the existing acceptance/regression tests. Allows for existing tests to be updated to match new behaviour rather than requiring separate tests where individual flags are enabled. Should result in minimal test updating once code reaches GA.
- adds a forced `'labs:enabled'` fixture op that edits the `labs` setting to enable all flags then restarts the settings service to pick up the new setting
- modifies labs service to not remove ALPHA_FEATURE labs settings when running in a testing environment
- The underlying package-json package has had i18n ripped out using the new tpl utility instead
- It's also then been refactored to not be a class that needs instantiating
- This means it can be required directly and its public interface methods used where needed
- This is a much nicer, neater pattern for what is a mature utility library :)
- Traditionally all of Ghost's public-facing text was written in British English
- We're changing that to US English because that's more common
- US English should also be used in code e.g. properties are called color not colour
- most of these changes are in comments, but I've changed them so that we have US English in front of us always
- fixed a few other typos I noticed whilst there
refs https://github.com/TryGhost/Team/issues/772
- When the feature is introduced into Ghost at it's first lifecycle stage - "alpha" the rule is to have a "enableDeveloperExperiments" flag along with labs toggle turned on before it's usagble in the codebase
- The changeset introduced a "ALPHA_KEYS" concept which should allow distinguishing alpha flags from beta flags.
- We are going to get rid of the internal i18n tool because it doesn't solve a real use case
- Instead, we have a new tpl utility that does basic string interpolation
- This pattern will make it easier for us to decouple the codebase, and the new tool helps to keep the refactor surface area really small
- This is the first example of using the new tpl helper, so it also adds @tryghost/tpl
refs e17f5004cc
In case of Stripe disconnect, it was possible that the product table still contained reference to monthly/yearly price id while the price itself isn't present in the DB. As part of Stripe disconnect reset, this also resets monthly/yearly price id for product.
closes https://github.com/TryGhost/Team/issues/724
closes https://github.com/TryGhost/Team/issues/739
Currently, site owners are allowed to disconnect Stripe if they don't have any active subscriptions for a member. On disconnect, all stripe related data for the old account in DB should be cleared as using Stripe id for old account can cause weird failures due to incorrect Stripe key being used. This was also causing site owners to not be able to create new prices after connecting to new account as it ended up using old stripe product id which failed on Stripe request.
no refs
In case of Stripe disconnect, its possible that the product table still contains reference to monthly/price id while the object itself isn't present in the DB. In this scenario the stripe price returned is empty object instead of `null` , which then passes down empty object in the API that causes clients to fail if they just check existence of stripe price. The fix returns `null` value for monthly/yearly price in case it has no reference and is empty object.
no refs
Monthly/yearly price values on a product can be `null` when stripe is not connected, this change handles the prices passed to Portal settings to ignore null prices in the array.
no-issue
The default include values are empty arrays which are not falsy, so the
boolean OR operator would never use the second operand. Instead we
concatenate the options together so that the API can use all of them.
no-issue
The Frame object colocates the query, params & options data under a
single options property, this is not the case for the "original" data
however, which means that we need to explicitly check individual
"original" properties. We do not expect the `include` option to be used
as a param so that has been left out for now.
This reverts commit ea9a83d444.
refs https://github.com/TryGhost/Team/issues/755
- the default value for `show_header_icon` is `true` but if there's no publication icon set then it should be read as `false` when rendering the email
refs: https://github.com/TryGhost/Team/issues/759
- wired up a matchHelper feature flag & used the labsEnabledHelper tool to gate the helper
- added a first version of the match helper, which is intended to replace the has helper
- this is an experimental helper and may or may not make it to GA
- match is a simple comparison helper, right now it does a very basic equals or not equals comparison
- much more functionality is needed to reach parity with has
refs https://github.com/TryGhost/Team/issues/757
- The "type" value in settings is meant to be representing the data type stored in the "value" field. It was an overlooked bug in v4 API adding a mapper to group->type
refs https://github.com/TryGhost/Team/issues/755
Make use of the new settings in the email template when `enableDeveloperExperiments` flag is enabled.
- added header image output if set
- hide all header output if both show publication title+icon are disabled
- hide individual header output for title and logo based on individual settings
- add left-align and serif classes to title based on individual settings
- hide feature image when disabled
refs https://github.com/TryGhost/Team/issues/757
- There is no usecase for editing "labs" settings outside of canary/v4 API versions. Removing support for older versions makes the supported API surface smaller (easy maintenance).
refs https://github.com/TryGhost/Team/issues/757
- To safeguard from mise of a very permissing "object" value of the "labs" setting this change introduces an "allowlist" approach to filtering unrecognized labs flags
- Should allow maintainers to have a clear view of which labs flags are currently in use and manage them accordingly
refs https://github.com/TryGhost/Team/issues/757
refs https://github.com/TryGhost/Team/issues/332
refs ea6d656457
- We have a need a quick way to add features behind flags. The old way of "labs" is the quickest way to achieve this. It has ready tooling around it and well understood pitfalls. This change reintroduces "labs" group & key in settings table in the same shape it used to be (see reffed commit)
- Next step will be introducing very basic guard rails to protect from pitfalls previous implementation of "labs" had. This will include an allowlist based input validation for lab's object's data
- The labs being an "object" type is an EXCEPTION. Even though it's an antipattern we aim to move away from, for now it's the lowest impact solution that will unblock the use of flags in the system. A proper solution will come at some point.
refs https://github.com/TryGhost/Team/issues/718
The ids for default prices for a product is now stored directly on product model instead of on global settings. This change updates
- the products data sent to Portal to use list of products with their active monthly/yearly prices, as well as
- the prices data sent to Portal to use the prices of default(first) product
no refs
The product output serializer is removing the include data due to the includes being missing in frame options for some reason. This is a temporary fix that always allows the default includes as `monthly/yearly_price` to unblock the API, and we can revert it back to explicit request once fixed.
* 🐛 Fixed saving Members with Complimentary plans
refs https://github.com/TryGhost/Team/issues/758
Since 4.6 The Admin is using the comped flag again, rather than creating
subscriptions for zero-amount prices directly. With the `comped` flag
removed, the default state was for it to be falsy in the Admin, and when
saved would trigger the legacy comped flow, cancelling the subscription.
This reverts commit 57a176ff3d.
refs https://github.com/TryGhost/Team/issues/712
- Adds a Content API for products, which can be used by the theme-engine
middleware to populate the products data.
- Removes Stripe ids from Content API so they cannot be used to
initiate checkout sessions directly
- The monthly_price and yearly_price are used to create new prices, and
to set them to the default monthly & yearly price for the product.
refs https://github.com/TryGhost/Team/issues/728
- The code of update check has been extracted into it's own package as a part of TryGhost/Core monorepo. This commit is a cleanup of the leftover files
refs https://github.com/TryGhost/Team/issues/754
- This is fixing the root cause of an error being saved in `settings` table under `notifications` key. There needs to be a follow up to this fixing any possible instances that might have been affected byt the bug
refs 2e7d0a4e26
- the referenced commit pushed some refactors to the service but
`this.config` should have just been `config`
- Ghost was 500ing so this commit fixes the incorrect variable
refs https://github.com/TryGhost/Team/issues/728
- This is continuation of the previous commit. TLDR: Passing only the necessary parameter data makes it easier to reason about what dependencies the UpdateCheckService has to deal with
- Instead of passing in a whole GhostMailer instance passing only an email sending function, which again - makes things way more manageable to reason about
- The end of refactor, next will be a move of the UpdateCheckService into a separate module in tryghost/core
refs https://github.com/TryGhost/Team/issues/728
- This is continuation of the previous commit. TLDR: Passing only the necessary parameter data makes it easier to reason about what dependencies the UpdateCheckService has to deal with
- Burned ghostVersion module passing in vafor of just one additional config parameter. Now the module along with unit tests can be easily extracted out of the codebase!
refs https://github.com/TryGhost/Team/issues/728
- This is continuation of the previous commit. TLDR: Passing only the necessary API endpoint function makes it easier to reason about what dependencies the UpdateCheckService has to deal with
- Substituted a parameter with already existing 'siteUrl' config value. No need to duplicate work!
refs https://github.com/TryGhost/Team/issues/728
- This is continuation of the previous commit. TLDR: Passing only the necessary API endpoint function makes it easier to reason about what dependencies the UpdateCheckService has to deal with
- Limited urlUtils to only one function as that's all the UpdateCheck uses. Next step will be removing the function completely as and passing a 'blogURL' as a config value (way better readability this way)
refs https://github.com/TryGhost/Team/issues/728
- This is continuation of the previous commit. TLDR: Passing only the necessary API endpoint function makes it easier to reason about what dependencies the UpdateCheckService has to deal with
- There are 8 different configs that NotificationService depends upon it will need some further investigation around which ones are even needed anymore and the naming is not the best. To keep the time cap at bay leaving it at what it is.
refs https://github.com/TryGhost/Team/issues/728
- Passing only the necessary API endpoint function makes it easier to reason about what dependencies the UpdateCheckService has to deal with
- The instance initialization had to be moved insided the module's exports to resolve "models" module initialization failure
no issue
- we were attempting to read an image file to determine it's dimensions when no feature image was set. This wasn't a fatal error as it was handled gracefully and had no ill consequences but it was adding confusing errors to the logs
refs https://github.com/TryGhost/Team/issues/728
- This is a continuation of the test coverage for the UpdateCheckService.
- Covers scpecial cases of notification processing within Update Check
- The refactor inside the update check service was a convenience to get rid or the Bluebird dependency completely. Also, some minor preventative code added to avoid errors from referencing undefined objects
refs https://github.com/TryGhost/Team/issues/728
- In additions to easier tracking of "this" context in the unit tests it gets rid of unnecessary Bluebird's "reflect" method which was making unit test dependent on Bluebird's specific Promise implementation
refs https://github.com/TryGhost/Team/issues/728
- This is a first step before moving update check code into an outside codebase.
- The aim is to have a self-contained module which could be unit tested and have a very clear API
refs https://github.com/TryGhost/Team/issues/710
This allows us to fetch the default monthly and yearly price models for
a product model, which is important since we no longer want to expose
the entire list of prices, but just the designated monthly & yearly prices.
refs https://github.com/TryGhost/Team/issues/710
refs https://github.com/TryGhost/Team/issues/725
Products will now have a single monthly and yearly price which will be
used throughout Themes, Portal & Admin. These columns will be used to
track the current prices for each of them, and will update anytime we
change the pricing of a product.
Due to a circular table dependency we have not added a foreign key
constraint to the new columns, this will be handled at a later date. It
is tracked in issue 725 references above
commit 414938cfc7
- This reverts commit 414938cfc7.
- The tests fails so I'll wait for Naz to finish the ongoing update-check tests refactoring before upgrading the api version again
refs https://github.com/TryGhost/Team/issues/598
refs https://github.com/TryGhost/Ghost/commit/5cdf910e
As part of the changes to disallow sites with starting up without https when they are connected to stripe, the conditional missed the check for stripe connection. As a result we were erroring in boot sequence for all sites starting without https irrespective if they are connected to Stripe or not which is incorrect. This fixes the `init` check for members service to only error for non-https sites if they are connected to Stripe.
refs https://github.com/TryGhost/Team/issues/726
- When UpdateCheck service sends a notification with "type: 'alert'" an email goes out to admin users with the "message" content of the notification.
- This functionality is aimed to handling critical messages like urgent instance updates
- Next step will be getting as much of the update check code extracted into a "service" and then moved out of Ghost's codebase
no issue
- While working on https://github.com/TryGhost/Team/issues/726 have questioned some of the options that were passed along to the `send` method. Documented findings and refactored the code slightly while touching it
refs https://github.com/TryGhost/Team/issues/726
- These are minimal changes that I've done while reviewing the code inside the update-check module. There's more to come, only picked up the low-hanging fruit!
refs https://github.com/TryGhost/Team/issues/660
In case stripe price for a subscription is missing in `stripe_prices` table, it will cause the API to load members list to fail with 500 as we try to serialize the stripe price on member subscription using empty object. This fixes the guard against populating price object for missing data in DB.
Note: This is only a short-term fix till we add a proper fix to cleanup the DB in the subsequent release.
refs https://github.com/TryGhost/Team/issues/726
- These are minimal changes that I've done while reviewing the code inside the update-check module. There's more to come, only picked up the low-hanging fruit!
refs https://github.com/TryGhost/Team/issues/726
- Update check service is self contained and handles errors through logging internally. There is no visible upside to do the same logging in multiple places
no issue
- moved `config` and `site` API output generation to a `public-config` service allowing all API versions to use `publicConfig.config` or `publicConfig.site` in their query methods
- updated `config` and `site` API output serializers to use an allow-list that limits the data returned for each API version
no issue
Our server-defined `mobiledoc` object was required by `UrlUtils.cardTransformers` property to help set up a shortcut for url transform functions but that was breaking the independence of `UrlUtils` by crossing the shared/server boundary.
- `cardTransformers` is only needed for the `mobiledocToTransformReady` utility function that will only be used by the server
- removed `UrlUtils.cardTransformers` (and associated require) from our `UrlUtils` instance and updated the few areas the server uses `mobiledocToTransformReady()` to pass in the mobiledoc card objects directly as an option
refs https://github.com/TryGhost/Team/issues/694
- This refactor is not ideal but moves us closer to the desired form of class with injectable (and testable) parameters. Allowed to refactor the test slightly so at least we can check if schedulerd subscribed events work and if they trigger the adapter with correct data
- Ideally the api/model calls shoudl be abstracted away as well, but that's for another time
- Also got rid of completely pointless "adapters/scheduling" unit test. All it was checking was if the "init" method was called int the passe in object
refs https://github.com/TryGhost/Team/issues/694
- Only passing necessary data into the module simplifies it's interface and allows to decouple it further from model layer dependencies
- Note, also verified and corrected the return type of the auth token creating method
refs https://github.com/TryGhost/Team/issues/694
- This is a tiny step towards more decoupled scheduler's code organization
- Similar to previous commit, it's just code extraction
- Next steps will be injecting these modules as "init" function depencency" so we can test scheduling behavior in isolation
no-issue
The JWT library we used does not throw an error which can be used by
Ghost. So we need to catch and wrap it in our own errors from
@tryghost/errors.
refs https://github.com/TryGhost/Team/issues/635
This is to ensure we don't break migrations for any sites which have
imported external subscriptions which have an interval of 'week' or
'day'
The bump to members-api includes the handling of these intervals for
ongoing population of mrr events
refs https://github.com/TryGhost/Team/issues/610
- Before introducing a new test for the refed issue doing a linting cleanup. The result will be removing one of `File has too many lines ` lint warnings
refs https://github.com/TryGhost/Team/issues/598
Stripe Webhooks require SSL in production, and so we should not be
allowing connecting to Stripe in production mode unless the site is
running with SSL.
refs https://github.com/TryGhost/Team/issues/598
We now have several pre-conditions related to members which determine
whether or not Ghost is allowed to start. Rather than burying this
within the members-api module, we have now surfaced them to an init
method which can be called during the boot sequence of Ghost. This will
allow us to exit early and explicitly.
no-issue
Our linter now requires that files named index.js have less than 50
lines, so this renames the index.js file to service.js and reexports
service.js from index.js so that linting will pass.
refs https://github.com/TryGhost/Team/issues/693
Since we've got rid of the concept of Complimentary with the Custom
Prices work, we're removing the 'comped' status from members. This
involves a migration for existing members, a schema update for the
validation, and a bump to members-api to no longer use the 'comped'
status for new members.
We also update the aggregation of the MemberStatusEvent to consider the
'comped' status as 'paid', and that there are 0 'comped' status events
in the database.
We can consider a migration for this data in the future, either adding
new status events moving from 'comped' to 'paid', or by modifying
existing status events. However both of these are very difficulty to
write a down migration for, and might be best saved for a major version.
- @tryghost/members-api@1.7.0 is the version that includes the required
changes, however we have already bumped to 1.8.0 in Ghost
refs https://github.com/TryGhost/Team/issues/693
Since we no longer have the concept the "comped" we update the v3 API to
always have a `comped` flag of `false` - maintaining backwards
compatibility.
refs a4c78dbf19
Updates member data on edit to include products data when comped status is changed, as by default we don't include products data when member goes from free to paid subscription due to comped being added.
closes https://github.com/TryGhost/Team/issues/699
With custom products, saving a member with subscriptions on member detail page in Admin throws errors on console, though the save is successful. This breaks the Admin as user needs to refresh the screen again to get rid of error. This change -
- updates the response on member save to return `price` object in subscription
- updates tests
no issue
Keeping CSRF enabled there would prevent oauth from working as users are redirected from the provider domain to the /callback route, where they are logged-in
no refs
Filters active prices in Portal settings to only contain the selected prices by site owner in new monthly/yearly price id settings, ignoring all other prices for now.
no refs
Since backend now allows multiple prices but we want the prices to be currently limited to monthly/yearly on UI, we need new settings to store the current monthly/yearly price by the site owner. These settings determine the active prices shown in Admin / Portal for the site till we allow all custom products/prices again.
closes https://github.com/TryGhost/Team/issues/675
Outlook will display images at their native resolution if no `width` attribute is supplied. Content images were fixed a while ago but feature images would still render very wide and cause horizontal scroll and text size/alignment issues.
- modify `post.feature_image` and add a `post.feature_image_width` property before passing it through to the email template
- for Unsplash images we assume all images are larger than 600px so we change the URL to reference a 1200px image and set the image width to 600 (to keep images on retina displays crisp)
- for other images we probe the image to fetch the original dimensions and give set an image width of 600 if needed, if it's a locally-hosted image we update the URL to point at a max 1200px version
- updated email template to output a `width` attribute on the feature image `<img>` tag if it's set
no issue
- `getLocalSize()` is useful outside of the mobiledoc populate-image-sizes function
- expanded `ImageSize` class with new methods
- `getOriginalImageSizeFromStoragePath()` - takes the "original" image extraction and test from `getLocalSize()` and makes it more generally available
- `getImageSizeFromStorageUrl()` - takes the path extraction from `getLocalSize()` to make image sizes from local urls more generally available
- `getOriginalImageSizeFromStorageUrl()` - URL version of the new `getOriginalImageSizeFromStoragePath()` method
closes https://github.com/TryGhost/Team/issues/560
closes https://github.com/TryGhost/Ghost/issues/12870
The endpoint `/members/api/member/` is used by Portal for fetching member details on site load to setup different flows. The response from this endpoint for logged out member has now changed from 401 Unauthorized to 204 No Content.
Ghost API was previously returning 401 Unauthorized error for logged-out member as this seemed to be technically correct response for unauthorized access to membership features. This resulted in a lot of confusion for end users where visible 401 errors on console were perceived as errors in the script as well as caught by loggers as erroneous traffic. Also for an end user, in the context of visiting a website - the user themselves is not trying to gain access to anything so this becomes cause for more confusion.
After internal discussion, the endpoint - [SITE_URL]/members/api/member- now returns 204 No Content instead of 401 for logged out member, denoting server was able to process the request but did not find any associated member. This should avoid any unwanted error logging on Portal load on a site, as well as make Portal functioning more transparent for a site.
no-issue
When importing Members it is possible to have both the
complimentary_plan and the stripe_customer_id columns set, this can
result in unusual outcomes, for example when importing a customer with a
zero-amount subscription, they would end up with two "comped"
subscriptions, and there would be two "comped" prices in the database.
As we are deprecating the use of "comped" in favour of creating a
subscription with a specific price, we're updating the import to prefer
`stripe_customer_id` column, only using the `complimentary_plan` column
when it is the only of the two columns passed.
refs https://github.com/TryGhost/Team/issues/581
closes https://github.com/TryGhost/Team/issues/582
Emails can now be sent to members with specific associated labels or products by specifying an NQL string. We want to bring the same members segment feature to content by allowing `visibility` to be an NQL filter string on top of the `public/members/paid` special-case strings.
As an example it's possible to set `posts.visibility` to `label:vip` to make a post available only to those members with the `vip` label.
- removed enum validations for `visibility` so it now accepts any string or `null`
- bumped `@tryghost/admin-api-schema` for API-level validation changes
- added nql validation to API input validators by running the visibility query against the members model
- added transform of NQL to special-case visibility values when saving post model
- ensures there's a single way of representing "members" and "paid" where NQL gives multiple ways of representing the same segment
- useful for keeping theme-level checks such as `{{#has visibility="paid"}}` working as expected
- updated content-gating to parse nql from post's visibility and use it to query the currently logged in member to see if there's a match
- bumped @tryghost/members-api to include label and product data when loading member
refs https://github.com/TryGhost/Team/issues/667
On clean and existing installs, the default product created should be named the same as the site title in the first setup so the UX on Portal and everywhere is consistent. This change adds a migration to update existing sites which already have a default product created via fixture, and rename them to their current site title. The rename is only done if the Product name is still the same as in fixture - `Default Product`.
refs https://github.com/TryGhost/Team/issues/671
When turning on custom products, existing sites should have default price descriptions that match existing values for prices. This change sets the default description for Free price to match existing hardcoded value.
refs https://github.com/TryGhost/Team/issues/667
On clean and existing installs, the default product created should be named the same as the site title instead of the name in fixture. This change updates the default product's name to site title during the site setup. We use the Product name in Portal.
refs https://github.com/TryGhost/Team/issues/637
With custom products it's possible to change the name and description of any price. This assumes that people would want to change the same properties of a Free membership, and wires up the values for free membership price settings to Portal site settings API for Portal UI
no-issue
Our base model will only automatically convert numbers to booleans if
the type is 'bool' - however this column was incorrectly added with a
type of 'boolean'. Lucklily - knex with both MySQL & SQLite3 will add
a column with the same type for both of these, so no migration is needed
to fix it.
refs https://github.com/TryGhost/Team/issues/637
The "free" price - when Members signup without using Stripe, should have
a name and description, so that it can be displayed in Portal in a
similar way to paid price's. As there is only ever one, and it is not a
fully fledged price, a setting makes more sense than a dedicated db
table.
refs https://github.com/TryGhost/Team/issues/586
We are no longer using the `stripe_plans` setting, instead we are using
the `stripe_prices` database table. However, we must keep the setting as
the migration from the setting to the database is not done as a standard
migration, but in code. This means our code has to still read and pass
the setting because we will never know if the migration in code has run
yet.
The `portal_plans` setting has been updated to only include 'free' by
default, because the setting must include id's now rather than names.