closes: https://github.com/TryGhost/Toolbox/issues/319
- at the moment, content-version is only set if one of our endpoints touches the request
- this was demonstrated in the e2e tests, where many of the tests that set accept-version did not receive accept-version
- by moving the middleware out of the http module and onto the api app we ensure it's always done
- I put the code in the api-version-compatibility service to keep it all co-located
- ideally we will refactor that service slightly so it only exposes middleware
refs https://github.com/TryGhost/Toolbox/issues/308
- we have a pattern of using plurals around Ghost but this was singular
- this shouldn't change any API functionality, it's just code
refactoring
refs: https://github.com/TryGhost/Toolbox/issues/229
- we are getting rid of the concept of having multiple api versions in a single ghost install
- removed all the code for multiple api versions & left canary wired up, but without the version in the URL
- TODO: reorganise the folders so there's no canary folder when we're closer to shipping
we need to minimise the pain of merging changes across from main for now
refs https://github.com/TryGhost/Toolbox/issues/280
- In response to 'Accept-Version' header in the request headers, Ghost will always respond with a content-version header indicating the version of the Ghost install that is responding. This should signal to the client the content version that is bein g served
- This is a bare bones implementation and more logic with edge cases where `content-version` is served with a version value of "best format API could respond with" will be added later.
refs: https://github.com/TryGhost/Toolbox/issues/245
- The default behaviour of a serializer is to call a mapper for each object
- Instead of all the boilerplate code we had in the snippets serializer, all we need is a single mapper function
- Added tests for the mapper function as well
refs: https://github.com/TryGhost/Toolbox/issues/245
- .all methods are fallback serializers not to be run as well as a custom serializer
- The default serializer is also a fallback
- The "All" file with before and after are global hooks that _always_ get run as well as other serializers
- There's a lot of room for further improvement here especially with naming but this logic makes more sense
for the usecases AND doesn't affect v2 & v3 etc. We can do another pass after 5.0
refs: https://github.com/TryGhost/Toolbox/issues/245
- we don't need this serializer because the default serializer will call the tags mapper
- for now I've changed, rather than removed the tag serializer test as this shows default works the same!
refs: https://github.com/TryGhost/Toolbox/issues/245
- Added a serializer called default to the canary API
- Ideally, this would be part of the shared framework, but this would change v2/v3 and we're about to get rid of them
- Therefore, we change just canary for now, and we can refactor again later.
- Added wiring to handler that uses the default serializer, if there is a default, and isn't an explicit serializer for the endpoint
- Removed the invites serializer, so that one endpoint now uses the default
Note: previous commits have added explicit serializers to every endpoint, this is the first step towards paring
that back so that we have less serializers overall, not more!
refs: https://github.com/TryGhost/Toolbox/issues/245
- Ghost's API framework has a mixed up concept of what a serializer is. Mappers are true serializers! What we call serializers are little more than a small formatting step.
- This PR splits mappers into individual files and uses the endpoint's docname as the mapper name. This will help us to automate the calling of a mapper for an endpoint later.
- This is one tiny step in reworking the framework to need less code to make it work, and to have clearer concepts for how to do things.
- Have ensured we have 100% coverage of core/server/api/shared/serializers/handle.js
- This meant I had to swap around two validation clauses as one was unreachable
- I have done this as I want to make some changes in this area of the codebase, and want to ensure we have tests
and a clear understanding of what this code does before I change it
refs https://github.com/TryGhost/Team/issues/1004
The `tiers` column for a post/page only contained data if its visibility is set to `tiers`, otherwise its empty. This is because originally the purpose of `tiers` column on `post` was to capture specific tiers with access to post.
The best way to ensure a consistent behavior for `tiers` column data on post is to update it to always contain list of all `tiers` that have access to post, and not just when the visibility is `tiers`. This means the value is set to all tiers when visibility is one of public|members, and only paid tiers when visibility is `paid`. This change also allows on frontend to get all relevant `tiers` information for a post locally within post context instead of relying on additional information from outside.
This change -
- updates the output serializer for post/page to add all desired tiers manually in case of visibility is not `tiers`
- updates tests
refs: https://github.com/TryGhost/Toolbox/issues/168
- These are all places where we reference an API version like v2 or v3 but it's not actually
used or relevant.
- The aim is to get rid of all mentions of these old versions to make it clearer that we're only running tests on canary
refs: https://github.com/TryGhost/Toolbox/issues/168
We're going to be dropping the idea of having multiple versions of the API in each Ghost version.
Because this has not achieved the goal of making it easier to make breaking changes, but it has
created an ordinate amount of technical debt and maintenance overhead.
As we know this is going away in the next major, there is no benefit to us constantly running tests
that check if those versions still work, especially given how long they take.
Instead we're starting work to ensure that all of our test work on canary, and that canary has
excellent test coverage so that we can be sure that our one API version works really well and that
any changes, no matter how subtle are deliberate, tracked and understood.
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
- 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
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/581
refs https://github.com/TryGhost/Team/issues/582
When publishing a post via the API it was possible to send it using `?email_recipient_filter=all/free/paid` which allowed you to send to members only based on their payment status which is quite limiting for some sites.
This PR updates the `?email_recipient_filter` query param to support Ghost's `?filter` param syntax which enables more specific recipient lists, eg:
`?email_recipient_filter=status:free` = free members only
`?email_recipient_filter=status:paid` = paid members only
`?email_recipient_filter=label:vip` = members that have the `vip` label attached
`?email_recipient_filter=status:paid,label:vip` = paid members and members that have the `vip` label attached
The older `free/paid` values are still supported by the API for backwards compatibility.
- updates `Post` and `Email` models to transform legacy `free` and `paid` values to their NQL equivalents on read/write
- lets us not worry about supporting legacy values elsewhere in the code
- cleanup migration to transform all rows slated for 5.0
- removes schema and API `isIn` validations for recipient filters so allow free-form filters
- updates posts API input serializers to transform `free` and `paid` values in the `?email_recipient_filter` param to their NQL equivalents for backwards compatibility
- updates Post API controllers `edit` methods to run a query using the supplied filter to verify that it's valid
- updates `mega` service to use the filter directly when selecting recipients
closes https://github.com/TryGhost/Team/issues/552
Refactors URL transforms so they take place at the model layer rather than the API serializer layer. Continuation of the pattern created for the settings model in https://github.com/TryGhost/Ghost/pull/12738
- Added checks to all front-end tests to ensure output does not contain the magic replacement string
- includes failing acceptance test for `__GHOST_URL__` appearing in sitemaps
- Removed all transform-ready URL transforms from API serializers
- input serializers transform image urls relative->absolute to keep absolute-urls as the consistent "outside of the database" format
- output serializers should not need to perform any URL transforms as that will be done at the model layer
- Added url transforms to models layer
- removes knowledge from the API serializers which shouldn't need to know how data is stored internally in the database
- makes absolute urls the consistent "outside of the database" URL format
- adds transform step to the sitemap generator because the data used for that is fetched directly via knex which will not run through the bookshelf `parse()` methods
refs 6b07d4b2a0
- The model is needed here, because it contains full set of fields. In some cases, like email-preview, the "plaintext" field is not present in "attrs" which causes the logic to fail.
- This should be sorted along with https://github.com/TryGhost/Ghost/issues/10396
refs https://github.com/TryGhost/Team/issues/467
refs a6f5eb71be
- When a generated excerpt is calculated for posts/page resources it uses raw model! to get the data. Model contains untranformed __GHOST_URL__ markup which has to be additionally processed before extracint an excerpt or use the transformed `plaintext` from available attributes (chose the latter to decrease complexity)
- Removed model dependency as `attrs` at this point of serialization should always contain the `plaintext` field. It's ugly and has an unsolved bug report here - https://github.com/TryGhost/Ghost/issues/10396. The reliance should be solved at some point, but definitely not a part of this issue
closes https://github.com/TryGhost/Team/issues/467
- switches to storing "transform-ready" URLs in the database
- transform-ready URLs contain a `__GHOST_URL__` placeholder that corresponds to the configured url that gives a few benefits
- much faster and less memory intensive output transformations through not needing to parse html or markdown - the transform can be achieved using a straightforward regex find+replace
- ability to change to/from or rename subdirectory without any manual updates to the database
- modified existing 4.0 url-transformation migration rather than adding another one and repeating the transformation on posts rows
no-issue
This removes all references to the members labs setting, any code that was run conditionally behind this flag now runs unconditionally.
* Removed usage of Members labs flag
* Removed tests for Members disabled
* Added dynamic keypair generation for when setting is missing
no-issue
* Removed support for paid param from v3 & canary API
* Updated active subscription checks to use status flag
* Updated MEGA to use status filter over paid flag
* Removed support for paid option at model level
* Installed @tryghost/members-api@1.0.0-rc.0
* Updated members fixtures
refs https://github.com/TryGhost/Ghost/issues/12256
We no longer want to filter out cancelled subscriptions, so we are able
to remove the whereIn clause of the relation.
* Fixed paid flag on member
* Fixed content gating for members
Now that the subscriptions for a member include all of them, we must
explicitly check that the member has an active subscription in order to
consider them "paid"
refs b6728ecb0f
- The "no-shadow" eslint rune was introduced into ghost's eslint plugin (referenced commmit), which resulted in flood of warning in console output when linting the project codebase.
- This cleanup is aiming to make any new linting issues more visible. Follow up commits will contain similar cleanups in other parts of the codebase
closes https://github.com/TryGhost/Ghost/issues/10628
- JSON Schemas were extracted into a separate module to allow other clients to reuse them (for example documentation). Having them in a separate package also slims down the amount of code needed to be maintained in the core.
- Updated canary API input validators to use admin-api-schema module
- Removed canary schemas that moved into admin-api-schema package
- Updated v2 API input validators to use admin-api-schema package
- Removed v2 schemas that moved into admin-api-schema package
- Updated tests to contain needed information in apiConfig to pick up correct validation
- Added @tryghost/admin-api-schema package dependency
refs #2635
- Adds 'Location' header to endpoints which create new resources and have corresponding `GET` endpoint as speced in JSON API - https://jsonapi.org/format/#crud-creating-responses-201. Specifically:
/posts/
/pages/
/integrations/
/tags/
/members/
/labels/
/notifications/
/invites/
- Adding the header should allow for better resource discoverability and improved logging readability
- Added `url` property to the frame constructor. Data in `url` should give enough information to later build up the `Location` header URL for created resource.
- Added Location header to headers handler. The Location value is built up from a combination of request URL and the id that is present in the response for the resource. The header is automatically added to requests coming to `add` controller methods which return `id` property in the frame result
- Excluded Webhooks API as there is no "GET" endpoint available to fetch the resource
closes#12033
- Added webhooks schemas and definitions.
- Added validation checking if integration_id is present when using session auth. This is needed to prevent orphan webhooks.
- Integrated webhook schemas into frame's validation layer.
- Added isLowerCase ajv keyword support. This is needed to be able to do isLowerCase validation using JSON Schema for webhooks.
no issue
Output serializer's url util was expecting `og_image` and `twitter_image` to be top-level attributes in the `attrs` object but they are actually nested under `posts_meta`.
- updated the code to use lodash's `get/set()` so that we can work with paths for easier handling of nested objects
- fixed unit tests where the mocked data under test did not match real-world data
closes#11574
- the current implementation of the access property has it frontend only, and wired up only in one place
- this leaves it only available in a handful of places, e.g. can't use it in a post loop or get helper
- the current implementation also fails logically if the html content of the post is blank
This fix moves the behaviour to the API
- this ensures the field is always available no matter what context you are in
- it also updates the logic to use the same membersHasAccess logic as is used to gate the post, so it's always correct
TODO: should reconsider the location of this code
refs https://github.com/TryGhost/Ghost/issues/10318
- Updates `boolean` serialization in v2/canary serializers to apply only for `boolean` type settings
- Updates `boolean` transformation in model layer `format`/`parse` to check on `boolean` type setting
- Removes error thrown on Read-only setting for settings edit endpoint
- Updates v2/canary input serializers to remove any Read-only settings (using RO flag) to avoid edits
- Added type/group mappings in the importer when pre-migration settings table import data is present
- Updates tests
refs https://github.com/TryGhost/Ghost/issues/10318
refs 1dc0405803
- Adds 1:1 mapping for filtering options to renamed settings "type" to "gorup"
- Ignores the name changes and any old types
- Detailsed type -> group mappings can be checked in the refereneced migration commit
no issue
- Moves out CSV parsing and serialization related code into separate package as a part of push to modularize Ghost repo.
- Next up is to remove `csv-parser` dependency from this new package
* refactored core/frontend/services/proxy to import common dependency like a normal person
* removed all imports of `common/errors`
* 🔥 removed common/errors module
Co-authored-by: Vikas Potluri <vikaspotluri123.github@gmail.com>
no issue
- the value of `mobiledoc` when submitting a page/post via the API must
be JSON, but we don't validate this
- this results in url-utils throwing an error, which ends up being a 500
- this commit adds a custom format to AJV to validate it is valid JSON
- also updates tests with bad JSON - 'a'
no-issue
* Added default for getting origin of request
This function is used to attach the origin of the request to the
session, and later check that requests using the session are coming from
the same origin. This protects us against CSRF attacks as requests in
the browser MUST originate from the same origin on which the user
logged in.
Previously, when we could not determine the origin we would return
null, as a "safety" net.
This updates the function to use a secure and sensible default - which
is the origin of the Ghost-Admin application, and if that's not set -
the origin of the Ghost application.
This will make dealing with magic links simpler as you can not always
guaruntee the existence of these headers when visiting via a hyperlink
* Removed init fns and getters from session service
This simplifies the code here, making it easier to read and maintain
* Moved express-session initialisation to own file
This is complex enough that it deserves its own module
* Added createSessionFromToken to session service
* Wired up the createSessionFromToken middleware
* Refactored SessionStore to use @tryghost/errors
no-issue
* Updated tests to test exposed API
no-issue
This will make refactoring easier, as we only have the "public" contract to maintain
* Refactored session functionality to SessionService
no-issue
This splits the session logic away from the HTTP responding logic,
which will allows us to decouple session creation/modification from the
API. Eventually this can be used to create sessions based on magiclink
style tokens.
* Instantiated and exported the new SessionService
no-issue
* Refactored session middleware to take session service
no-issue
This removes duplication of code and makes the middleware more explicit
that it's just a wrapper around the session service.
* Updated to use external @tryghost/session-service
no-issue
- move all test files from core/test to test/
- updated all imports and other references
- all code inside of core/ is then application code
- tests are correctly at the root level
- consistent with other repos/projects
Co-authored-by: Kevin Ansfield <kevin@lookingsideways.co.uk>