Commit Graph

1327 Commits

Author SHA1 Message Date
Nazar Gargol
86e9c35c3c Allowed passing an array directly instead of requiring object with values key for validation options
noissue
2018-10-10 16:48:22 +02:00
Fabien O'Carroll
3516b15f9e
Updated session middleware to support node v6 (#9980)
closes #9972

* Added breaking test for node v6 session auth
* Updated session middleware to support node v6

This uses the legacy url to obtain the origin rather than the WHATWG
URL class in order to support node <6.14.4
2018-10-10 20:07:31 +07:00
Katharina Irrgang
a7b0029471 Added mobiledoc revisions functionality
closes #9927

- Added post model implementation to be able to store up to 10 versions of mobiledoc
- Bumped GQL to support filtering on the mobiledoc revision table
- Added tests ensuring new functionality works
2018-10-09 15:31:09 +02:00
Fabien O'Carroll
1b9aa2546f
Updated frame.context to use req.api_key_id (#9965)
* Added api_key_id to frame.context

refs #9865

This is to allow controllers to check permissions using api_key_id data.

* Removed client and client_id from frame.context

refs #9865

This is unused as we only support oauth on v0.1 API.
2018-10-09 18:28:38 +07:00
Fabien O'Carroll
e392fe55ae
🐛 Fixed redirect issue with private sites (#9960)
closes #9959

This issue existed because the logic assumed that if there were no
query parameters then there would be no `query` object. However this is
not the case. What we really wanted to check was for the existence of an
"r" query param - the code has been refactor to explicitly do this now.
2018-10-08 16:31:08 +07:00
Katharina Irrgang
d699daeb35 🐛Fixed sitemap duplicates after routes.yaml upload (#9957)
closes #9956

- sitemap reset was missing
2018-10-08 10:29:21 +07:00
Katharina Irrgang
d2baf80d58
Optimised test folder structure (#9958)
refs #9866

- test/functional/
- test/functional/api
- test/functional/api/v0.1
- test/functional/api/v0.1/utils
- test/functional/api/v2
- test/functional/api/v2/admin
- test/functional/api/v2/admin/utils
- test/functional/api/v2/content
- test/functional/api/v2/content/utils

- updated grunt file
- instead of `grunt test-routes`, you now need to use `grunt test-functional` (docs are updated)

You can use `localUtils.API.getApiQuery('posts/')` and it will generate the correct API url.
2018-10-07 16:36:02 +02:00
Katharina Irrgang
db1d2f62dd
Removed api integration tests (#9940)
refs #9866 

- moved the tests either to unit tests or routing tests
- or removed test case (a lot)
- this commit is very big 🤪, it was not rly possible to create clean commits for this
- it only changes the test env, no real code is touched

Next steps:
- optimise folder structure + make v2 testing possible
- reduce some more tests from routing and model integeration tests
2018-10-06 22:13:52 +02:00
kirrg001
b855f2d8f0 Removed testUtils.API.getApiPath
refs #9866

- the global utility should for now not generate API urls
- we only have one test which generates the API url
- for now it will live in this test file
- if we have multiple cases, we can reconsider this
2018-10-05 16:49:46 +02:00
kirrg001
b74879c64e Refactored Ghost SDK unit test
refs #9866

- the sdk does not use the url utility
- it just respects what you pass in
- there is no need to test this behaviour for multiple API versions
2018-10-05 16:49:46 +02:00
kirrg001
1e9d87624a Moved test/unit/api files to test/unit/api/v0.1
refs #9866

- these test files belong to v0.1
2018-10-05 15:11:35 +02:00
Fabien O'Carroll
b6e80ef557
Added refreshSecret method to ApiKey model (#9947)
refs #9865

This is to allow the secret of an api_key to be refreshed, in the event of a secret being compromised.
2018-10-05 15:51:13 +07:00
Katharina Irrgang
959912eca3
Added tiny framework to support multiple API versions (#9933)
refs #9326, refs #9866

**ATTENTION: This is the first iteration. Bugs are expected.**

Main Goals: 

- add support for multiple API versions.
- do not touch v0.1 implementation
- do not break v0.1

## Problems with the existing v0.1 implementation

1. It tried to be generic and helpful, but it was a mixture of generic and explicit logic living in basically two files: utils.js and index.js.

2. Supporting multiple api versions means, you want to have as less as possible code per API version. With v0.1 it is impossible to reduce the API controller implementation. 

----

This commit adds three things:

1. The tiny framework with well-defined API stages.
2. An example implementation of serving static pages via /pages for the content v2 API.
3. Unit tests to prove that the API framework works in general.

## API Stages

- validation
- input serialization
- permissions
- query
- output serialization

Each request should go through these stages. It is possible to disable stages, but it's not recommended.

The code for each stage will either live in a shared folder or in the API version itself. It depends how API specific the validation or serialization is. Depends on the use case.

We should add a specific API validator or serializer if the use case is API format specific.
We should put everything else to shared.

The goal is to add as much as possible into the shared API layer to reduce the logic per API version.

---

Serializers and validators can be added:

- for each request
- for specific controllers
- for specific actions

---

There is room for improvements/extensions:

1. Remove http header configuration from the API controller, because the API controller should not know about http - decouple.

2. Put permissions helpers into shared. I've just extracted and capsulated the permissions helpers into a single file for now. It had no priority. The focus was on the framework itself.

etc.

---

You can find more information about it in the API README.md (api/README.md)

- e.g. find more information about the structure
- e.g. example controllers

The docs are not perfect. We will improve the docs in the next two weeks.

---

Upcoming tasks:

- prepare test env to test multiple API versions
- copy over the controllers from v0.1 to v2
- adapt the v2 express app to use the v2 controllers
2018-10-05 00:50:45 +02:00
kirrg001
80b963fb5a Moved test/unit/api/decorators
no issue

- to test/unit/api/v0.1/decorators/urls_spec
2018-10-04 19:09:52 +02:00
Rishabh Garg
f78d9d3914
Refactored hardcoded v0.1 url unit tests to support multiple versions (#9945)
refs #9866

- Added test util method for api path based on version
- Updated all hardcoded v0.1 tests strings to use dynamic string from util method
- Updated hardcoded v0.1 tests using regex match to use string equal with new util method
2018-10-04 21:43:12 +05:30
Rish
dd151f3713 Refactored method urlFor to use versionType instead of admin: true
no issue

- Updated urlFor to work with versionType instead of admin:true
- Updated tests to use the correct method call
2018-10-04 16:49:55 +05:30
Fabien O'Carroll
b185892b7b
Created session controller (#9911)
refs #9865

Note that this controller is the singular, that's because we plan to
make a session resource controller to be used with /sessions, wheras
this is on /session
2018-10-03 20:45:42 +07:00
Nazar Gargol
82b7aea641
Refactor URL generation from models (#9917)
Moved URL attributes logic from the model into API layer 

refs #9866

- Moved URL related attribute calculation for posts, users, and tags into API layer
- Added test coverage for url attributes in tags/authors/primary_tags/primary_authors
2018-10-03 15:44:30 +02:00
kirrg001
27996db5e9 Extended sequence utility
no issue

- support promise and none promise tasks
- helpful if you create an array of operations and not all of the operations/tasks are async
- `response instanceof Promise` does not work for all cases e.g. some usages return a transaction/bookshelf chain
2018-10-03 00:17:45 +02:00
Rish
91f8e03244 Added mobiledoc_revisions schema, migration script and updated tests 2018-10-02 19:15:23 +02:00
Kevin Ansfield
1db3aefb9b
Set up schema and models for API Key authentication (#9904)
refs https://github.com/TryGhost/Ghost/issues/9865
- schema migrations
  - adds `integrations` and `api_keys` tables
  - inserts `integration` and `api_key` permissions and Administrator role relationships
  - inserts `Admin Integration` role and permissions
- adds `Integration` model
- adds `ApiKey` model
  - creates default secret if not given
  - hardcodes associated role based on key type
    - `admin` = `Admin API Client`
    - `content` = no role
- updates `Role` model to use `bookshelf-relations` for auto cleanup of permission relationships on destroy
2018-10-02 17:46:38 +01:00
Fabien O'Carroll
ecf47f3b7b Added some missing tests to base model (#9931)
no-issue
2018-10-02 16:43:19 +02:00
Fabien O'Carroll
cb0c5dc582
Session auth service (#9910)
refs #9865

* This service handles the session store and exporting middleware to be
used for creating and managing sessions

* Updates the auth service index.js file in line with how we do things elsewhere

* After wrapping the exports in a getter, the usage of rewire had broken
the authenticate tests, this commit _removes_ rewire from the tests, calls `init` on
the models before the tests (needed because rewire isn't there) and also
cleans up the use of var.
2018-10-02 15:35:23 +07:00
Fabien O'Carroll
6cd1dc8005 🐛Fixed blog not responding when uploading routes.yaml with unknown taxonomy (#9926)
closes #9870

Instead of 500'ing when uploading a routes.yaml with an invalid taxonomy
we will now send back an error saying it's invalid.
2018-10-01 20:40:29 +02:00
Fabien O'Carroll
af12f21db7 Updated base model destroy fn to be more generic (#9928)
refs #9914

This allows us to destroy models on properties other than the id.
2018-10-01 14:44:52 +02:00
Rishabh Garg
6163d1f128 Updated overrides config for api versions with v0.1 to deprecated (#9921)
refs #9866

- v0.1 == deprecated
- v2 == active
2018-09-27 19:34:12 +02:00
Katharina Irrgang
b43ab65d8a
Moved api controllers into api/v0.1 (#9918)
refs #9866

- preparation for v2
- moved api/ to api/v0.1
- do export v0.1 straight from the api folder, we don't want to touch this right now
- that means currently if you require the api folder, we return v0.1 by default
- there were some direct requires of api files in the test env
  - some of them use rewire
  - for now, we just correct the require path to require api/v0.1/
  - we touch the test env next week

**Docs about V2 design are coming soon!**
2018-09-27 16:06:57 +02:00
Fabien O'Carroll
4d9414b5d2 Created Session Model (#9909)
refs #9865

- Created session model for session table
- Added model relations
- Added unit test coverage
2018-09-27 14:31:39 +02:00
Fabien O'Carroll
1d17f2aa91 Created session table migration (#9908)
refs #9865

- This table will be used for storing user sessions in
2018-09-27 09:51:46 +02:00
Fabien O'Carroll
045ce0a800 Updated private-sites to not redirect to full urls
no-issue

- Parse redirects as URL with blog as base
- Redirect to the pathname property of parsed URL

Credits: @j3ssie
2018-09-25 17:32:17 +07:00
Rishabh Garg
9624c88f3e Refactored url utility to generate multiple API version URLs (#9897)
refs #9866

- added api version config to overrides, which makes it possible to have a centralized api versioning configuration
- the next PR will use this config in the web folder
- make api url generation in url service flexible and dynamic
- remove hardcoded API_PATH
- updated all places which used `urlFor('api'..)` -> we now ask for explicit api version
2018-09-24 21:49:20 +02:00
Rishabh Garg
39485d17c0 Added new endpoint to upload square profile images with dimension validation (#9862)
refs #8576

- adds new API endpoint `/uploads/profile-image` for uploading profile images
- new validation which fails with error message if uploaded image is not square
- Renamed getImageSizeFromFilePath to getImageSizeFromStoragePath, because it's more explicit
- Add new getImageSizeFromPath method, which is used in the new dimensions middleware
- Ensure we use the sharp middleware to auto-resize the uploaded profile pictures
- Ensure the new route get's added to v2

While this makes sure all future profile images uploaded are square, this doesn’t affect any existing non-square profile image. Needs more thought on how to handle existing non-square profile images for the purpose of making theming easier in future.
2018-09-24 21:42:58 +02:00
Daman Mulye
214d682ea3 Removed change frequency and priority fields from sitemap generator (#9771)
closes #9765

- Google says that change frequency and priority are not important when search engines crawl through pages. Therefore, these two properties are unimportant and removed from Ghost. Reference: https://www.seroundtable.com/google-priority-change-frequency-xml-sitemap-20273.html
- Credits to @damanm24
2018-09-24 19:16:31 +02:00
Katharina Irrgang
b913618c03 Extended uncapitalise unit tests (#9891)
Extended uncapitalise unit tests

refs #9866

- Proved that the middleware works for many API versions
- Added test case to prove that the version identifier gets lowercased too
2018-09-20 22:27:38 +02:00
Rishabh Garg
fcd275f6c0 Refactored web/middleware and web/utils to web/shared (#9892)
refs #9866

- Moved web/middleware to web/shared/middlewares
- Moved util file to web/shared/utils
2018-09-20 20:04:34 +02:00
Nazar Gargol
7e17c56feb Removed res.isAdmin usages from v2 express app (#9884)
refs #9866

- Removed `res.isAdmin` flag in v2 express app
- Did not touch v0.1 express app
- Separated url redirect middleware for admin and content API
2018-09-20 13:58:45 +02:00
Nazar Gargol
57271127f4 Added v2 api endpoints (#9874)
refs #9866

- Registered Content API under /ghost/api/v2/content/
- Registered Admin API under /ghost/api/v2/admin/
- Moved API v0.1 implementation to web/api/v0.1
- Created web/api/v2 for the new api endpoints
- Started with reducing the implementation for the new Content API (the Content api does not serve admin api endpoints, that's why it was reducible)
- Covered parent-app module with basic test checking correct applications/routes are being mounted
- Added a readme file, which contains a warning using v2, because it's under active development!
- This PR does only make the new endpoints available, we have not:
  - optimised the web folder (e.g. res.isAdmin)
  - started with different API controllers
  - reason: we want to do more preparation tasks before we copy the api controllers
2018-09-18 15:59:06 +02:00
kirrg001
242f7ef4c8 Removed usage of res.isAdmin from private blogging app
no issue

- private blogging was once part of a single big express app, see: c1a2601514
- therefor we needed to differentiate if the request is for /api/v0.1 or for the actual site
- nowadays, we register apps only for the site express app
2018-09-15 08:58:53 +02:00
Nazar Gargol
9613de7cc1 🐛 Fixed gif images are not converted to png (#9853)
refs #9848

- Disabled image optimization for .gif files as a temporary solution until sharp library starts supporting latest version of libvips
- Disabled image optimization for .svg/.svgz files as permanent solution as these file types are being converted to .png
2018-09-06 11:42:42 +02:00
Kevin Ansfield
8e4c5d0f34 Fixed mobiledoc-converter test
no issue
- 👻
2018-08-31 12:03:08 +01:00
Kevin Ansfield
bba3049106 Updated gallery renderer to cope with invalid images
no issue
- skip rendering images that do not have all required fields
- do not render anything if there are no valid images
2018-08-31 11:13:24 +01:00
Rish
d29e376367 Added kg-card class to mobiledoc cards
No issue
2018-08-31 11:05:47 +01:00
Fabien O'Carroll
c9b8ddde4b 🎨Added absolute_url flag to public api (#9833)
closes #9832

The API _should_ be returning absolute URLs for everything, 3rd party applications require absolute urls to read and display ghost data correctly. Currently they have to concat the blog url and the resource url, which is very uncomfortable.

Changing the public api like this would be considered a breaking change however so we've opted to put it behind a query parameter named `absolute_urls`.
2018-08-31 11:02:39 +01:00
Kevin Ansfield
402d26a23c Added mobiledoc renderer for gallery card
no issue
- basic renderer for working with Koenig's gallery card
2018-08-30 17:57:17 +01:00
Nazar Gargol
0faf89b5ab Added ability to resize and compress images on upload (#9837)
refs #4453

* On by default

* Added config to disable resizing

* Added basic image optimization processing

* Added dep: sharp (optional dep)

* Added resize middleware

* Take care of rotation based on EXIF information

* Removed all meta data from optimised image

* Added handling if sharp could not get installed

* Do not read ext twice - optimisation

* Do not call sharp if config is disabled

* Do not remove the original image which was uploaded (store 2 images)

* Support of `req.files` for internal logic

* Disabled cache to enable file removal on Windows
2018-08-30 17:30:36 +01:00
Nazar Gargol
154366f448 🎨 Added additional parameters to subscribe_form and input_email helpers (#9820)
closes #9134

- Added form_id, input_id, and button_id parameters to subscribe_form helper
- Added id parameter to input_email helper
- Added test coverage to input_email helper
- Added quotes to id attributes for consistency
- Added subscribe_form helper tests
- Updated express to v4 in helper tests
2018-08-30 17:17:27 +01:00
Fabien O'Carroll
8ccf27340b Oembed meta tag fallback for unknown providers (#9827)
closes #9786

- Make GET request when url has no provider match
  - The HEAD request was made in order to send less data over the wire when
checking for redirects for urls that do not have an oembed provider
match. We are now going to look for provider metatags withing the
response of the request - rather than making a HEAD followed by a GET if
no redirect is found, this condenses that to a single request.

- Try to get OEmbed data from tag if no provider
  - Here we parse the HTML response of the resource and look for a link tag
that will give us the oembed resource url which we can use to fetch the
embed html
2018-08-27 15:02:03 +01:00
Fabien O'Carroll
2376c614b3 Fixed RPC pings (#9816)
closes #9644

- Removed google blogsearch from pingList, because it's dead (https://plus.google.com/+GoogleWebmasters/posts/46W7ZwVrwqg)
- Updated pingomatic method weblogUpdate -> weblogUpdates
- Updated RPC response handler to check for errors, log improvement
- the pingomatic service sends back a 200 even when it errors, so we
check the xml response to see if it's good, it throws and passes of to
the catch handler already in place
- Avoid multiline XML error message strings, but
includes a catch in case our regex stops working with a fallback to
multiline XML error message
- we check for arbitrary whitespace between different XML tags,
which I haven't seen in any of the responses - but it could change I
guess. I haven't added support of whitespace between the tags, as I
believe that would be a different value with XML spec. And we wanna
match on exact values here.
2018-08-23 15:20:29 +02:00
Katharina Irrgang
4b2ebee67b
🐛 Added logic to avoid updating the updated_at and updated_by field when migrating (#9814)
no issue

- we have to explicitly reset the previous `updated_at` field, because Bookshelf auto-updates this field on each update
- we have to extend the condition to avoid updating the `updated_by` field
- detect and respect `options.migrating`
2018-08-22 13:57:12 +02:00
Katharina Irrgang
cd690efad1 🐛 Dynamic Routing Beta: Disallow using author resource and author data key name (#9790)
* 🐛 Dynamic Routing Beta: Shortform `author.foo` is not allowed

refs #9601

- otherwise you get access to {{author}} in the theme, which is deprecated & causes errors
- recommend not using {{author}} as data longform name in the yaml validator
- (internal usage is still allowed)
- also warn against using reserved data key names like filter, resource, limit etc - maybe remove this restriction later but seems like a sensible validation right now.
2018-08-16 12:13:24 +02:00
kirrg001
fd8502448a Updated fixture post content
no issue

- Organising your content

From: Here, the theme would assign the post publicly displayed tags of Blog - but it would also keep a private record of the post being tagged with #video.
To: Here, the theme would assign the post publicly displayed tags of News - but it would also keep a private record of the post being tagged with #video.
2018-08-16 12:13:24 +02:00
kirrg001
bbde22a687 Fixed tests
no issue

- replace test themes
  - otherwise they are all invalid with the new GScan version
- fix general tests because of Ghost 2.0 logic
2018-08-16 12:13:24 +02:00
kirrg001
17833a669b 🎨 Dynamic Routing Beta: Enabled redirect by default when using data key
refs #9601

- when using the short form `data: tag.welcome` the redirect is enabled by default
  - /tag/welcome/ will redirect to the channel/collection which makes use of the data key
- you can disable the redirect by using the long form
  e.g. data:
	tag:
	  resource: tags
          type: read
          slug: welcome
          redirect: false
2018-08-16 12:13:24 +02:00
Katharina Irrgang
220d0456b4 🎨 Changed fixture data and default settings (#9778)
closes #9774, refs #9742

- added new fixture posts for Ghost 2.0
- added migration file to remove old fixture posts
  - only remove them if they are owned by the Ghost author and if they are tagged with getting-started
  - added new fixture posts if you had all (!) old fixture posts
  - ensure on rollback we remove the new fixture posts again
- updated default settings
2018-08-16 12:13:24 +02:00
Katharina Irrgang
1caa941d20 🔥 Removed demo post (#9769)
refs #9742

- removed demo post fixture for fresh blogs
- added migration to remove the demo post from the database
- on rollback: bring back demo post
2018-08-16 12:13:24 +02:00
kirrg001
8bb7088ba0 🔥 Removed permalink setting
refs #9742

- removed usage of single permalink setting
  - with dynamic routing this configuration does no longer makes sense
  - because you can configure your permalinks in the routes.yaml
  - furthermore you can have multiple collections with multiple permalinks
- removed @blog.permalinks
- do not export permalink setting
- do not import permalink setting
- permalink setting UI will be removed soon
- get rid of {globals.permalink} completely
- remove yaml in-built migration
- do not expose settings.permalinks via the private API
- do not allow to edit this setting
- keep phyiscal value in case a blog needs to rollback from v2 to v1
- sorted out when the routers should be created
  - ensure routes.yaml file doesn't get validated before Ghost is fully ready to start
2018-08-16 12:13:24 +02:00
kirrg001
52a9eebabf Changed comments and deprecation notes
refs #9742
2018-08-16 12:13:24 +02:00
Katharina Irrgang
c39df004dc Changes for Koenig and Ghost 2.0 (#9750)
refs #9742, refs #9724

- handle König Editor format for 2.0
- adapted importer to be able to import 1.0 and 2.0 exports
- added migration scripts
  - remove labs flag for Koenig
  - migrate all old editor posts to new editor format
- ensure we protect the code against mobiledoc or html field being null
- ensure we create a blank mobiledoc structure if mobiledoc field is null (model layer)
- ensure you can fully rollback 2.0 to 1.0
- keep mobiledoc/markdown version 1 logic to be able to rollback (deprecated code)
2018-08-16 12:13:24 +02:00
kirrg001
d518f23b48 Updated docs links
refs #9742

- rebase against master updated some docs links again
- go over code base again and double check that all docs links are correct
- 2.0 will become the latest version on our readme pages
2018-08-16 12:13:24 +02:00
kirrg001
91152efdc1 Changed http to https links
no issue

- use https
- replace broken links e.g. docs.ghost.org/themes
2018-08-16 12:13:24 +02:00
kirrg001
529bec8089 Renamed core/server/data/export to core/server/data/exporter
no issue

- i'vejust renamed the folder
- it makes more sense
  - data/importer
  - data/exporter
2018-08-16 12:13:24 +02:00
kirrg001
e99015e700 Refactored importer tests
no issue

- these tests were a mess
- we had many duplicated tests
- it was very hard to work with the exporter files
- i have tidied up the whole file
  - first section: all general importer tests based on the current Ghost version
  - second section: 1.0 tests
- everything is now JSON based (much easier to control)
2018-08-16 12:13:24 +02:00
kirrg001
7db0739296 Renamed amp post column to column_id
refs 9742

- when we've introduced Ghost 1.0, we have noticed that we broke Disqus comments
- Disqus comments use a unique identifier, which is the post id
- that means if you have exported your LTS content and imported it into 1.0, all resource identifiers are regenerated
- but the Disqus must use the original post resource id
- that's why we have imported the old post id and remembered it in the `amp` field 🤠
- that was the only field which was available and un-used
- now in Ghost 2.0, we would like to rename the `amp` field to `comment_id`
- string length: 50 (i thought it might be safer to not use 24 characters, because who knows if support other comment id's in the future)
2018-08-16 12:13:24 +02:00
Kevin Ansfield
66fb0955a4 Koenig - Render image title attribute if present
refs https://github.com/TryGhost/Ghost/issues/9724
- `<img>` elements can have both `alt ` and `title` attributes, ensure we render both of them
2018-08-13 09:48:04 +01:00
Kevin Ansfield
cfd9ff3993 🎨 Koenig - Added support for shortened URLs in embed card (#9781)
refs https://github.com/TryGhost/Ghost/issues/9724

- perform a HEAD request on a url if we don't find a matching provider, following any redirects until we hit success response before looking up providers for the resulting url
2018-08-12 15:57:19 +02:00
kirrg001
860718f584 Minimized cached data on resource add/update
refs #9601

- on resource update/add we have cached mobiledoc, html etc
- we have to ensure we exclude the fields (same procdure happens on bootstrap)
- these excluded fields don't have to be cached
- otherwise memory usage is higher in general
- ensure we cache relations with a minimal field set on resource update/add
2018-08-12 14:23:32 +02:00
Kevin Ansfield
0c06a47b9b Koenig - Added rich-text caption support
refs https://github.com/TryGhost/Ghost/issues/9724
- captions can have HTML so we need to render as HTML rather than as a text node so special chars don't get escaped
2018-08-08 14:29:20 +01:00
kirrg001
40c8eacd44 Added option to export extra tables
refs #9742, refs #8719

- you can now use `include` to export extra tables e.g. `include=clients`
- admin client won't make use of this option yet, maybe later and optional
- we won't announce this new ability for now (stays hidden)
2018-08-03 14:11:45 +02:00
Kevin Ansfield
5b80ec44ab 🐛 Koenig - Fixed missing alt text on images
refs https://github.com/TryGhost/Ghost/issues/9724
- render `alt` attribute if the image card payload has an `alt` property
2018-07-30 10:10:11 +01:00
Katharina Irrgang
76b9a49eb8
🎨 Added Koenig Demo Post (#9747)
no issue

- add a new migration for 1.25 to insert the draft demo post for existing blogs
- ensure new blogs get the draft demo post as well
- tested on sqlite3 + mysql
- added handling if Ghost Author user doesn't exist anymore (fallback to owner user)
2018-07-24 14:37:17 +02:00
Kevin Ansfield
f57268daae
Koenig - Finalise Koenig HTML output and migrate existing content (#9741)
refs https://github.com/TryGhost/Ghost/issues/9742

We've identified some changes we need to make to the HTML output of the [new Koenig editor](
https://forum.ghost.org/t/koenig-editor-beta-release/1284/102) for future proofing and consistency across cards.

- the `<div class="kg-post">` wrapper around post content has been removed
- for image cards the `.kg-image-wide` and `.kg-image-full` classes have been changed to `.kg-width-wide` and `.kg-width-full` and applied to the `<figure>` element rather than the `<img>` element

Before:
```html
<div class="kg-post">
    <figure class="kg-image-card">
        <img class="kg-image kg-image-wide" src="...">
        <figcaption>example wide image</figcaption>
    </figure>
</div>
```

After:
```html
<figure class="kg-image-card kg-width-wide">
    <img class="kg-image" src="...">
    <figcaption>example wide image</figcaption>
</figure>
```
2018-07-23 12:23:02 +01:00
kirrg001
132df78940 Updated docs links
refs #9742

- Ghost 2.0 is coming
- all doc links in 1.0 must use concrete links e.g. docs.ghost.org/v1 or themes.ghost.org/v1.23.0/
- if we release Ghost 2.0, docs.ghost.org will show 2.0 docs
2018-07-20 23:49:16 +02:00
kirrg001
b335002269 🐛 Fixed Disqus comments on post preview pages
closes #9727

- this is a short term fix to proof that Disqus comments on preview pages no longer appear on other threads
- this is not a full solution to the problem
- the private API still returns /404/, which is right now inconsistent, but not critical in any way
- the url helper will now output the post preview url if you serve a draft/scheduled post
- this should register unique page urls at Disqus and ensure uniquness for threads
  - i still don't understand why the cross posting happens at all, because we also pass an unique identifier to Disqus (the post ID)
- it could be that comments, which are added on the preview page, won't appear on the published urls, because
  the published url !== preview url. I wasn't able to figure this out via testing or reading their docs
2018-07-11 00:20:55 +02:00
Kevin Ansfield
a4aab19403 🎨 Koenig - Added ID attributes to heading tags when rendering (#9720)
refs https://github.com/TryGhost/Ghost/issues/9623

- added `DomModifier` class to walk a SimpleDom document and modify as needed
  - adds `id` attributes to `h1`, `h2`, etc heading tags
    - converts H* tag content to a dasherized string for the id attribute (dasherized id's are different to the smushed ids that are generated by our markdown converted but there are no backwards-compatibility concerns here)
    - if a duplicate id is detected then add a `-1`, `-2`, etc suffix to the id
- use `DomModifier` after converting mobiledoc to SimpleDom but before serialising to html
- switched top-level var declarations to es6
2018-07-11 00:03:25 +02:00
Kevin Ansfield
865acecaef
🐛 Koenig - Support schema-less URLs in embed card (#9725)
refs https://github.com/TryGhost/Ghost/issues/9724
- adjust the "base url" regex in the oembed endpoint to strip schemaless scheme `//` as well as `https?://`
2018-07-09 10:32:39 +01:00
kirrg001
c5bad55d6f Dynamic Routing Beta: StaticRoutesRouter has to respect the route name
refs #9601

- this was already working for collections or channels
- but the `routeName` was not parsed for static routes
- ensure we push the route name into the context object

e.g. /about/: about

-> name of the route is "about"
2018-06-26 19:06:42 +02:00
kirrg001
af58de0490 🐛 Fixed dated urls when timezone changes
no issue

- discovered while testing (issue doesn't exist)
- with dynamic routing we have introduced a bug
- we pre-generate urls and if your permalink contains a date (dated permalink),
  we have to regenerate the urls, otherwise the dated urls do not respect your blog timezone
- collection router has to subscribe to the timezone event
- collection router must trigger an update on it's url generator if the timezone changes and the it's permalink is dated
- ensure we also update the urls on import
2018-06-26 18:18:11 +02:00
kirrg001
00cf043e15 Fixed missing defaults in model layer
no issue

- reported in the forum: https://forum.ghost.org/t/publishing-with-a-single-post-request-to-posts/1648
- the defaults are defined in two places
  1. on the schema level (defaults for the database)
  2. on the ORM (model layer)
- the defaults on the db layer are set correctly when inserting a new resource
- but if we don't apply all defaults on the model layer, it will happen that model events are emitted without the correct defaults
  - see comment in code base
  - it's caused by the fact that knex only returns the inserted resource id (probably caused by the fact knex has to support x databases)
- components/modules are listening on model events and expect:
  1. a complete set of attributes
  2. a complete set of defaults
  3. sanitized values e.g. bool, date
- this commit fixes:
  1. added missing defaults for user & post model
  2. sanitize booleans (0|1 => false|true)
  3. added tests to ensure this works as expected
  4. clarfies the usage of `defaults`

Regarding https://forum.ghost.org/t/publishing-with-a-single-post-request-to-posts/1648:
  - the post event was emitted with the following values {page: undefined, featured: undefined}
  - the urlservice receives this event and won't match the resource against collection filters correctly
  - NOTE: the post data in the db were correct
2018-06-26 16:35:23 +02:00
Katharina Irrgang
7027980ad2
Dynamic Routing Beta: Filter collections with NQL (#9704)
refs #9601

- replace jsonpath with [NQL](https://github.com/NexesJS/NQL)
- jsonpath was just a temporary solution (a short-term fix)
- with NQL we are able to filter collections more powerful in the near future
- NQL is not feature complete
- we still support `featured:true` for collections
2018-06-26 01:54:51 +02:00
Katharina Irrgang
fc9da07025
Dynamic Routing Beta: Added ability to disable+override rss (#9693)
refs #9601

- you can now use `rss:false`
- ability to define a custom rss url with a target template (+ content_type)
- ability to disable rss for channel or collection
2018-06-26 01:33:29 +02:00
Katharina Irrgang
13cccfa9ee
Dynamic Routing Beta: Refactor res.routerOptions (#9705)
refs #9601

- sort out `res._route` vs. `res.locals.routerOptions`
- it was super hard to maintain two different objects
2018-06-26 01:12:50 +02:00
David Balderston
74a6a413ed Changed theme fixture post: point to forum instead of slack (#9703)
no issue

 - changed the default themes post to direct users to the Ghost forum
rather than slack
- updated the tests to reflect this change
2018-06-25 22:06:21 +02:00
kirrg001
07c72d735e Dynamic Routing Beta: Render default.hbs as fallback for static routes
refs refs #9601

- instead of index.hbs (that doesn't make sense)
2018-06-24 02:06:58 +02:00
kirrg001
c2fa469c4d Dynamic Routing Beta: Channels
refs #9601

- refactor architecture of routing so you can define a channel
- a channel is a different way of looking at your posts (a view)
- a channel does not change the url of a resource

Example channel

```
routes:
  /worldcup-2018-russia/:
    controller: channel
    filter: tag:football18
    data: tag.football18
```

- added ability to redirect resources to a channel/static route
- support templates for channels
- ensure we still support static routes (e.g. /about/: home)
- ensure pagination + rss works out of the box
2018-06-24 02:06:58 +02:00
kirrg001
4ed10aa76a 🎨 Dynamic Routing Beta: Extended collection feature (limit, order, data)
refs #9601

- support data, limit and order for collections
- limit definition in routes.yaml is stronger than theme package.json limit configuration
- ensure we update hbs template options
2018-06-24 02:06:58 +02:00
kirrg001
51e6286924 Dynamic Routing Beta: Added redirect middleware to ParentRouter
refs #9601

- middleware to control dominant router redirects
2018-06-24 02:06:58 +02:00
kirrg001
1952c55d33 Dynamic Routing Beta: Added redirect helper to ParentRouter
refs #9601

- this function will help us to determine if a redirect should happen or not
2018-06-24 02:06:58 +02:00
kirrg001
935f064357 Dynamic Routing Beta: Added yaml validation for data key
refs #9601

- support short and long form of data key
- always return the expanded version (long) to the routers
2018-06-24 02:06:58 +02:00
Katharina Irrgang
5a61f99467
Dynamic Routing: Added migration for routes.yaml file (#9692)
refs #9601

- the home.hbs behaviour for the index collection (`/`) is hardcoded in Ghost
- we would like to migrate all existing routes.yaml files
- we only replace the file if the contents of the routes.yaml file equals the old routes.yaml format (with home.hbs as template)
- updated README of settings folder
- if we don't remove the home.hbs template from the default routes.yaml file, home.hbs will be rendered for any page of the index collection
  - the backwards compatible behaviour was different
  - only render home.hbs for page 1
- remember: the default routes.yaml file reflects how Ghost was working without dynamic routing
2018-06-22 20:28:01 +02:00
kirrg001
a1b55509df Dynamic Routing Beta: collection name behaviour
refs #9601

Example:

```
collections:
  /podcast/:
    permalink: /{slug}/
```

- the name of the collection is remembered as `routerName` (in the case above: "podcast")
- the name of the collection is important for two things
  1. context value
  2. template name
- the context value is available for specific theme helpers e.g. is helper, body_class helper
- we auto-lookup the collection name in your theme e.g. podcast.hbs
- this logic does not apply to static routes
- if you define templates on your collection, they are stronger than the collection name
2018-06-21 20:59:43 +02:00
kirrg001
0046dce39f Dynamic Routing Beta: Better template support
refs #9601

- single or multiple template definition
- possible formats:

```
routes:
  /about/: about
```

```
routes:
  /about/:
    template: about
```

```
routes:
  /about/:
    template:
      - about
      - me
```

```
collections
  /posts/:
    template:
      - posts
      - general
```

```
collections
  /posts/:
    template: posts
```
2018-06-21 16:22:45 +02:00
kirrg001
1a79aac673 Fixed collection ownership if a published post status changes to featured
refs #9601

- implementation of resource listener updated
- if you define two collections: `featured:true` (1) and `page:false` (2) you can run into the following bug:
  - you create a published post (owned by (2))
  - you change the status to featured
  - still owned by (2), because the filter still matches (it's still not a static page)
- this adaption fixes the behaviour
- less smart logic, but less error prone
2018-06-17 10:41:05 +02:00
Kevin Ansfield
a16077a8e3 Koenig - Do not render image cards with no src on the front-end
refs https://github.com/TryGhost/Ghost/issues/9623
- blank images may be used in the editor as placeholders, don't render them on the front-end
2018-06-14 14:57:09 +01:00
kirrg001
87c01c131b 🐛 Fixed {{#is "index"}}
closes https://github.com/TryGhost/Ghost/issues/9674

- with dynamic routing the first collection get's the "index" context attached
- the index context signalises the main post listening route (first collection)
- this behaviour was present < 1.24 - we have to keep this behaviour
2018-06-14 11:53:13 +02:00
Katharina Irrgang
835fd6c45b
Removed knex mock (#9685)
no issue

- this mock eat already too much of my/our time
- the idea of adding a knex mock was definitely a failed approach/try
- it's too much to maintaince and have not found a module which does this already
  - we have to support any query format
  - this is too crazy
- the idea was to use the knex mock for model unit tests, because if we want to unit test models we have to
  run through bookshelf, because the whole model layer depends on bookshelf e.g. events
- for now we simply use the real database
  - we could use the sqlite3 memory mode, but that would mean every unit test runs on sqlite3
  - something to consider for later e.g. run unit tests on one matrix
  - run the rest on another matrix for sqlite + mysql
2018-06-12 20:26:16 +02:00
Katharina Irrgang
7b0d5d465b 🐛 Fixed preview url and Zapier on subdirectory (#9683)
closes #9675

- with dynamic routing we have introduced a breaking change, which we have overseen
- Ghost does not return absolute urls, that's why the clients need to concat the blog url and the resource url
- with 1.24.0 Ghost returned resource urls including the subdirectory
- this caused trouble for e.g. zapier or the preview feature in the admin client
- revert breaking change and ensure we only expose resource urls without subdirectory
2018-06-12 16:36:58 +01:00
Kevin Ansfield
fe8c07333d Koenig - Embed card renderer
refs https://github.com/TryGhost/Ghost/issues/9623
- add `embed` card renderer
2018-06-12 16:18:01 +01:00
Kevin Ansfield
ca20f3a6b0 Added /oembed API endpoint
refs https://github.com/TryGhost/Ghost/issues/9623
- add `oembed-parser` module for checking provider availability for a url and fetching data from the provider
  - require it in the `overrides.js` file before the general Promise override so that the `promise-wrt` sub-dependency doesn't attempt to extend the Bluebird promise implementation
- add `/oembed` authenticated endpoint
  - takes `?url=` query parameter to match against known providers
  - adds safeguard against oembed-parser's providers list not recognising http+https and www+non-www
  - responds with `ValidationError` if no provider is found
  - responds with oembed response from matched provider's oembed endpoint if match is found
2018-06-12 16:18:01 +01:00
kirrg001
f25f7ac54b 🐛 Fixed slug template for tags and authors
no issue

- was introduced with dynamic routing beta: https://github.com/TryGhost/Ghost/releases/tag/1.24.0
- the slug param wasn't forwarded correctly
- you were not able to render a custom tag or author template e.g. `tag-news.hbs`
2018-06-11 22:06:47 +02:00
kirrg001
e4807a779c 🐛 Fixed default theme context
closes #9674

- the collection router had a hardcoded default context "home"
  - this is wrong
- the context array get's automatically filled for the collection
  - if you are serving a page e.g. /page/2/ -> it's "paged"
  - if you are serving / -> it's "home"
    - same for {{body_class}}, it outputs "home-template" on "/"
    - this is the same behaviour as in 1.23.x
2018-06-08 15:11:47 +02:00
kirrg001
2d70b8fe20 🐛 Fixed template order not being respected after refresh
no issue

- reverse must happen once in the constructor
- otherwise we reverse the array on each request
  - Ghost would randomly pick the first and then the second template
2018-06-08 15:11:43 +02:00
kirrg001
839d82b398 🐛 Fixed post redirect with query params
no issue

- reported here: https://forum.ghost.org/t/best-practice-for-appending-a-query-string-to-a-post/1535
- there was a bug that query params were not respected and this ended in a 301 redirect losing them
2018-06-07 09:52:51 +02:00
kirrg001
3155ea2aa7 🐛 Fixed urls being /404/ after starting the Ghost server
no issue

- there was a timing bug in Ghost
- we do operations in parallel on bootstrap
  - 1) we fetch the resources as early as possible
  - 2) we do all the rest (express bootstrapping, theme loading, router registration) etc.
- it can happen that (2) happens too slow and ends in the situation that the queue, which is responsible
  to handle both parallel actions, does not wait for the routers and closes the event
- this is a short term fix
- i need to reconsider if there is a better long term fix
2018-06-07 09:27:24 +02:00
Katharina Irrgang
b392d1925a
Dynamic Routing Beta (#9596)
refs #9601

### Dynamic Routing

This is the beta version of dynamic routing. 

- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation 
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
  - yaml file + validation
  - routing + routers
  - url service
  - sitemaps
  - url access
- deeper implementation of yaml validations
  - e.g. hard require slashes
- ensure routing hierarchy/order
  - e.g. you enable the subscriber app
  - you have a custom static page, which lives under the same slug /subscribe
  - static pages are stronger than apps
  - e.g. the first collection owns the post it has filtered
  - a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
  - e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
  - and you change the permalink in the admin to dated permalink
  - the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
  - unmount without server restart, yey
- ensure we are backwards compatible
  - e.g. render home.hbs for collection index if collection route is /
  - ensure you can access your configured permalink from the settings table with {globals.permalink}

### Render 503 if url service did not finish

- return 503 if the url service has not finished generating the resource urls

### Rewrite sitemaps

- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
  - the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)

### Re-work usage of Url utility

- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
  - only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 19:02:20 +02:00
Tien Do
3afc2654aa 🐛Fixed short urls when private blogging is enabled (#9628)
close #9578

- updated condition to disable RSS for private blog
- use regex
- ensure private rss feed still works
2018-06-04 18:57:18 +02:00
kirrg001
0ccc24bf11 Removed old jshint/jscs rules
refs bcf5a1bc34

- leftovers
2018-06-02 21:48:23 +02:00
kirrg001
dd668892d7 Removed more 'use strict' usages
no issue

- after we have dropped node 4, we have removed all 'use strict' usages
- but they came back from older pull requests
2018-06-02 21:38:11 +02:00
Kevin Ansfield
6c1e5511fc 🐛 Fixed infinite redirect when subdirectory equals top level domain (#9621)
closes https://github.com/TryGhost/Ghost/issues/9620

- adjust the `deduplicateSubDir` function's regex to only match duplicate subdirectories when the `url` is only a path rather than full url or the duplicate match starts with a `/`
2018-05-28 12:18:34 +02:00
Kevin Ansfield
ee31157040 Koenig - Fix broken image card tests
refs https://github.com/TryGhost/Ghost/issues/9505
- update tests to match loose BEM image style classes
2018-05-22 09:43:53 +01:00
ololoken
86c28e382e 🐛 Fixed /edit shortcut not working in Safari (#9637)
closes #9633 
- use non-hash URL for admin redirects so that redirects are followed correctly by Safari when admin is on different domain
2018-05-21 15:26:32 +01:00
Aileen Nowak
6e117e63fb 🐛 Fixed gscan errors not caught for corrupted zips
closes TryGhost/Support#426
refs TryGhost/gscan#106
needs TryGhost/gscan#107

GScan can return errors, which was not handled in our theme validator and caused Ghost to crash completely. GScan will now return an Ignition error when its not able to read the `.zip` file.

e. g.: `{"errors":[{"message":"Failed to read zip file","context":"tife.zip","errorType":"ValidationError","errorDetails":"invalid relative path: ../tife/"}]}`
2018-05-16 10:20:30 +08:00
Kevin Ansfield
f54db75ed1 Koenig - Code card server-side rendering
refs https://github.com/TryGhost/Ghost/issues/9623
- add support for `code` card that renders into `<pre><code>...</code></pre>`
- render language class if one is provided
2018-05-15 16:27:34 +01:00
Kevin Ansfield
bd75d7551d Koenig - Remove developer experiments flag requirement
refs https://github.com/TryGhost/Ghost/issues/9505
- remove requirement for the `enableDeveloperExperiments` flag to be able to use Koenig
- it's now possible to enable as a standard Labs beta feature
2018-05-15 13:20:40 +01:00
Kevin Ansfield
367c5b9639 Koenig - Fixed empty HTML card rendering undefined
refs https://github.com/TryGhost/Ghost/issues/9623
- add tests for undefined payloads in container cards
- add guard for undefined payload in html card
2018-05-15 10:09:52 +01:00
Kevin Ansfield
e953a1c3a8
Koenig - Versioned renderer (#9606)
refs https://github.com/TryGhost/Ghost/issues/9505
- updates mobiledoc converter's `render` method to accept a `version` argument
    - `1` === Ghost 1.0's markdown-only renderer output
    - `2` === Koenig's full mobiledoc renderer output
- switch between mobiledoc renderer versions in Post model's `onSaving` hook
    - version 1 by default
    - version 2 if Koenig is enabled (currently behind dev experiments config + labs flag)
    - version 2 if the post's mobiledoc is not compatible with the markdown-only renderer
- "version 2" full-Koenig mobiledoc renderer output
    - wraps content in a `.kg-post` div
    - removes wrapper around markdown and html card output
    - adds classes to image card output including selected image size/style
- standardises es6 usage across mobiledoc related files
2018-05-04 14:59:39 +01:00
kirrg001
5f5f0021db 🔥 Drop Node v4 Support
no issue

- support ends today
- see https://github.com/nodejs/Release
- removed `use strict`
2018-05-01 14:06:18 +02:00
kirrg001
ab5199267b Renamed urlService.getUrl to urlService.getUrlByResourceId
no issue

- explicit function naming
- no functional change, only renaming
2018-04-25 19:37:39 +02:00
kirrg001
02abe3862e Use bookshelf-relations for Permission model: roles
refs https://github.com/TryGhost/Ghost/pull/9592

- we add bookshelf-relations step by step if we need it
- with https://github.com/TryGhost/Ghost/pull/9592 we have rewritten the test env to use Bookshelf
  - this is important for our new url service
  - because the service is listening on model updates and updates the urls based on the model events
- so with moving to Bookshelf, we need any easy way to add relations
  - the test env inserts test fixtures
  - it adds permissions and each permission get's roles attached
  - `models.Permission.add({roles: [...]})
2018-04-25 12:27:39 +02:00
kirrg001
27ebc3d1ac Added unit tests for models.Invite.add
no issue

- replaced token creation by `lib.common.security`
- added unit tests for adding invites
- allow a different invite status for internal access
2018-04-25 11:56:45 +02:00
kirrg001
6ac00255e3 Renamed resources to taxonomies in default routes yaml file
refs https://github.com/TryGhost/Team/issues/65

- this was incorrect
- we don't use the wording `resources` in the routes yaml file
2018-04-21 01:17:52 +02:00
kirrg001
0ac19dcf84 Load yaml settings files synchronously
refs https://github.com/TryGhost/Team/issues/65

- it's easier for the architecture if we read the setting files synchronously,
  because the dynamic routing component is part of the express bootstrap and
  the whole routing bootstrap is synchronously
- for now: we only read one file anyway
- it's for now easier to read the file synchronously, then i don't have to change
  any existing express bootstrap architecture
2018-04-20 15:25:06 +02:00
Vikas Potluri
ce98d272fe Removed unnecessary type attribute in script tags (#9586)
closes #9585

- for reference: https://stackoverflow.com/questions/3485606/will-removing-the-type-from-a-script-tag-break-in-any-browsers
2018-04-18 14:33:31 +02:00
kirrg001
097e1d1fac Url Service: trigger url event with relative/absolute urls
refs https://github.com/TryGhost/Team/issues/65

- this is just the first optimisation regarding relative/absolute urls
- the full strike will happen when i start with the url utility re-write
- for now: there will be only one subscriber of url events -> the sitemaps service
- the sitemaps service outputs absolute urls
  - we don't want to receive an url event and ask the url service again to get an absolute version of the url
2018-04-18 11:33:46 +02:00
Rosco Kalis
2a4d759b78 🎨Removed seconds option from {{reading_time}} (#9573)
closes #9569

- Removed the `<1 min read` time clause, effectively making `1 min read` the minimum reading time
- Removed the `seconds` option for i18n strings, which contained the less than one minute display string
- Kept the other i18n string options the same
- Amended and improved tests for new functionality
2018-04-18 10:55:08 +08:00
kirrg001
79c790c891 Fixed url service did not respect subdirectory setup's
refs https://github.com/TryGhost/Team/issues/65

- currently we generate a relative resource url
- if you configure a subdirectory, the urls have to respect that
  - e.g. you configure `localhost:2368/blog`, your url results in e.g. `/blog/my-post/`
- this is not yet a critical bug, because the url service is not connected yet

- @TODO: consider absolute vs. relative urls in the url service
2018-04-17 15:52:57 +02:00
Katharina Irrgang
6a4af1f465
Rewrite url service (#9550)
refs https://github.com/TryGhost/Team/issues/65

We are currently work on dynamic routing (aka channels).
An important piece of this feature is the url service, which always knows the url of a resource at any time.
Resources can belong to collections or taxonomies, which can be defined in a [routing yaml file](https://github.com/TryGhost/Ghost/issues/9528). We are currently shipping portions, which will at end form the full dynamic routing feature.

### Key Notes

- each routing type (collections, taxonomies, static pages) is registered in order - depending on the yaml routes file configuration
- static pages are an internal concept - they sit at the end of the subscriber queue
- we make use of a temporary [`Channels2`](https://github.com/TryGhost/Ghost/pull/9550/files#diff-9e7251409844521470c9829013cd1563) file, which simulates the current static routing in Ghost (this file will be modified, removed or whatever - this is one of the next steps)
- two way binding: you can ask for a resource url based on the resource id, you can ask for the resource based on the url
- in theory it's possible that multiple resources generate the same url: we don't handle this with collision (because this is error prone), we handle this with the order of serving content. if you ask the service for a resource, which lives behind e.g. /test/, you will get the resource which is served
- loose error handling -> log errors and handle instead of throw error and do nothing (we log the errors with a specific code, so we can react in case there is a bug)
- the url services fetches all resources on bootstrap. we only fetch and keep a reduced set of attributes (basically the main body of a resource)
- the bootstrap time will decrease a very little (depending on the amount of resources you have in your database)
- we still offer the option to disable url preloading (in your config `disableUrlPreload: true`) - this option will be removed as soon as the url service is connected. You can disable the service in case you encounter a problem
- **the url service is not yet connected, we will connect the service step by step. The first version should be released to pre-catch bugs. The next version will add 503 handling if the url service is not ready and it will consume urls for resources.**


----

- the url service generates urls based on resources (posts, pages, users, tags)
- the url service keeps track of resource changes
- the url service keeps track of resource removal/insert
- the architecture:
  - each routing type is represented by a url generator
    - a routing type is a collection, a taxonomiy or static pages
  - a queue which ensures that urls are unique and can be owned by one url generator
    - the hierarchy of registration defines that
  - we query knex, because bookshelf is too slow
- removed old url service files + logic
- added temp channels alternative (Channels2) -> this file will look different soon, it's for now the temporary connector to the url service. Also the name of the file is not optimal, but that is not really important right now.
2018-04-17 11:29:04 +02:00
kirrg001
defe65c2de Tests: extended knex mock
no issue

- support more cases
  - e.g. multiple where matches
- @TODO
  - take time to look for NPM module, which does this already
  - test sqlite3 :memory: mode again
2018-04-16 00:29:17 +02:00
Aileen Nowak
63642fd8ad YAML settings loader and parser
closes #9528

These code changes introduce a YAML parser which will load and parse YAML files from the `/content/settings` directory. There are three major parts involved:

1. `ensure-settings.js`: this fn takes care that on bootstrap, the supported files are present in the `/content/settings` directory. If the files are not present, they get copied back from our default files. The default files to copy from are located in `core/server/services/settings`.

2. `loader.js`: the settings loader reads the requested `yaml` file from the disk and passes it to the yaml parser, which returns a `json` object of the file. The settings loader throws an error, if the file is not accessible, e. g. because of permission errors.

3. `yaml-parser`: gets passed a `yaml` file and returns a `json` object. If the file is not parseable, it returns a clear error that contains the information, what and where the parsing error occurred (e. g. line number and reason).

- added a `get()` fn to settings services, that returns the settings object that's asked for. e. g. `settings.get('routes').then(()...` will return the `routes` settings.
- added a `getAll()` fn to settings services, that returns all available settings in an object. The object looks like: `{routes: {routes: {}, collections: {}, resources: {}}, globals: {value: {}}`, assuming that we have to supported settings `routes` and `globals`.

Further additions:
- config `contentPath` for `settings`
- config overrides for default `yaml` files location in `/core/server/services/settings`

**Important**: These code changes are in preparation for Dynamic Routing and not yet used. The process of copying the supported `yaml` files (in this first step, the `routes.yaml` file) is not yet activated.
2018-04-15 19:40:22 +02:00
Katharina Irrgang
7273786459
Fetch relations by default when insert/updating posts (#9568)
no issue

- required for model events
- otherwise you won't receive a full data set
  - in worst case you have to re-fetch the post
- required for the url service
  - the url service always needs relations (authors,tags) to be able to generate the url properly

@IMPORTANT
- no API change, we still return what you are asking for
  - we first edit/add the resource
  - then we fetch the data with the API options
  - @TODO: this can be optimised and will improve performance
    	   picking/selecting it from the insert/update response
- this is an internal change
2018-04-15 12:12:20 +02:00
Kevin Ansfield
3a27e557ed Protect generated post.html and post.plaintext fields (#9559)
closes https://github.com/TryGhost/Ghost/issues/9512

- loop through list of generated fields in `Post.onSaving` and reset their values if a new value was passed in via attributes
2018-04-10 22:45:31 +02:00
kirrg001
d209a4d013 🐛 Fixed importer bug: can't resolve authors relation
closes #9547

- you setup a blog with the following owner:
  - email: test@ghost.org
  - name: test
  - slug: test
- now you import a JSON db file, which holds the exact same owner
  - this owner won't be imported, because it's a duplicate
  - but the slug is different (!)
- the importer tries to find a matching existing user, but won't find anything
- the importer then send an empty authors array `post.authors=[]` into the model layer
- this is not allowed -> this would mean, you are actively trying to unset all authors
2018-04-10 01:10:06 +02:00
kirrg001
f114f45740 Added a post unit test to proof a bug
no issue

- permalink: /:primary_tag/:slug/, columns: [title,url]
- will be auto resolved with channels
- the test should fail if we add channels
2018-04-06 13:36:03 +02:00
kirrg001
5a2155f814 Added tests for event behaviour: updating resources with or without updating it's relations
closes #9548

- unit test to proof which events are triggered
2018-04-05 18:51:58 +02:00
kirrg001
853b518a51 Sanitize incoming model relation data
refs #9548

- we always receive date strings from the client in ISO format
- we ensure that we transform these strings into JS dates for comparison
- when the client sends relations, we need to ensure that relations are checked as well
- will only work for the post model for now, because this is the only model which uses `bookshelf-relations`
- added unit tests
- removed some model tests, which do the same
2018-04-05 18:51:58 +02:00
kirrg001
bda76acba6 Extended the API object validation
refs #9548

- do not forward `tag.parent` to the model layer
  - the model layer should only know `tag.parent_id`
  - and the API should only expose `tag.parent` (this is an API feature)
  - currently Ghost has a mixture of using `toJSON` and the API validation layer for this
  - we just continue with this for now (no time to fix this)
- disallow sending nested-nested relations
  - unsupported
  - see comment for more information
  - this can cause problems with calling `hasChanged` on relations
- add unit tests
2018-04-05 18:51:58 +02:00
Katharina Irrgang
40d0a745df Multiple authors (#9426)
no issue

This PR adds the server side logic for multiple authors. This adds the ability to add multiple authors per post. We keep and support single authors (maybe till the next major - this is still in discussion)

### key notes

- `authors` are not fetched by default, only if we need them
- the migration script iterates over all posts and figures out if an author_id is valid and exists (in master we can add invalid author_id's) and then adds the relation (falls back to owner if invalid)
- ~~i had to push a fork of bookshelf to npm because we currently can't bump bookshelf + the two bugs i discovered are anyway not yet merged (https://github.com/kirrg001/bookshelf/commits/master)~~ replaced by new bookshelf release
- the implementation of single & multiple authors lives in a single place (introduction of a new concept: model relation)
- if you destroy an author, we keep the behaviour for now -> remove all posts where the primary author id matches. furthermore, remove all relations in posts_authors (e.g. secondary author)
- we make re-use of the `excludeAttrs` concept which was invented in the contributors PR (to protect editing authors as author/contributor role) -> i've added a clear todo that we need a logic to make a diff of the target relation -> both for tags and authors
- `authors` helper available (same as `tags` helper)
- `primary_author` computed field available
- `primary_author` functionality available (same as `primary_tag` e.g. permalinks, prev/next helper etc)
2018-03-27 15:16:15 +01:00
CriticalRespawn
60386dbba5 🐛Fixed misspelled schema.org type for WebSite (#9526)
closes #9525

- updated the schema type to 'WebSite' as it is the correct spelling according to schema.org. See [here](http://schema.org/WebSite)
2018-03-23 10:50:28 +07:00
Rosco Kalis
4013023d60 🐛Added more language support to {{reading_time}} helper (#9509)
closes #9507

- Changed the utils.wordCount implementation to the one used by simpleMDE
- Added extra À-ÿ to the regex to support diacritics characters
- Added corresponding text with Chinese text mentioned in the issue
2018-03-22 10:27:02 +07:00
Mante Bridts
7ed822cc0c 🐛Fixed i18n for the {{meta_title}} helper (#9468)
closes #9466

- make 'page' in the meta title translatable through subexpression in the meta title helper
- e.g. `{{meta_title page=(t....)}}`
2018-03-19 09:48:07 +01:00
Vikas Potluri
63aeebb144 🐛 Fixed escaping < in reading time helper (#9508)
no issue

Using the < character raw isn't w3 complaint
2018-03-19 09:47:58 +07:00
Kevin Ansfield
7548ace32d Koenig - Output captions for image and embed cards
refs https://github.com/TryGhost/Ghost/issues/9311
- very basic implementation, still needs proper classes and default stylesheet implementation
- change image card output to a `<figure>` with optional `<figcaption>`
- add optional `<p>` caption output to the html card
2018-03-14 18:21:30 +00:00
Rosco Kalis
301e1b2419 🎨Improved image counting for the {{reading_time}} helper (#9366)
refs #9200

- We have not yet counted the images within your html, this commit counts images based on the this algorithm: https://blog.medium.com/read-time-and-you-bc2048ab620c
- Added imageCount utility, which counts images using an img-tag regex, amended from the general tag-regex found in wordCount
- Added this imageCount to the {{reading_time}} helper, adding 12 seconds to the reading time for every image
- The feature image is still counted as before
- The first image adds 12 seconds, the second 11, the third 10, and so on
- Images from the tenth onwards add 3 seconds to the reading time
2018-03-05 09:30:15 +01:00
Aileen Nowak
1da2eec915 🐛Fixed image properties to be reset to null after removal (#9432)
closes #9085

Fixes an issue, where the client sets image properties to `""` after deleting the image. This causes problems with the query filter (see https://github.com/TryGhost/GQL/issues/24), as they have to be `null`.

Added a check in the model layer saving method to set value  to `null`, when the property is empty.

Affected models and properties:
- `posts`:
	- `feature_image`
	- `og_image`
	- `twitter_image`
- `users`:
	- `profile_image`
	- `cover_image`
- `tags`:
	- `feature_image`
2018-03-05 09:10:27 +01:00
kirrg001
e01b61dcf4 Proper error handling for permissible implementations
no issue

- currently if you would like to edit a resource (e.g. post) and you pass an invalid model id, the following happens
  - permission check calls `Post.permissible`
  - the Post could not find the post, but ignored it and returned `userPermissions:true`
  - then the model layer is queried again and figured out that the post does not exist
- A: there is no need to query the model twice
- B: we needed proper error handling for post and role model
2018-02-21 16:59:48 +01:00
Katharina Irrgang
0aff9f33d9
Improved validation layer (#9427)
refs https://github.com/TryGhost/Ghost/issues/3658

- the `validateSchema` helper was a bit broken
  - if you add a user without email, you will receive a database error
  - but the validation error should catch that email is passed with null
- it was broken, because:
  - A: it called `toJSON` -> this can remove properties from the output (e.g. password)
  - B: we only validated fields, which were part of the JSON data (model.hasOwnProperty)
- we now differentiate between schema validation for update and insert
- fixed one broken import test
  - if you import a post without a status, it should not error
  - it falls back to the default value
- removed user model `onValidate`
  - the user model added a custom implementation of `onValidate`, because of a bug which we experienced (see https://github.com/TryGhost/Ghost/issues/3638)
  - with the refactoring this is no longer required - we only validate fields which have changed when updating resources
  - also, removed extra safe catch when logging in (no longer needed - unit tested)
- add lot's of unit tests to proof the code change
- always call the base class, except you have a good reason
2018-02-16 00:49:15 +01:00
kirrg001
355ef54702 Removed isNew usages in model layer
no issue

- `isNew` does not work in Ghost, because Ghost does not use auto increment id's
- see https://github.com/bookshelf/bookshelf/issues/1265
- see https://github.com/bookshelf/bookshelf/blob/0.10.3/src/base/model.js#L211
- we only had one occurance, which was anyway redundant
  - if you add a user, `hasChanged('password') is true
  - if you edit a user and the password has changed, `hasChanged('password')` is true as well

NOTE #1:

1. We can't override `isNew` and throw an error, because bookshelf makes use of `isNew` as well, but it's a fallback if `options.method` is not set.
2. It's hard to re-implement `isNew` based on `options.method`, because then we need to ensure that this value is always set (requires a couple of changes)

NOTE #2:
If we need to differentiate if a model is new or edited, we should manually check for `options.method === insert`.

NOTE #3:
The unit tests are much faster compared to the model integration tests.
I did a comparision with the same test assertion:
  - unit test takes 70ms
  - integration test takes 190ms
2018-02-15 22:11:49 +01:00
kirrg001
2b76d7a492 Added lib.security.password lib
no issue

- move password hashing and password comparison to lib/security/password
- added two unit test
- FYI: password hashing takes ~100ms
  - we could probably mock password hashing in certain cases when unit testing
2018-02-15 21:13:04 +01:00
Katharina Irrgang
c6a95c6478
Sorted out the mixed usages of include and withRelated (#9425)
no issue

- this commit cleans up the usages of `include` and `withRelated`.

### API layer (`include`)
- as request parameter e.g. `?include=roles,tags`
- as theme API parameter e.g. `{{get .... include="author"}}`
- as internal API access e.g. `api.posts.browse({include: 'author,tags'})`
- the `include` notation is more readable than `withRelated`
- and it allows us to use a different easier format (comma separated list)
- the API utility transforms these more readable properties into model style (or into Ghost style)

### Model access (`withRelated`)
- e.g. `models.Post.findPage({withRelated: ['tags']})`
- driven by bookshelf

---

Commits explained.

* Reorder the usage of `convertOptions`

- 1. validation
- 2. options convertion
- 3. permissions
- the reason is simple, the permission layer access the model layer
  - we have to prepare the options before talking to the model layer
- added `convertOptions` where it was missed (not required, but for consistency reasons)

* Use `withRelated` when accessing the model layer and use `include` when accessing the API layer

* Change `convertOptions` API utiliy

- API Usage
  - ghost.api(..., {include: 'tags,authors'})
  - `include` should only be used when calling the API (either via request or via manual usage)
  - `include` is only for readability and easier format
- Ghost (Model Layer Usage)
  - models.Post.findOne(..., {withRelated: ['tags', 'authors']})
  - should only use `withRelated`
  - model layer cannot read 'tags,authors`
  - model layer has no idea what `include` means, speaks a different language
  - `withRelated` is bookshelf
  - internal usage

* include-count plugin: use `withRelated` instead of `include`

- imagine you outsource this plugin to git and publish it to npm
- `include` is an unknown option in bookshelf

* Updated `permittedOptions` in base model

- `include` is no longer a known option

* Remove all occurances of `include` in the model layer

* Extend `filterOptions` base function

- this function should be called as first action
- we clone the unfiltered options
- check if you are using `include` (this is a protection which could help us in the beginning)
- check for permitted and (later on default `withRelated`) options
- the usage is coming in next commit

* Ensure we call `filterOptions` as first action

- use `ghostBookshelf.Model.filterOptions` as first action
- consistent naming pattern for incoming options: `unfilteredOptions`
- re-added allowed options for `toJSON`
- one unsolved architecture problem:
  - if you override a function e.g. `edit`
  - then you should call `filterOptions` as first action
  - the base implementation of e.g. `edit` will call it again
  - future improvement

* Removed `findOne` from Invite model

- no longer needed, the base implementation is the same
2018-02-15 10:53:53 +01:00
Hannah Wolfe
fe0197b226 🐛Fixed {{get}} helper's date comparison (#9454)
no issue

- Date comparisons are possible via API, but there's no way to inject a valid date into the get helper
- JavaScript's Date.toString() function outputs dates in a useless format
- Swap to using Date.toISOString() and now the format can be understood anywhere!
- {{#get "posts" filter="published_at:<='{{published_at}}'"}}{{/get}} works now as expected
2018-02-14 18:33:07 +01:00
Austin Burdine
777247cbc7 Contributor Role (#9315)
closes #9314 

* added fixtures for contributor role
* update post api tests to prevent contributor publishing post
* update permissible function in role/user model
* fix additional author code in invites
* update contributor role migration for knex-migrator v3
* fix paths in contrib migration
* ensure contributors can't edit or delete published posts, fix routing tests [ci skip]
* update db fixtures hash
* strip tags from post if contributor
* cleanup post permissible function
* excludedAttrs to ignore tag updates for now (might be removed later)
* ensure contributors can't edit another's post
* migration script for 1.21
2018-02-07 10:46:22 +01:00