Commit Graph

1006 Commits

Author SHA1 Message Date
Steve Larson
7083bd0628
🐛 Fixed slug not always updating for draft posts (#21691)
ref https://linear.app/ghost/issue/ONC-548/

There have been reported cases of the editor not updating the slug for
draft posts. The logic should be as follows: for a draft post, if the
title was updated and we do not detect a custom slug, update it.

This got out of sync due to actions where the save was triggered but the
title onBlur effect (which updates the slug) was not triggered. This has
been resolved by evaluating the slug in the before save actions.
2024-11-23 00:24:17 +00:00
Steve Larson
c046bbda91
🐛 Fixed Istanbul timezone (#21686)
ref https://linear.app/ghost/issue/ENG-1781/
- updated Istanbul TZ to +03

Thanks to @muratcorlu for the PR to TryGhost/SDK.
2024-11-21 17:23:21 +00:00
Kevin Ansfield
98c06f8126 Fixed removal of event tracker requests in Sentry
no issue

- filtering was previously added to breadcrumbs but that wasn't enough to clean up Sentry reports
- added filtering to the `beforeSend` hook too so reports don't get cluttered with unhelpful XHR noise
2024-10-30 11:52:50 +00:00
Kevin Ansfield
9fa0c24be9 Removed resend countdown from 2fa flow
closes https://linear.app/ghost/issue/ENG-1658

- switched to using a task to match patterns elsewhere and have better cancellation behaviour if code is re-used in a short-lived component
- added `drop: true` task modifier to our main tasks so they can't be triggered again whilst we're waiting on an API request
- removed confusing countdown in button text
- restored forced "text" data type for resend API request to match API behavior
- added acceptance tests for resend behaviour
2024-10-25 15:26:23 +01:00
Kevin Ansfield
a4e3ef012c Improved validation behaviour on 2fa code verification screen
closes https://linear.app/ghost/issue/ENG-1672

- removed input on-blur validation because it can be triggered when clicking reset button giving a misleading error state
- added client-side validation for 6-digit code
- added validation when submitting the form
- added error reset when typing in the code field, including removal of button failure state, so it's clearer you're in a new submit state
2024-10-21 12:32:29 +01:00
Kevin Ansfield
6c4de6a937 Updated 2fa flow copy
closes https://linear.app/tryghost/issue/ENG-1654
closes https://linear.app/tryghost/issue/ENG-1656
closes https://linear.app/tryghost/issue/ENG-1657

- updated copy
- improved error handling when verification fails
- refactored some duplication of steps in Admin authentication tests
2024-10-21 11:01:40 +01:00
Kevin Ansfield
2bf626bf6c Added explicit 2fa required error detection
no issue

- previously we determined any 403 response was an indication that we should switch to the 2fa input screen during sign-in
- added a custom error that explicitly looks for an error with our `2FA_TOKEN_REQUIRED` code so we don't have any confusion when a non-2fa 403 is received for any reason and to have the option of moving away from the 403 if needed without breaking the client
- test to ensure our error 2fa-required error detection works correctly
- extracted duplicate steps in the authentication tests into a helper function
- fixed authentication tests so they better represent our API output of `errors` being an array
2024-10-21 11:01:40 +01:00
Kevin Ansfield
1a05652b50 Added 2fa token verification error handling
closes https://linear.app/tryghost/issue/ENG-1635

# Conflicts:
#	ghost/admin/app/controllers/signin-verify.js
2024-10-21 11:01:40 +01:00
Kevin Ansfield
68af12cfad Added 2fa happy path to Admin
closes https://linear.app/tryghost/issue/ENG-1617/
closes https://linear.app/tryghost/issue/ENG-1619/

- updated cookie authenticator's `authenticate` method to accept an `{identification, pasword, token}` object
  - if `token` is provided, hit our `PUT /session/verify/` endpoint passing through the token instead of hitting the `POST /session/` endpoint
- added `signin/verify` route
  - displays a 2fa code input field, including required attributes for macOS auto-fill from email/messages to work
  - uses `session.authenticate({token})` when submitted
- updated signin routine to detect token-required state
  - detects a `403` response with a `2FA_TOKEN_REQUIRED` code property when authenticating
  - if detected transitions to the `signin/verify` route
2024-10-21 11:01:40 +01:00
Kevin Ansfield
2fb88e65ca Fixed signin and signup button failure state hover colors
ref https://linear.app/tryghost/issue/ENG-1653

- we were always setting a `style="background-color: #123456"` attribute on the buttons but that didn't allow for different button states such as the red failure state to correctly override meaning there was some odd behaviour when hovering
- removed the fixed `style` attribute and adjusted `<GhTaskButton>`
  - added `@useAccentColor` prop
  - when `@useAccentColor` is true, add the necessary `style` attribute except when showing the failure state
2024-10-17 16:54:23 +01:00
Sag
d5aa77bb7f
🐛 Fixed missing 'duplicate a post' feature for editors (#21304)
ref https://linear.app/tryghost/issue/ENG-1647

- as per [staff user definitions](https://ghost.org/docs/staff), an
editor should be able to duplicate a post
- this feature was missing from the right-click menu on post/page lists
for editors
2024-10-15 12:19:56 +02:00
Kevin Ansfield
3bbe8c8c7a
Fixed bugs in post's change-access context menu flow (#21173)
ref 86d61304b1
ref https://linear.app/tryghost/issue/ONC-323

- added `tracked()` to our proxy model object properties
  - fixes default data always showing when opening the modal
- fixed data push after completing modal
- `post.tiers` is set up as an attribute in Admin rather than a relationship
- fixes incorrect tiers list showing when the change access modal is opened again after changing access before the post is re-fetched from the API
- fixed flash of failure button state when saving modal changes
- expanded tests to cover tiers selection
2024-10-01 17:16:23 +00:00
Kevin Ansfield
86d61304b1 🐛 Fixed errors creating new posts after a post access change via context menu
ref https://linear.app/tryghost/issue/ONC-323

After changing a post's access via the posts list context menu, creating new posts or members would not work correctly.

- the issue stemmed from `this.post.set('currentState.parentState.isNew', false);` that was called when changing a post's access level, after that all Ember Data models created from the store would have `isNew: false` causing Ember Data to attempt a PUT request to update the not-yet-created model rather than a POST request to create it
- we were only using a real post model instance in order to run validations against the post access level settings but we can do that just as easily by creating a new object and injecting our validation mixin
2024-10-01 15:10:59 +01:00
Chris Raible
046b06fe72
Refactored local revisions to avoid QuotaExceededErrors (#21128)
ref https://ghost-foundation.sentry.io/issues/5908152800/

- In the current state, we are maintaining an 'index' key for all
revisions in localStorage. This gives us quick and easy access to all
the revisions in localStorage, but it requires additional "bookkeeping"
to update the index each time we add/remove a key.
- In some obscure edge cases, this results in the `remove()` method
throwing a `QuotaExceededError` (since removing a revision also requires
updating the index with `localStorage.setItem()`). If the `remove()`
call fails, we are sort of stuck — the only way to reduce our storage
usage is to remove items, but if the `remove()` method throws errors, we
can't do that.
- This change removes the whole index concept, and instead loops over
all the keys in localStorage, filtering by the prefix to find all our
revisions. This makes the `keys()` method slightly more complex, as it
has to filter out keys in localStorage that aren't related to revisions,
but it simplifies saving and removing revisions.
- Critically, this also means that `remove()` should never throw a
`QuotaExceededError`, since it no longer needs to call
`localStorage.setItem()` — it now simply calls
`localStorage.removeItem()` for the revision, which should never fail.
2024-09-26 12:50:31 -07:00
Ronald Langeveld
052ef6971f
🐛 Fixed infinite loops in setFeatureImageCaption for deleted posts (#21081)
ref ONC-364

- Adds a condition to check whether the record is deleted or if deleting
is in progress before firing the `setFeatureImageCaption`.
- Adds tests. Managed to reproduce the issue using tests.
2024-09-25 08:02:38 +00:00
Chris Raible
0125f52dc4
Added sentry logging to local revisions service for localStorage errors (#21078)
no issue

- Added Sentry logs to capture how often we are running into
`QuotaExceededErrors` when saving local revisions to localStorage, to
help in deciding if localStorage is sufficient, or if we need to expand
to e.g. IndexedDB.
- Also adds some handling to ignore errors when calling
`localStorage.setItem()` elsewhere in the admin app to avoid crashing if
localStorage isn't supported or the quota is exceeded.
2024-09-24 19:39:36 -07:00
Steve Larson
c121149ca3
Added posts restore UI (#21096)
ref https://app.incident.io/ghost/incidents/107
ref cc88757e2a
- added new path in admin `/restore`
- added basic ui for restoring posts from local storage
- added limits for # of revisions for posts with an `id` (5 revisions)

This commit adds a simple UI for restoring posts in case of data loss.
This is a backstop for very rare situations in which it seems Ember gets
into a conflicted state. See ref'd commit for more info. Clicking
'Restore' will create a new post with the saved off content.
2024-09-24 15:01:17 +00:00
Sodbileg Gansukh
2f02ec5566
Added unschedule bulk action to posts (#20945)
ref DES-675
2024-09-24 15:32:45 +08:00
Kevin Ansfield
459a2c553e Added full-page refresh when new post route is in a bad state
ref https://linear.app/tryghost/issue/ONC-323

When the store gets into a bad state for new posts that causes saves to fail we can detect that by looking at the `model.isNew` property. Currently our best approach to fix this state is to restart the app.

- added a `didTransition()` hook to our `lexical-edit.new` route
  - detects the bad state, logs the error, and triggers a browser refresh
  - logs with a `recreatedPostIsGood` property that will let us know if we could instead just try recreating the post and avoiding a full refresh (so far we have no reproduction case so we need to learn what we can)
- added `sinon-chai` dependency for better assertions on spies/stubs
- added `sentry-testkit` dependency so we can test our Sentry integration calls
  - we can't use sinon for these calls because of the way Sentry's es6 imports work
- extracted our full Sentry config object generation to a util function so it can be re-used in unit tests
  - updated our integrations list to disable the default `dedupe` integration because it can cause very unexpected/difficult to debug test failures when you're asserting using `sentry-testkit`
2024-09-23 22:38:34 +01:00
Kevin Ansfield
c41c44b02d Fixed "Editor crashed" error showing for a valid 404
ref https://linear.app/tryghost/issue/ONC-323

- sometimes posts can be deleted by another user or in a different tab but then edited in an old tab that had the post loaded in the editor
- in this situation we were displaying our "Editor crashed" error put in place for the  rarer situation where the editor is genuinely in a bad state
- added an extra conditional for the bad state and a custom error message for the deleted post state
2024-09-20 09:40:44 +01:00
Kevin Ansfield
64118c139e Added extra post model state properties to debug logs
ref https://linear.app/tryghost/issue/ONC-323

- include post model state properties as well as the state name
2024-09-20 09:14:39 +01:00
Chris Raible
cc88757e2a
Added local revisions to the editor as backstop against data loss (#21044)
ref https://app.incident.io/ghost/incidents/107

- We have a rare bug that causes the initial `POST` request to create a
new post from the editor to be skipped or fail. Subsequent `PUT`
requests then fail because there is no post ID, potentially resulting in
data loss. The aim of this commit is to start saving revisions of posts
in the editor to the browser's localStorage, as a last-ditch option to
restore lost work.
- Since we don't know where the bug is yet, and to protect against
future bugs, we've deliberately avoided depending too heavily on the
`lexical-editor` controller or the ember store. We've aimed to create a
direct route to the state in the editor, by hooking into the
`updateScratch` method (effectively the `onChange` handler for the
editor).
- The `scheduleSave` function on the new `local-revisions` service is
called immediately upon any changes to the state of the lexical editor,
which is effectively every keystroke. The service has some logic and
timeouts, so it doesn't actually save a revision on every change to the
editor.
- The "schema" of the datastore is a simple key-value store, where the
key is of the format: `post-revision-${postId}-${timestamp}` if the post
has an ID, or `post-revision-draft-${timestamp}` for an unsaved draft.
There is also an array of all the revisions' keys, which allows us to
clear all the revisions without having to loop over every key in
localStorage (along with some other conveniences, like filtering).
- There is currently no UI for viewing/restoring revisions. In the event
that you need to restore a revision, you can access the service in the
browser console. You can access all the saved revisions using the
`list()` method, which logs all the revisions to the console by title &
timestamp. You can then choose a revision to restore, and call
`restore(revision_key)`, which will `POST` the revision's data to the
server to create a new post.
- Since localStorage data is limited to a 5mb quota in most browsers,
the service has a mechanism for evicting the oldest revisions once it
meets the quota. If a save fails because it would exceed the quota, the
`performSave` method will evict the oldest revision, then recursively
try to save again.

---------

Co-authored-by: Steve Larson <9larsons@gmail.com>
2024-09-20 00:08:28 -07:00
Kevin Ansfield
8ab7182bfe Added logging of post state changes
ref https://linear.app/tryghost/issue/ONC-323

- added debug logs to print to console each time the post state changes and include a full list of post state changes within the editor session in the error reports when we hit the 404 error caused by a bad editor state
2024-09-19 17:31:20 +01:00
Kevin Ansfield
bd6ca272dd 🐛 Fixed wrong breadcrumb and missing post status when starting new post from analytics
closes https://linear.app/tryghost/issue/ENG-1533

- the code to switch to "from analytics" state for the editor was applying when clicking the create post button in the nav menu whilst on the analytics screen which was confusing because you not only lost the `< Posts` link in the editor but you couldn't see the post's saving status
2024-09-19 16:27:40 +01:00
Hannah Wolfe
f828ddefee Updated missed references to unique visitors
ref https://github.com/TryGhost/Ghost/pull/21035

- We decided to rename unique visitors to unique visits, but I missed a few places. Updated test case names for good measure
2024-09-19 12:09:46 +01:00
Kevin Ansfield
618d0b130a Added debug logging for 404 errors on new posts
ref https://linear.app/tryghost/issue/ONC-323

- the post model state appears to be in an odd situation when this issue occurs, the extra log context should help us determine if the bad state is occurring at the route level or inside the editor controller
2024-09-18 17:20:23 +01:00
Sag
430fbdb987
🐛 Fixed member filtering for "Unsubscribed from newsletter" filters (#20926)
ref https://linear.app/tryghost/issue/ENG-1466
ref https://linear.app/tryghost/issue/ENG-1484

- Previously, filtering members with multiple "Unsubscribed from
newsletter x" led to no filtering at all, all members were returned
- This was caused by a bug in NQL, that is fixed in version 0.12.5, cf.
[commit](dd18d1d6ca)
- We're also removing the safeguard in the product around bulk deletion
when multiple newsletter filters are in use, as the root problem has
been fixed
2024-09-16 11:16:49 +02:00
Kevin Ansfield
a9bf6c66ed Improved displayed error message when editor reaches bad saving state
ref https://linear.app/tryghost/issue/ONC-323

- added explicit 404 handling to the editor's save task so we can display a more direct/useful error message
2024-09-13 11:35:53 +01:00
Kevin Ansfield
f054205e58 Fixed errors from 404 error handler for non-transition 404s
ref https://linear.app/tryghost/issue/ONC-323

- our fallback 404 error handler assumed we always had a transition along with the error
  - this wasn't a bad assumption, it should be very unlikely that we see a 404 outside of navigating to a non-existent/deleted resource
  - unfortunately we weren't handling the error thrown by our error handler which meant the error was silent as far as the user was concerned
  - having a silent error meant that in very rare circumstances the editor could get into a state where saving was failing but there was no indication of that
- updated the fallback 404 error handler to only do something when navigation was occurring in which case it transitions to the 404 screen, otherwise let the error continue to our generic API error handling which will stay on the current screen but show an error alert
- adjusted the editor saving to actually trigger autosave-after-change when testing (albeit with 100ms wait compared to 3s) so the tests better reflect actual behaviour
2024-09-13 11:02:55 +01:00
Kevin Ansfield
1bc34f7227 Added Tips & Donations one-off payments
no issue

Give your audience a simple way to support your work with one-time payments, no membership required.

- cleaned up `tipsAndDonations` labs flag
2024-09-03 16:00:48 +01:00
Kevin Ansfield
3744caa950 Fixed lint warnings from Admin feature-test
no issue

- converted use of promises to async/await
- removed return from async test functions to clear lint warnings
2024-09-03 10:59:08 +01:00
Kevin Ansfield
fd926193ce 🐛 Fixed unsaved changes modal showing when title has leading/trailing whitespace
closes https://linear.app/tryghost/issue/PLG-205

The server trims whitespace from the title when saving but our unsaved changes detection was comparing the raw title input field value meaning there would be a mismatch after publishing if the title field contained leading/trailing whitespace.

- updated title comparison to compare trimmed values
- moved and improved unsaved changes modal tests from publish-flow to unsaved-changes acceptance test file
  - added util for pasting content into the editor to test for content changes
2024-09-03 10:53:53 +01:00
Sodbileg Gansukh
1cee402339 Fixed publish flow related admin tests 2024-09-03 10:46:25 +01:00
Kevin Ansfield
cc72d368de Fixed Admin tests
no issue

- fixed eslint config so tests are correctly linted
- removed `.only` on stats tests preventing other tests from running
- removed unneccessary `return` from async setup functions
2024-09-03 10:46:25 +01:00
Peter Zimon
ad9312451d
Stats tab charts (#20895)
[ANAL-1](https://linear.app/tryghost/issue/ANAL-1/v1-chart-list)

Creating first version of charts on Stats tab which includes KPIs, Content, Sources, Locations and technical data.
2024-09-02 13:22:39 +02:00
Hannah Wolfe
9d121d8e9a
Added initial Stats page to Ghost Admin (#20877)
closes
https://linear.app/tryghost/issue/ANAL-10/stats-page-in-ghost-admin

- Adds all the structure, logic and permissions tests for the Stats page
to check we're loading the right thing at the right time
- Adds @tinybirdco/charts as a dependency, and has a single example of a
chart setup using the right config
2024-08-29 12:56:39 +01:00
Ronald Langeveld
8e1a730731
Fixed hanging dash when no attribution is present (#20869)
ref PLG-198

- Fixed trailing dash when no attribution is present
2024-08-29 15:22:31 +09:00
Ronald Langeveld
f2206fb232
Added one-time payments under "payments" for filtering (#20807)
ref PLG-153

- Scoped one-time payments (`donation_event`) under the "payments"
category in the member activity feed filter.
- Updated `toggleEventType` logic to ensure that toggling "payments"
also toggles one-time payments when the `tipsAndDonations` feature is
enabled.
- Refactored event type handling into utility functions for easier
testing.
- Added unit tests for the new utility functions to ensure correct
behaviour.
- Added acceptance testing.
2024-08-22 10:26:46 +00:00
Kevin Ansfield
b01d4287ad Fixed Admin test failures when running in Safari
no issue

- Safari's `innerText` sometimes includes a trailing `\n` depending on the markup used so we need to use `.to.have.rendered.trimmed.text()`
- reproducible when running tests via http://localhost:4200/tests (we don't yet run in Safari via our testem config)
2024-08-21 12:58:11 +01:00
Kevin Ansfield
fc501add94 Fixed editor not loading in Admin acceptance tests
closes https://linear.app/tryghost/issue/PLG-176

The editor files were previously stubbed for testing because we didn't have a way to load the externally-hosted files. This made testing slow and difficult because the only way to test the Admin integration was via Ghost's e2e browser tests.

- unstubbed the editor globals so `fetchKoenigLexical()` actually tries to import the external assets
- updated `ember-cli-build` to copy the Koenig UMD file over to the assets directory in development/test builds
- updated `environment.js` to set the required filename for the default asset import to successfully hit the test environment hosted files
- updated lexical editor acceptance tests to demonstrate the editor loads successfully for new and existing posts
2024-08-21 11:49:05 +01:00
Kevin Ansfield
9dfbd3e293 Fixed excerpt blur saving non-draft posts
ref https://linear.app/tryghost/issue/PLG-174

- forcing autosave on excerpt blur caused posts to revert to `draft` and save immediately even when they were published/scheduled
- updated the save-on-excerpt-blur to only autosave drafts
- added acceptance tests for title and excerpt change+blur on published posts
2024-08-19 21:04:15 +01:00
Kevin Ansfield
887f4d3ac2
🐛 Fixed editor unsaved changes modal showing too often (#20787)
ref [ENG-661](https://linear.app/tryghost/issue/ENG-661/) 
ref [ONC-253](https://linear.app/tryghost/issue/ONC-253/)
ref [PLG-174](https://linear.app/tryghost/issue/PLG-174/)

- restored the original but reverted fix for unsaved changes modal from https://github.com/TryGhost/Ghost/pull/20687
- updated code to remove some incorrect early-falsy-return logic in `editorController.hasDirtyAttributes` that prevented save of unsaved changes on the underlying model (e.g. excerpt)
- updated unit tests so they are testing real post model instances and therefore are testing what we expect them to test
- added acceptance tests to ensure autosave is working for title and excerpt fields

---------

Co-authored-by: Ronald Langeveld <hi@ronaldlangeveld.com>
2024-08-19 18:03:13 +00:00
Kevin Ansfield
64fbf3b9ee Updated Admin editor unit tests to use real model instances
ref https://linear.app/tryghost/issue/PLG-176

- we recently had to revert code because it caused unexpected problems despite the unit tests passing
- the setup for the editor unit tests was very basic and did not represent the real world because it tested a simple EmberObject instance rather than an Ember Model instance meaning the tests weren't covering the real code paths
- updated the unit test with a more realistic environment ready for re-working the reverted code+tests
2024-08-19 16:13:49 +01:00
Kevin Ansfield
21aa1b4378
🐛 Fixed autosave not triggering when in-editor excerpt is changed (#20785)
ref https://linear.app/tryghost/issue/PLG-174

- added `blur` handler to excerpt field so it acts the same as the title field and triggers a save when it loses focus
2024-08-19 14:38:00 +00:00
Ronald Langeveld
6ebcd10288
Revert "Fixed draft posts not autosaving without title (#20774)" (#20776)
This reverts commit aad438ba0b.

- reverts the commit so that we can merge it together with PLG-174
2024-08-19 10:19:53 +00:00
Ronald Langeveld
aad438ba0b
Fixed draft posts not autosaving without title (#20774)
ref [ENG-661](https://linear.app/tryghost/issue/ENG-661/) ONC-253

- Reverts the revert of
93cbb94b90
of the intial bug fix.
- Updated hasDirtyAttributes logic to ensure the dirty state changes
when typing a draft, despite not title.
- Updated tests and added tests missing from the hasDirtyAttributes
logic
2024-08-19 12:21:35 +07:00
Chris Raible
77b18916f4
🐛 Fixed a bug causing new drafts to only save if the title is populated (#20769)
ref
https://linear.app/tryghost/issue/ONC-253/drafts-only-save-if-the-title-is-populated

- A
[commit](c8ba9e8027)
in `v5.89.1` introduced a bug that caused new drafts to only save if the
post title was populated, causing potential data loss if a user is
working on a new draft without setting the title.
- This commit reverts the one that introduced this bug to prevent data
loss.

This reverts commit c8ba9e8027.
2024-08-16 12:09:11 -07:00
Sanne de Vries
ae628d7520
🎨 Added “Copy post link” to posts list context menu (#20760)
REF DES-321
- Added a "Copy post link" button to the context menu to copy the post URL for published posts, and a "Copy preview link" for draft and scheduled posts.

---------

Co-authored-by: Kevin Ansfield <kevin@lookingsideways.co.uk>
2024-08-15 16:09:48 +02:00
Sag
e6254bbb93
🎨 Removed member bulk deletion safeguard from safe queries (#20747)
fixes https://linear.app/tryghost/issue/ENG-1484

- in Ghost release
[v5.89.0](https://github.com/TryGhost/Ghost/releases/tag/v5.89.0), we
have added a safeguard around bulk member deletion, due to a limitation
in NQL for member filters (commit: 2484a77)
- with this change, we limit the safeguard to only the cases we know are
problematic, and remove it for other useful and safe queries
- more precisely, the safeguard is in place only when:
    - Multiple newsletters exist, and the filter contains 2 or more
newsletter filters
    - If any of the following stripe filters are used even once:
        - Billing period
        - Stripe subscription status
        - Paid start date
        - Next billing date
        - Subscription started on post/page
        - Offers
2024-08-14 15:48:54 +00:00
Kevin Ansfield
a86f9dbdda Cleaned up internalLinking labs flag
closes https://linear.app/tryghost/issue/PLG-15

- removed `internalLinking` GA labs flag
- renamed search providers to `flex` and `basic`
  - keeps old search provider around as it can handle non-English languages unlike the faster flex provider
- updated `search` service to switch from `flex` to `basic` when the site's locale is not english
- bumped Koenig packages to switch from a feature flag for toggling internal linking features to the presence of the `searchLinks` function in card config
- updated tests to correctly switch between flex and basic providers in respective suites
2024-08-12 13:08:29 +01:00