Commit Graph

3230 Commits

Author SHA1 Message Date
kirrg001
f9974a91a9 Added public /site endpoint to Admin API v2
no issue
2019-02-25 13:24:19 +01:00
kirrg001
b5155e280e Returned tags & authors by default for Admin API v2
no issue

- tags, authors, authors.roles by default
2019-02-25 13:22:50 +01:00
kirrg001
28a222703b Added computed "excerpt" field to Admin API v2
no issue
2019-02-25 13:22:50 +01:00
kirrg001
e65a82833c Changed default format from html to mobiledoc for Admin API v2
no issue

- Ghost-Admin needs mobiledoc only
- Ghost-Android needs mobiledoc only
- any other client can fetch other formats using the query param
2019-02-25 13:22:50 +01:00
Nazar Gargol
f558b58c89 Combined /images* endpoints into /images/upload
- refs #10438

- /images/upload now accepts all the image uploads and distinguishes their purpuse using new `purpose` form data field
2019-02-25 19:15:16 +07:00
Kevin Ansfield
4f9e687f62 Updated mobiledoc renderer to insert begin/end HTML comments around cards
no issue

We're creating tooling to convert HTML to Ghost flavoured mobiledoc, however we have cards that allow arbitrary content without a wrapper element which means that we're unable to do a 1:1 mapping of mobiledoc->html->mobiledoc. To work around this problem we now output HTML comments before/after the output of each card so that our converter can extract card content correctly when parsing HTML.

- added `createCard` method which wraps a card's `render()` method to add begin/end comments and updated all cards to use it
- only takes affect for newly added or re-saved posts/pages
2019-02-25 18:05:01 +07:00
kirrg001
23d54803e6 Triggered webhooks with all content formats
no issue

- it make sense to include as much as possible
- webhook consumers don't need to re-fetch resources if they need a specific format
2019-02-25 09:46:50 +01:00
kirrg001
f3f3b62d19 Removed console.log
no issue
2019-02-25 09:43:32 +01:00
kirrg001
3459f38c09 Fixed webhook payload
no issue

- async code was not handled
2019-02-25 09:38:08 +01:00
kirrg001
23fed961e5 Removed requirement to provide authors for admin api keys
no issue

- we just fallback to owner user
- reason: consistent with how the importer works, easier to work with the API
2019-02-25 09:16:32 +01:00
Nazar Gargol
50ea7f0eff Added user friendly error messages to Admin API
refs #10438

- Adds new fields to errors returned from API:  help, code, and id
- Makes `message` more descriptive towards non technical users
2019-02-25 10:40:35 +07:00
Kevin Ansfield
792c2608c5 Added kg-card-hascaption class to image/gallery/embed cards with captions
refs https://github.com/TryGhost/Ghost/issues/10445
- adds class to card renderers
- class will only be present on new or re-saved posts
2019-02-25 10:15:14 +07:00
kirrg001
0665c72dda Removed primary_tag & primary_author if null from Admin API v2
refs #10438

- "null" means the resource does not exist (it was sett to "null"), which is not true
- we won't serve primary_tag and primary_author by default
- TODO: add the same change to the Content API v2 (raise issue)
2019-02-24 13:31:43 +01:00
kirrg001
377d7e4271 Removed serving primary_tag when members is enabled
no issue

- Content API v2 served primary_tag by default if members flag is enabled
- reference: b2201d4179
- it's safe to remove, because members is behind the dev flag
2019-02-24 11:54:04 +01:00
Nazar Gargol
9d4b0c09a8 Renamed uploads to images
refs #10438

- As the support of /uploads endpoint has been dropped in Admin API, all related files have to correspond to new naming
2019-02-24 11:18:45 +07:00
Nazar Gargol
73bb626cae Removed unused GhostErrors
refs #10438
2019-02-24 10:52:03 +07:00
kirrg001
48bd7a094c Stripped virtual fields from Admin API v2: primary_tagg & primary_author
refs #10438

- you cannot add or update these fields
- these are virtual fields
2019-02-23 22:58:57 +01:00
kirrg001
aa96334379 Removed default debug log from base model when emittingg events
no issue

- we should only log the event if the model was changed
2019-02-23 22:31:56 +01:00
kirrg001
4fb783d4a3 Stripped virtual field from Admin API v2: "url"
refs #10438
2019-02-23 22:31:23 +01:00
kirrg001
0430dc374f Expanded webhooks debug
no issue
2019-02-23 22:03:49 +01:00
kirrg001
58153ad47d Fixed "html" being marked as changed if mobiledoc or html was not changed
no issue

- if you html is NULL e.g. you create a draft post, we always set "html" to ""
- this get's marked as changed
- !this.get('html') was added for the 2.0 migration, because some posts had custom mobiledoc, but no html value
2019-02-23 22:02:42 +01:00
kirrg001
641b67e784 Fixed x_by being detected as changed if owner updates resources
refs #9299

- `contextUser` returns a number and if the previous x_by is "1", then bookshelf marks it as changed ("1" !== 1)
- this is a left over from 0.x, because we still owner as id 1
- as soon as we fix 9299, we don't have to worry about this anymore, because we will fetch the owner id if we need it
2019-02-23 22:00:24 +01:00
Fabien O'Carroll
4a1a245e9b
Updated audience validation for admin api tokens (#10519)
no-issue
2019-02-23 12:51:21 +01:00
kirrg001
487a32832a Reverted access to "actions" for integrations
refs #9865

- see dbd3832967
- we are not aware of any use cases so far
- reverting
2019-02-23 09:37:18 +01:00
Fabien O'Carroll
a02a43e6fa
Improved Members security and performance (#10511)
no-issue

* Corrected function names for rpc methods

* Updated gateway to store tokens locally

* Fixed lint

* Added hardcoded 30 minute expiry for member tokens

* Added default contentApiAccess config;

* Updated validateAudience method

This is required for security, we need to restrict which domains can access
tokens meant for the content api
2019-02-23 04:47:42 +01:00
Katharina Irrgang
a361a8d7c0
Added support for short format when attaching authors/tags in Admin API v2 (#10505)
closes #10504

- both formats are supported
2019-02-22 13:01:04 +01:00
Nazar Gargol
55289d04c8 Changed response structure for /images
refs #10438

- To make response structure future proof and conform to the rest of API responses /images* now returns an object with url property instead of plain url string
2019-02-22 18:17:44 +07:00
Nazar Gargol
187636193b Removed /uploads* endpoints
refs #10438
2019-02-22 18:17:44 +07:00
Katharina Irrgang
dfd350bd69
Cleaned up Admin API v2 posts/pages input serializer (#10516)
no issue

- make use of filter instead of status=all or data.page
- nql was designed to filter data on database layer
- do not break v0.1
- we just got rid of the "status" query param, you should use the filter instead
- get rid of the ugly condition to remove page field if "fields" param was used
- allow filtering on model layer for "findOne"
  - do not allow filtering for "findOne" on API layer for now
  - the API controller defines what is allowed
  - the model layer can allow more by default
  - we can re-use the powerful filter logic without adding hacks
2019-02-22 12:07:34 +01:00
Fabien O'Carroll
a1219e8f65
Added upgrade page to members auth (#10513)
no-issue
2019-02-22 07:30:00 +01:00
Katharina Irrgang
0a70226128 Separated pages & posts in Admin API v2 (#10494)
refs #10438, refs #10106

* Renamed existing pages ctrl
* Splitted posts & pages for Admin API v2
* Added pages JSON input schema for Admin API v2
* Removed single author for Content & Admin API v2
  - single author is not documented
  - single author usage is deprecated in v0.1
  - single author usage is removed in API v2
* Splitted posts & postsPublic controller for v2
* Removed requirement to send `status=all` from Admin API v2
* Removed `status` option from pages Content API v2
* Removed `status` options from Users Admin API v2
2019-02-22 10:17:14 +07:00
kirrg001
cf8622ea99 Removed "status" query option from Authors Content API v2
no issue

- this is either documented, not does it work
- the Content API returns authors independing on the status
- filtering by status should not work, because otherwise you could guess the status of a user
- we do not expose the status (!)
2019-02-21 12:24:16 +01:00
kirrg001
0dd3aad2d0 Required updated_at for Admin API v2 when updating a post/page
refs #10438

- the `updated_at` functions as version control value
- it is required for collision detection
- we might redesign this feature at some point
2019-02-21 08:39:17 +01:00
Nazar Gargol
f394eaa7b8 Added optional support for HTML source
closes TryGhost/Ghost-SDK/issues/51

- Due to JSDOM not supporting Node v6 the support for HTML conversion is now optional
2019-02-21 13:27:47 +07:00
Kevin Ansfield
288a38036b Improved error messages for failed authorization 2019-02-21 13:19:57 +07:00
kirrg001
3b2ede88e0 Handled duplicated authors
no issue

- discovered while testing
- the matching helper can fallback twice to owner user in theory
2019-02-18 19:30:11 +01:00
kirrg001
2ab0c8e222 🐛 Fixed filtering by primary_tag or primary_author in routes.yaml
closes #10482

- the mapping was missing
2019-02-18 19:13:22 +01:00
Nazar Gargol
9020293e61 Added posibility to accept html as an input source for post
closes #10471

- Allows accepting HTML input for /posts endpoint when `?source=html` is
present in query parameter along with `html` in request payload
2019-02-15 18:58:46 +00:00
Zimo
17e29a3185 Applying basic styles to members popups
no issue
2019-02-15 18:17:38 +01:00
Kevin Ansfield
8e9ade6357
Added migration to insert builtin Zapier integration (#10500)
no issue

A new Zapier app will be released that uses the v2 Admin API which means it will require an ApiKey that is linked to an Integration.

- adds a `type` column to the `integrations` table with the following types allowed:
  - `custom` (default) used by custom integrations added by users
  - `builtin` used by built-in integrations that have their own UI and won't show up in the "Custom Integrations" list
  - `internal` used by "internal" integrations such as the scheduler
- adds a `zapier` "builtin" integration to the fixtures
2019-02-15 14:48:21 +00:00
Nazar Gargol
18921747bb Added check for empty name for tags
refs #10438

- Also corrected and expanded test cases for tag validation
2019-02-15 13:19:06 +00:00
Nazar Gargol
921f9d394f Removed posts.tags.parent sanitation
refs #10438

- As we strip parent and parent_id fields in /tags endpoint, similarly stripping it for posts related tags
2019-02-15 12:19:49 +00:00
Nazar Gargol
c58e03a359 Added stricter validation for post.authors
refs #10438

- By stripping relational fields, it allows to remove redundant code in post input serializer
2019-02-15 12:19:49 +00:00
Nazar Gargol
e305d5e9cb Skiped 'all' validations for posts/tags endpoints
refs #10438

- Skipped validations that are now handled on JSON Schema level and would make sure error messages are consistent for these endpoints
2019-02-15 12:19:49 +00:00
Katharina Irrgang
40f359a238 🐛 Fixed night mode when using API v2 (#10499)
no issue
2019-02-15 12:15:37 +00:00
Rish
b84881e842 Updated members modal UI structure
no issue
2019-02-15 14:15:17 +05:30
Nazar Gargol
76c6f96aed Changed error type for missing file in /uploads
refs #10438
2019-02-14 20:52:51 +00:00
Fabien O'Carroll
9dd7aff9c6
Updated Content API to use members plans to determine permission (#10483)
no-issue


* Refactored hideMembersOnlyContent to 3 "stages"
* Exported paymentConfigured flag from members service
* Updated Content-API to check members service for paymentConfigured
* Updated members content output serializer to remove content if plan required and no plan
* Updated isContentAPI method
* Moved api util test
2019-02-14 18:17:02 +01:00
Rishabh Garg
896769ee8f
Updated signup page for members (#10493)
no issue

* Added new subscribe page with stripe integration
2019-02-14 22:29:41 +05:30
Nazar Gargol
5f7c2b4d87 Improved error messaging returned from JSON Schema validations
refs #10438
2019-02-14 10:52:42 +00:00
Nazar Gargol
fa42a71181 🐛 Fixed validation error when adding tag from PSM
refs #10438

- Relaxed validation rules for tag.slug property to allow 'null' values
2019-02-14 10:04:02 +00:00
Katharina Irrgang
c2b3520652
Removed id restriction for posts relations in Admin API v2 (#10489)
refs #10438

- we now try to match by slug or id or email
- fallback to owner
- you cannot create a user via post endpoint
- Ghost uses the invite flow to add users
- get rid of `id` restriction on API level
2019-02-13 20:38:25 +01:00
Fabien O'Carroll
6bdeeaba10
Added apiType property to frame for {Content,Admin} API (#10487)
no-issue

This sets the `apiType` property of the `frame` to 'content' and 'admin'
for the Content & Admin API respectively.
2019-02-13 16:59:10 +01:00
Katharina Irrgang
90c421a8a8 Removed client credentials from Admin API v2 (#10485)
refs #10438
- v2 does not use client credentials anymore
- exception: scheduler & backup clients
2019-02-13 13:51:51 +00:00
Naz Gargol
ae437a89dd
Updated posts JSON Schema with 'strip' properties (#10488)
refs #10438
refs #9100

- Added 'strip' attributes to properties that need to be ignored
- Relaxed 'uri' format to 'uri-reference'
- Made input array for posts more restrictive
2019-02-13 13:34:45 +00:00
Naz Gargol
40cc6e6548
Added JSON Schema validations for /tags (#10486)
Added JSON Schema validations for /tags endpoints

refs #10438
refs #9100

- Added JSON Schemas for POST/PUT /tags endpoints
- Added 'strip' keyword definition schema allowing to strip data and not throw errors on further validation stages
2019-02-13 12:26:32 +00:00
kirrg001
f8b62a063b Removed more unused fields from Admin API v2 response
refs #10438

- these fields are not used
- no need to expose them in v2
- we will either remove them in the next major or use them for new features (will see)
2019-02-13 11:42:08 +01:00
Fabien O'Carroll
a3e7a7b3ea
Updated product hashseed to be hardcoded (#10484)
no-issue
2019-02-13 11:19:43 +01:00
Fabien O'Carroll
5472aa61ac
Added config endpoint to Member API (#10467)
no-issue

* Added getPublicConfig method to stripe payment processor
* Added getPublicConfig method to subscriptions service
* Added initial config endpoint for members api
* Added getConfig method to members gateway
2019-02-13 10:12:15 +01:00
kirrg001
36547a9c3a Removed ghost_auth_id from Admin API v2 response
refs #10438

- unused field
- no need to expose this field
2019-02-12 23:36:42 +01:00
kirrg001
db148e653f Removed tag.parent from Admin API v2 response
refs #10438

- this is an unused field
- no need to expose this field
- if we start working on nested tags, this field might become interesting/used
2019-02-12 19:26:31 +01:00
Nazar Gargol
20300cf002 🐛 Fixed error when inserting unexistent related tag
refs #10438

- Additional check for present 'name' property before generating a
'slug'. Setting slug should not succeed and throw validation error in later
stages.
2019-02-12 17:50:51 +00:00
Nazar Gargol
d0d299285c Fixed tests for post input serialization
refs #10472

- Moved config related variable into function scope, so it can be reset by unit tests
- e47d1e275f broke the build and is being fixed by this commit
2019-02-12 12:04:18 +00:00
Nazar Gargol
e47d1e275f Fixed image URL to be stored as relative in mobiledoc
refs #10477
closes #10472

- Adds transformation for any asset absolute URL's into relative used in mobiledoc
2019-02-11 19:20:16 +00:00
Fabien O'Carroll
8e75267bbb
🐛 Allowed data to be read from root of specified key for static pages (#10449)
refs #10434
2019-02-11 12:43:01 +01:00
Nazar Gargol
d299e8676f Fixed JSON Schema validation error message format
refs #10438
2019-02-08 12:17:39 +00:00
Nazar Gargol
28986b3b77 Fixed post.tags validation schema
refs #10438

- Change oneOf to anyOf to allow any of the required fields
2019-02-08 11:29:42 +00:00
Nazar Gargol
96cdde80b9 Fixed validation error when creating new tag from PSM
refs #10438

- Expanded required fields for related tags to have either one of 'id', 'slug' or a 'name' field
2019-02-08 11:02:18 +00:00
Naz Gargol
19643c75dd
Added JSON Schema validation for /posts endpoint (#10468)
refs #10438

- Added  validation helper based on JSON schema
- Added schema validation for POST/PUT in /posts endpoints
- Refactored existing authors validation test suite
- Extended test coverage with a minimally required structure of post.add validator
2019-02-08 10:40:58 +00:00
kirrg001
e1436e2985 Required "event" & "target_url" for webhook creation
refs #10461
2019-02-07 23:21:59 +01:00
kirrg001
f8a286869a Allowed POST & DELETE webhooks endpoints for integrations
refs #9865

- was not sure about allowing to edit webhooks
2019-02-07 23:14:27 +01:00
kirrg001
b83232bf0c Added more webhooks & changed payload
refs #10461

- do not break the existing webhooks by keeping both payload formats for subscribers events
- refactored webhooks service to run models through target API version
- added new events described in the target issue reference
- this refactoring & enhancement is undocumented, further breaking changes will happen because we are actively working on: https://github.com/TryGhost/Ghost/issues/10438
2019-02-07 23:14:27 +01:00
kirrg001
a83aa6e184 Added ability to receive toJSON format of previous attributes
refs #9248

- e.g. model.toJSON({previous: true})
- includes previous relations
2019-02-07 23:14:27 +01:00
kirrg001
50da5d9bab Corrected debug in base model
no issue
2019-02-07 22:08:52 +01:00
kirrg001
7810140f15 Avoided site.changed event if nothing has changed
refs #10461
2019-02-07 22:08:36 +01:00
kirrg001
82c5fc7f5a Ensured API can ask model.wasChanged
refs #10461

- the model layer (only post & user) fetches the model after update
- i assume it was added to ensure a response with all fields
- quick fixing it for now to ensure API layer can access ".wasChanged" to be able to decide if a request modified a resource or not

@NOTE: Bookshelf does not physically update a resource if nothing has changed.
2019-02-07 22:07:13 +01:00
kirrg001
4fca28e643 Made use of model.wasChanged
refs #10461
2019-02-07 22:06:13 +01:00
kirrg001
a157c147af Added model.wasChanged helper
refs #10461

- helpful if you need to ask if the model was changed
- Bookshelf does not support this feature yet
- https://github.com/bookshelf/bookshelf/issues/1943
2019-02-07 22:05:07 +01:00
kirrg001
2eb1f2a507 Avoided inserting actions if nothing has changed
refs #10431

- I thought i have added this protection, but got removed via the simplification in cca3317a11
2019-02-07 20:49:35 +01:00
kirrg001
b25da62cca Ensured defaults when creating resources
no issue

- the model & api layer suffered from missing fields when creating resources
- usually there is only a handful of fields which are required to insert a resource
- the other fields are nullable and/or get defaults assigned
- the API only returned the configured default fields and the fields you have sent to the API
  - this resulted in a response with missing fields
- if you have listend on "created" event, the same happend
  - you received a model with missing fields
- we now set the undefined fields to null on purpose to ensure a full model for both cases

@NOTE:
There is no endpoint to serve webhooks (not for v0.1, not for v2).
Exposing the secret is required if an integration fetches it's api keys and it's webhooks.
The secret is currently un-used and not implemented.
2019-02-07 20:20:10 +01:00
John O'Nolan
ae5ed03488
Update admin redirects
Refs https://github.com/TryGhost/Ghost/pull/10079
2019-02-07 17:59:35 +07:00
kirrg001
1e90126760 Remembered changed fields on destroy
refs #9248
2019-02-07 11:35:00 +01:00
kirrg001
865366c7c8 Ensured consistency for event handlers in the model layer
no issue

- the event chain works like this:
  - if a model registers an event, it get's triggered, because it's stronger than the base model
- but you have to call the base model to agree on a contract, because base model implements generic logic in event handlers
- this was inconsistently used
2019-02-07 11:02:35 +01:00
Fabien O'Carroll
46bf5270df
Added initial subscription support with stripe to Members API (#10460)
These changes introduce a new "service" to the members api, which handles getting and creating subscriptions.

This is wired up to get subscription information when creating tokens, and attaching information to the token, so that the Content API can allow/deny access. 

Behind the subscription service we have a Stripe "payment processor", this holds the logic for creating subscriptions etc... in Stripe.

The logic for getting items out of stripe uses a hash of the relevant data as the id to search for, this allows us to forgo keeping stripe data in a db, so that this feature can get out quicker.
2019-02-07 10:41:39 +01:00
Fabien O'Carroll
5f66026647
Refactored auth pages for future flows (#10458)
no-issue

* Used camelCase for gateway method calls
* Added some components for building blocks of forms
* Added input specific components
* Added Form component
    This handles collecting the data to submit and sharing state between forms
* Added Pages component to handle urls
* Added the pages for the popup
* Added MembersProvider component
    This is designed to give its children access to gateway methods
* Added Modal component
    This wraps the pages and handles dispatching form submissions to the members gateway
* Refactored index.js to use new components/pages
* Fixed default page from Signup -> Signin
2019-02-07 10:39:55 +01:00
kirrg001
cca3317a11 Simplfied action trigger in base model
refs #10431

- the model layer triggers a couple of events on resource update
  e.g. post to page -> post.deleted, post.added
- the resource_type must be always "post", because "page" is not an official model (Bookshelf won't be able to resolve the resource anymore)
- the action streams looks very confusion if you see deleted and added actions when toggling the post to a static page
- therefor the easiest approach for now is to only store actions for: added, edited, deleted
- and we will add the context information asap
  - e.g. you will see that status was changed from "draft" to "published"
- we can also introduce extra published actions if we want
- relying on the internal event system right now makes things just more complicated and we want to keep it simple
2019-02-06 22:21:06 +01:00
kirrg001
dbd3832967 Allowed browse actions for integrations
refs #9865
2019-02-06 21:36:09 +01:00
kirrg001
5f4cf42c14 Fixed tests
no issue
2019-02-06 21:36:09 +01:00
kirrg001
a8e0a173c2 Redefined context.integration
no issue

- we only have access to the ID at the moment
- we really don't want to end up in the same situation as with "context.user"
2019-02-06 21:36:09 +01:00
kirrg001
68bdcfc753 Fixed model._changed for creating resources
no issue

- discovered while testing
- the events are still triggered though for posts because .authors are added on creation
2019-02-06 21:36:09 +01:00
kirrg001
2fd4cbb93b Added v2 actions endpoint
refs #10431

- added v2 endpoint with browse permissions
- context.integration was never accessible in the model layer
  - why? https://github.com/TryGhost/Ghost/issues/10099
2019-02-06 21:36:09 +01:00
kirrg001
8bb2c7d3d5 Added model implementation for actions
refs #10431

- added actions model
- added logic in event emiiter to insert actions if supported
2019-02-06 21:36:09 +01:00
kirrg001
fde31b31ba Added permissions for actions including migration
refs #10431

- migration script to add permissions for actions
- restricted to owner & admin & integration role for now
- we will add permissions for other rules too, but we need add more granular restrictions
  - e.g. contributors can only read actions for posts which he created
2019-02-06 18:59:09 +01:00
kirrg001
c127b406fc Added actions table including migration
refs 10431

- add actions table
- add migration
2019-02-06 18:59:09 +01:00
Kevin Ansfield
c9d6ffa5ab Allowed GET /configuration/about/ for Admin API v2 with API Key auth
refs https://github.com/TryGhost/Ghost/issues/9865
- needed for Zapier
2019-02-06 14:00:29 +00:00
ShumailAhmed123
24e96dcabf Updated default-routes.yaml syntax to single template (#10459)
closes #10456
2019-02-06 14:34:57 +01:00
Aileen Nowak
93b936d2fb Added back "theme.uploaded" analytics event (#10450)
no issue

- With the changes in 79ca6c575c we removed old unused events
- The theme upload event is still used and needed to be put back
- Added the event emit right after the successful upload of the theme
- Renamed analytics events for more consistency
- We need to add the same event emitter to the v0.1 API as it's not deprecated
- emits a `theme.uploaded` event after the theme was successfully uploaded and saved
2019-02-05 17:38:40 +01:00
Hannah Wolfe
426c122ed1 Updated messaging around {{get}} helper access
closes #10447

- Get helper message talks about the old API, but upgrading is the best way to solve the problem
- Had to create a way to add a custom message to a labs enabled helper to achieve this
2019-02-04 17:58:35 +00:00
Hannah Wolfe
5365094dfc 🐛 Provided get helper filters access to globals
closes #10448

- using @site.lang to read posts is a valid use case for the get helper filters
- get helper filters have special treatment of anything wrapped in {{}}, in the form of resolvePaths
- resolvePaths uses some custom logic + jsonpath to find the right bit of data to inject
- this function had no handling for globals starting with `@`, and also didn't have access to them
2019-02-04 15:26:45 +00:00
kirrg001
8b3336c84d Added condition to not trigger events if nothing has changed
refs #9248

- we no longer trigger events if the db was not changed
2019-02-03 13:02:31 +01:00