refs #7489
* 🎨 protect error when creating owner
* 🎨 reset migration table
- temporary solution, see TODO's
* 🎨 use sephiroth in bootUp script
- do not populate the database
- ask sephiroth for database state
- do seeding manually (this will be removed in next seeding PR)
* 🎨 rewrite createTableIfNotExists because it causes error when running twice
- see knex issue
- hasTable and createTable
- indexes can cause trouble when calling them twice
* 🎨 tests: populate db in test env
- when forking db
- when starting ghost()
- this basically affects only the functional tests
* 🎨 server spec test adaption
- we now throw an error when database is not populated, instead of populating the database
* 🎨 migration spec adaption
- reset database now deletes migration table
- we will move the reset script into sephiroth and then we make it pretty
* 🎨 error creation adaption in bootUp
* 🎨 fixes
- sephiroth error handling
- fix tests
refs #4172
* 🎨 Use bodyParser only where it is needed
This is a pretty extreme optimisation, however in the interests of killing middleware/index.js it
seemed prudent to move towards not having in there that wasn't strictly necessary 😁
We should reassess how apps do this sort of thing, but it seems pretty sane to declare bodyParsing
if and only if it is necessary.
* 🎨 Move all API code to API router
* 🎨 Refactor API into an App, not just a router
- Apps have their own rendering engines, only the frontend & the admin panel need views
- The API should be JSON only, with minimal middleware
- Individual sections within the API could/should be treated as Routers
* 🎨 Flatten API middleware inclusion
- get rid of the weird middleware object
- move the api-only middleware into the middleware/api folder
- we can see the logging mode as HTTP mode
- standalone logging should still log everything
- tidy up the PrettyStreamer a little big and add current expectation tests
* 💄 Combine slashes & uncapitalise middleware
- these bits of middleware belong together
- ideally they should be optimised
* 🎨 Move ghostLocals out of themeHandler
GhostLocals sets several important values which are needed for every part of the application,
admin, api and theme. Therefore, it doesn't make sense for it to be bundled in the themeHandler.
* 🐛 Fix the uncapitalise middleware
- Updated to make correct use of req.baseUrl, req.path, req.url & req.originalUrl
- Updated the tests to actually cover our weird cases
* 🎨 Move ghostVersion logic out of config
* 💄 Group static / asset-related middleware together
* 🔥 Remove /shared/ asset handling
- The 5 files which are located in `/shared/` are all handled by individual calls to `serveSharedFile`
- Therefore this code is redundant
closes#2597
- Remove .archive-template
- Remove .page
- Don't output .post-template on pages
- Use `page-slug` instead of `page-template-slug`
- Always output `page-slug` irrelevant of whether or not there is a custom template
closes#6165
- internal tags has been in labs for a couple of months, we've fixed some bugs & are ready to ship
- removes all code that tests for the labs flag
- also refactors the various usage of the visibility filter into a single util
- all the tests still pass!!!
- this marks #6165 as closed because I think the remaining UI tasks will be handled as part of a larger piece of work
refs #7489
- new database versioning scheme which is based upon the Ghost version, and so easier to reason about
- massive refactor of all the version related code
Summary of changes:
* ✨ new error: DatabaseNotSeeded
* 🎨 change versioning module
- versioning is based on Ghost Version
* 🎨 change bootUp file
- add big picture description
- version error get's trigger from versioning module
* 🎨 default setting for database version is null
- very important change: this is caused by the big picture
- see bootUp description
- the database version get's set by the seed script later
- db version is by default null
- 1. population happens (we ensure that this has finished, by checking if each table exists)
- 2. seeds happening (we ensure that seeds happend if database version is set to X.X)
* 🎨 temporary change for population logic
- set database version after population happens
- ensure population of default settings happend before
- both: get's removed in next iteration
* 🎨 adapt tests && mark TODO's
* 🎨 err instance checking
refs #7116, refs #2001
- Changes the way Ghost errors are implemented to benefit from proper inheritance
- Moves all error definitions into a single file
- Changes the error constructor to take an options object, rather than needing the arguments to be passed in the correct order.
- Provides a wrapper so that any errors that haven't already been converted to GhostErrors get converted before they are displayed.
Summary of changes:
* 🐛 set NODE_ENV in config handler
* ✨ add GhostError implementation (core/server/errors.js)
- register all errors in one file
- inheritance from GhostError
- option pattern
* 🔥 remove all error files
* ✨ wrap all errors into GhostError in case of HTTP
* 🎨 adaptions
- option pattern for errors
- use GhostError when needed
* 🎨 revert debug deletion and add TODO for error id's
no issue
- unsued code:
- there are no public assets anymore, might need to use this instead of shared in future, but for now lets remove it to reduce confusion
- the `input password` box was incorrectly registered as an admin helper, thinking that was needed in order to render the default template. This isn't needed.
- apps:
- small structure & comment update to amp app
- moving input_password helper into private blogging app
- refactor helpers in subscribers app
- 🛠 add bunyan and prettyjson, remove morgan
- ✨ add logging module
- GhostLogger class that handles setup of bunyan
- PrettyStream for stdout
- ✨ config for logging
- @TODO: testing level fatal?
- ✨ log each request via GhostLogger (express middleware)
- @TODO: add errors to output
- 🔥 remove errors.updateActiveTheme
- we can read the value from config
- 🔥 remove 15 helper functions in core/server/errors/index.js
- all these functions get replaced by modules:
1. logging
2. error middleware handling for html/json
3. error creation (which will be part of PR #7477)
- ✨ add express error handler for html/json
- one true error handler for express responses
- contains still some TODO's, but they are not high priority for first implementation/integration
- this middleware only takes responsibility of either rendering html responses or return json error responses
- 🎨 use new express error handler in middleware/index
- 404 and 500 handling
- 🎨 return error instead of error message in permissions/index.js
- the rule for error handling should be: if you call a unit, this unit should return a custom Ghost error
- 🎨 wrap serve static module
- rule: if you call a module/unit, you should always wrap this error
- it's always the same rule
- so the caller never has to worry about what comes back
- it's always a clear error instance
- in this case: we return our notfounderror if serve static does not find the resource
- this avoid having checks everywhere
- 🎨 replace usages of errors/index.js functions and adapt tests
- use logging.error, logging.warn
- make tests green
- remove some usages of logging and throwing api errors -> because when a request is involved, logging happens automatically
- 🐛 return errorDetails to Ghost-Admin
- errorDetails is used for Theme error handling
- 🎨 use 500er error for theme is missing error in theme-handler
- 🎨 extend file rotation to 1w
refs #7452
- remove references to 'patronus' in favour of GhostAuth, Note: this will require databases to be deleted ;)
- remove email addresses from test data
* 🎨 run database population in transaction
refs #6574, refs #7432
- create transaction for creating tables
- if an error occurs or a container get's destroyed before population finishes, transaction is rolled back
* 🎨 simplify transaction creation and test
issue #7452
Remote oauth2 authentication with Ghost.org.
This PR supports:
- oauth2 login or local login
- authentication on blog setup
- authentication on invite
- normal authentication
- does not contain many, many tests, but we'll improve in the next alpha weeks
- Don't let people start Ghost Alpha with non-alpha databases.
- Provide a new welcome message for development mode (a little bit of positive reinforcment)
- Provide a RED WARNING when in production mode (will still be used for developing, but we can ignore)
- Change package.json to 1.0.0-alpha.0, we won't relelase this, will bump to .1 for release
refs #6982
- create config util fn: getContentPath
- we can later let the user change the folder names in contentPath
- get rid of custom/default storage paths
[ci skip]
closes#7313
- Adds `getSanitizedFileName` function to storage/base.js which replaces non A-Z0-9@. chacracters with -
- modifies /api/theme.js so that zip.shortName is consistent throughout.
closes#7192
- add 008 migration
- added script to re-run 006/01
- re-run 006/01 migration for postgres in any timezone (transform formats only)
- re-run 006/01 migration for sqlite (transform formats only)
- rely on format checks for sqlite, do not check server TZ
* 🐛 fix direct update
closes#7297
- move sitemap initialisation into sitemap handler
- initialise sitemap on first request to sitemap
* 🐛 fix how we pass options to migration files
refs #7317
- clone options when passing them into the migration/fixture files
- do not use default sequence, because it does not clone the arguments
refs #7305
* 🎨 display upgrade alerts with the correct "info" style
* 💄 update use of notifications status/type/location attrs to reflect current usage
no issue
This PR takes the existing function `processUrls` in `data/xml/rss` and refactors it to be a stand-alone util.
The change is needed, as this functionality will be accessed from `apps/amp` to convert relative URLs.
closes#7186
- Add a concept of validity to each generator
- Refactor base generator to handle invalid (empty) nodes for both events & the initial generation
- Update the tests a bit, to fix some bugs in the tests
- Ensure the homepage is always present
refs #7204
- Adds a new ThemeValidationError class
- This error has a top level message, but will also contain all the individual errors within the `errorDetails` property
- Updated the API error handling to return `errorDetails` if it is present
no issue
Double slashes are treated as a HTTP calls as specified in [RFC1801](http://www.ietf.org/rfc/rfc1808.txt). Because of this behaviour the uncapitalise created an open redirect. By removing double slashes in the path we ensure open redirects cannot be created.
As an example, please click the following URL: https://dev.ghost.org///Google.com/.
This issue has been reported by pentesters of our product [LearningSpaces.io](http://learningspaces.io).
refs #2852
- improvement: ensure custom storage adapter has required functions
- serve, save and exists are from now on required functions for a custom storage adapter
- add delete as required storage function
closes#6588, #7095
* `ImageObject` with image dimensions (#7152, #7151, #7153)
- Returns meta data as promise
- returns a new Promise from meta data
- uses `Promise.props()` to resolve `getClient()` and `getMetaData()`
- Adds 'image-size' util
The util returns an object like this
```
{
height: 50,
url: 'http://myblog.com/images/cat.jpg',
width: 50
};
```
if the dimensions can be fetched and rejects with error, if not.
In case we get a locally stored image or a not complete url (like `//www.gravatar.com/andsoon`), we add the protocol to the incomplete one and use `urlFor()` to get the absolute URL. If the request fails or `image-size` is not able to read the file, we reject with error.
- adds 'image-size' module to dependencies
- adds `getImageSizeFromUrl` function that returns image dimensions
- In preparation of AMP support and to improve our schema.org JSON-LD and structured data, I made the following changes:
- Changes the following properties to be `Objects`, which have a `url` property by default and a `dimensions` property, if `width` and `height` are available:
- `metaData.coverImage`
- `metaData.authorImage`
- `metaData.blog.logo`
- Checks cache by calling `getCachedImageSizeFromUrl`. If image dimensions were fetched already, returns them from cache instead of fetching them again.
- If we have image dimensions on hand, the output in our JSON-LD changes from normal urls to be full `ImageObjects`. Applies to all images and logos.
- Special case for `publisher.logo` as it has size restrictions: if the image doesn't fulfil the restrictions (<=600 width and <=60 height), we simply output the url instead, so like before.
- Adds new property for schema.org JSON-LD: `mainEntityOfPage` as an Object.
- Adds additional Open Graph data (if we have the image size): `og:image:width` and `og:image:height`
- Adds/updates tests
* AMP router and controller (#7171, #7157)
Implements AMP in `/apps/`:
- renders `amp.hbs` if route is `/:slug/amp/`
- updates `setResponseContext` to set context to `['amp', 'post']` for a amp post and `['amp', 'page']` for a page, but will not render amp template for a page
- updates `context_spec`
- registers 'amp' as new internal app
- adds the `amp.hbs` template to `core/server/apps/amp` which will be the default template for AMP posts.
- adds `isAmpURL` to `post-lookup`
* 🎨 Use `context` in meta as array (#7205)
Instead of reading the first value of the context array, we're checking if it includes certain context values.
This is a preparation change for AMP, where the context will be delivered as `['amp', 'post']`.
* ✨ AMP helpers (#7174, #7216, #7215, #7223)
- Adds AMP helpers `{{amp_content}}`, `{{amp_component}}` and `{{amp_ghost_head}}` to support AMP:
- `{{amp_content}}`:
- Adds `Amperize` as dependency
- AMP app uses new helper `{{amp_content}}` to render AMP HTML
- `Amperize` transforms regular HTML into AMP HTML
- Adds test for `{{amp_content}}` helper
- Adds 'Sanitize-HTML` as dependendy
- After the HTML get 'amperized' we still might have some HTML tags, which are prohibited in AMP HTML, so we use `sanitize-html` to remove those. With every update, `Amperize` gets and it is able to transform more HTML tags, they valid AMP HTML tags (e. g. `video` and `amp-video`) and will therefore not be removed.
- `{{amp_ghost_head}}`:
- registers `{{amp_ghost_head}}` helper, but uses `{{ghost_head}}` code
- uses `{{amp_ghost_head}}` in `amp.hbs` instead of `{{ghost_head}}`
- `{{ghost_head}}`:
- Render `amphtml` link in metadata for post, which links to the amp post (`getAmpUrl`)
- Updates all test in metadata to support `amp` context
- Changes context conditionals to work with full array instead of first array value
- Adds conditionals, so no additional javascript gets rendered in `{{ghost_head}}`
- Removes trailing `/amp/` in URLs, so only `amphtml` link on regular post renders it
- Adds a conditional, so no code injection will be included, for an `amp` context.
- `{{amp_components}}`:
- AMP app uses new helper `{{amp_components}}` to render necessary script tags for AMP extended components as `amp-iframe`, `amp-anime` and `amp-form`
- Adds test for `{{amp_components}}`
closes#7182
When calling `config.set()` in the settings api, we want to set the active timezone of the blog to make it available in our `settingsCache`. But because the `theme` object in the `set` prototype was already set to `Etc/UTC` as default, the `_.merge` function would always overwrite our `activeTimezone` with the default value.
This PR changes the code in the way, that we always set 'Etc/UTC' for the timezone as default, _until_ we fetched our settings and therefore the `activeTimezone` setting, so we can overwrite it.
This issue had not only influence on the date helper, but everywhere in our codebase, where we rely on reading the `timezone` from our config, instead of our settings. The `{{@blog.timezone}}` helper reflected that quiet well, as it would always show `Etc/UTC`
no issue
- Source out validation logic into a upload validation middleware for all upload types (csv, image, subscribers). This unit can be later used for Ghost 1.0 as a pre validation core unit.
- More usage of route tests than controller tests. These are use case tests, a use case only changes if the product changes
no issue
- sets `settings.activeTimezone` to best-guess based on current server time when performing the timezones migration in order to prevent unexpected changes in timezone when upgrading
closes#5071
- Send application/json requests to UpdateCheck service. New UpdateCheck service accepts JSON request
- If UpdateCheck service respponse has messages[] array, iterate over the array and create custom notifications intended for current version
- Save custom notification if its not already in the store AND its uuid is not in seenNotifications array
- When a custom notification is dismissed, store its uuid in seenNotifications array
- setup test fixtures to trigger tests properly
- api_notification_spec test to ensure custom notification can be added to store and added to seenNotifications when dismissed
- update_check_spec test to ensure custom notification can be displayed for a specific Ghost version
- added test to ensure messages meant for other versions don't create notifications
closes#6948
- the hbs engine was never initialised when server starts
- when you request a page which does not exist, express jumps directly into the error handlers
- delete some dynamic hbs engine setters in theme handler
closes#6625
- "url" and "author" fields depend on {id, published_at, slug, author_id} to construct post url.
- implemented a generic solution by defining defaultColumnsToFetch() in
base class for models.
- findPage() calls defaultColumnsToFetch() before loading models
- results are transformed by filtering out additional properties to return just the requested fields
- Added a test case to check for url and author fields
- Renamed allColumns as requestedColumns and used _.map instead of Promise.map
refs #6958 (first task of it)
-includes additional tests
-Instead of removing all slashes "/g" we now specifically remove leading and trailing slashes.
closes#6932
- new default order of posts: scheduled, draft, published
- invent orderDefaultRaw fn for each model
- each model is able to create a default raw order query
- separate count and fetch query for fetchPage, because the count query where group/order statements attached
closes#7060
- changed meta referrer from origin to origin-when-cross-origi
- made referrer policy configurable via referrerPolicy option in config js
- added example to config.example.js
-modified test to reflect new defaul origin-when-cross-origin
-added a test for configuration changed referrerPolicy
refs #7023
The template can be used for all cases (different newsletter interval, different amount of blog posts, with or without blog picture).
The template can be filled with the following data structure:
- `blog.logo` is the blog logo from settings
- `blog.title` is the title of the current blog
- `blog.url` is the URL of the blog
- `blog.twitterURL` is the twitter profile URL of the blog from settings
- `blog.facebookURL` is the facebook page URL of the blog from settings
- `blog.unsubscribe` is the link for the reader to unsubscribe from the blog
- `newsletter.interval` is the interval in words like 'weekly', 'daily', 'monthly'
- `newsletter.date` is the date of the newsletter issue in a format like 'June 9th, 2016'
- `blog.post` is expected to be an array:
- `blog.post[i].picture` is the picture of the blog post. There are also conditionals, which change the inline CSS to either show a border-top if there's no picture (in that case the HTML code, that shows the picture is not active)
- `blog.post[i].title` is the title of the current blog post
- `blog.post[i].text` is the text of the current blog post, which needs to be cut down to 278 letters, plus ending with `…`
- `blog.post[i].url` is the URL of the current blog post
- `blog.post[i].tag` is the tag of the current blog post
- `blog.post[i].author` is the author of the current blog post
Important is, that only HEX HTML entities will work, especially in Outlook. So instead of `—` we need to use `—` and `’` instead of `'` or `'` and so on.
Added unit test for newsletter template in `test/unit/mail/utils_spec.js`.
no issue
This is a fix for the default-scheduler.
When a post never had a published_at value, the oldTime for removing the job would be null. And in this case we would try to delete a job with an invalidate date.
refs #6413
- PUT endpoint to publish a post/page for the scheduler
- fn endpoint to get all scheduled posts (with from/to query params) for the scheduler
- hardcoded permission handling for scheduler client
- fix event bug: unscheduled
- basic structure for scheduling
- post scheduling basics
- offer easy option to change adapter
- integrate the default scheduler adapter
- update scheduled posts when blog TZ changes
- safety check before scheduler can publish a post (not allowed to publish in the future or past)
- add force flag to allow publishing in the past
- invalidate cache header for /schedules/posts/:id
no issue
- config.theme.timezone can be undefined, when settings are not loaded from the database
- this PR will define the default blog TZ in config
- use `Etc/UTC` as default instead of `Europe/Dublin`
closes#6406
- created listeners.js connector
- merged listeners.js with events.js (in models/base)
- set a post to draft when published_at would be in the past
- reschedule a post when published_at would be in the future
refs #6949
- Adds a new VersionMismatchError with status 400 (bad request)
- Adds middleware that checks the X-Ghost-Version header if it is provided
- If it is not provided, the middleware does nothing
- If it is provided, and the versions match, the middleware does nothing
- If it is provided, and the versions don't match, the middleware returns a VersionMismatchError
- Includes both unit and a functional test to prove the middleware works alone and as part of the whole system
no issue
- changes xmlrcp & slack `init` function to be `listen`
- update the code to use `listen` instead of `init`
- changes the tests to make sure that event listeners are not wired up
- adds 100% test coverage
Since we added slack event listeners, the xmlrpc event tests have been throwing an error:
> Unhandled rejection Error
See: http://puu.sh/phvjZ.png
This is because both xmlrpc & slack are listening to `post.published` events.
xmlrpc didn't require any extra stubbing, but the slack listener did
By turning the listeners off after the tests, we reset the environment to not impact the next event test
We probably need to do more work like this to improve the systems around event handling and
make them more robust
fixes#6919, refs #6917
- resolves the problem by guarding for `tags` being undefined or null
- If it is undefined, we don't do any tag processing
- If it is null, we don't do any tag processing
- To delete all tags, you would provide `tags: []`
- adds tests at both the model (using withRelated) and API (using includes) layers
- moves the tests for the post updateTags functionality from the tag model spec to the post model spec & cleans up a bit
issues #6406#6399
- all dates are stored as UTC with this commit
- use moment.tz.setDefault('UTC')
- add migration file to recalculate local datetimes to UTC
- store all dates in same format into our three supported databases
- add option to remeber migrations inside settings (core)
- support DST offset for migration
- ensure we force UTC in test env
- run whole migration as transaction
- extend: Settings.findOne function
- add NODE_LEVEL to print errors while running tests
- try/catch while parsing translations file
- run setup/teardown as promise or callback
- some general error improvements