Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent autosave when the post is locked #32475

Open
wants to merge 4 commits into
base: trunk
Choose a base branch
from

Conversation

desaiuditd
Copy link
Member

@desaiuditd desaiuditd commented Jun 6, 2021

Description

Fixes #13509. Potentially addresses #21236, #42400, #36118 as well. Also fixes a bug described below.

Steps to reproduce

  • Login as User A.
  • Create a post in block editor. Let's say with Post ID - 1. Do not publish it.
  • Make any changes right before the user session is about to expire and wait for session expiry and do not save the post.
    • Testing Note: One way to achieve this is by making some changes in the post content and immediately deleting all the cookies. Do not save the post.
  • Wait for the on-page WordPress login popup to appear. Stay on the screen. Do not log back in just yet.
  • Login as User B in different browser or incognito mode.
  • Wait for the post lock to expire for User A on Post with ID - 1.
  • Open the Post with ID - 1 as User B once post is not locked anymore.
  • Observe that the post has last persisted changes made by User A.
  • Make some changes in the post as User B and save it. Do not publish it.
  • Leave this window open for User B.
  • Meanwhile, go back to User A window and re-login.
  • Notice from dev console that an autosave request is triggered with User A's last unsaved changes from the open browser.
  • Also notice that until next heartbeat happens, you can actually go ahead and make changes and save the post as User A after re-login, even though the post is locked by User B.
  • Come back to User B window and refresh the page.
  • Notice that you lost changes made by User B.

How has this been tested?

With the fix in this PR, I tested above reproduction steps. After User A re-logs in, there's not autosave request triggered, User A immediately sees the PostLockedModal preventing any further updates and User B is not loosing the content anymore.

Types of changes

  • Non-breaking change
  • Bug fix

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • I've tested my changes with keyboard and screen readers.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.
  • I've updated all React Native files affected by any refactorings/renamings in this PR (please manually search all *.native.js files for terms that need renaming or removal).

@desaiuditd desaiuditd added [Type] Bug An existing feature does not function as intended [Feature] Saving Related to saving functionality labels Jun 6, 2021
@desaiuditd desaiuditd self-assigned this Jun 6, 2021
@desaiuditd desaiuditd requested a review from nerrad as a code owner June 6, 2021 04:30
@desaiuditd
Copy link
Member Author

desaiuditd commented Jun 6, 2021

Some of the changes I've made here ... they can be questionable. Would like to get any initial feedback and iterate on this, if needed. Please feel free to point me to right direction if I've missed or unknowingly neglected anything.

@github-actions
Copy link

github-actions bot commented Jun 6, 2021

Size Change: +361 B (0%)

Total Size: 1.71 MB

Filename Size Change
build/core-data/index.min.js 72.8 kB +106 B (0%)
build/editor/index.min.js 62 kB +255 B (0%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 955 B
build/annotations/index.min.js 2.69 kB
build/api-fetch/index.min.js 2.32 kB
build/autop/index.min.js 2.1 kB
build/blob/index.min.js 578 B
build/block-directory/index.min.js 7.22 kB
build/block-directory/style-rtl.css 1.02 kB
build/block-directory/style.css 1.02 kB
build/block-editor/content-rtl.css 4.35 kB
build/block-editor/content.css 4.35 kB
build/block-editor/default-editor-styles-rtl.css 381 B
build/block-editor/default-editor-styles.css 381 B
build/block-editor/index.min.js 251 kB
build/block-editor/style-rtl.css 15.4 kB
build/block-editor/style.css 15.4 kB
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 60 B
build/block-library/blocks/archives/style-rtl.css 90 B
build/block-library/blocks/archives/style.css 90 B
build/block-library/blocks/audio/editor-rtl.css 150 B
build/block-library/blocks/audio/editor.css 150 B
build/block-library/blocks/audio/style-rtl.css 122 B
build/block-library/blocks/audio/style.css 122 B
build/block-library/blocks/audio/theme-rtl.css 126 B
build/block-library/blocks/audio/theme.css 126 B
build/block-library/blocks/avatar/editor-rtl.css 116 B
build/block-library/blocks/avatar/editor.css 116 B
build/block-library/blocks/avatar/style-rtl.css 104 B
build/block-library/blocks/avatar/style.css 104 B
build/block-library/blocks/block/editor-rtl.css 305 B
build/block-library/blocks/block/editor.css 305 B
build/block-library/blocks/button/editor-rtl.css 415 B
build/block-library/blocks/button/editor.css 414 B
build/block-library/blocks/button/style-rtl.css 627 B
build/block-library/blocks/button/style.css 626 B
build/block-library/blocks/buttons/editor-rtl.css 337 B
build/block-library/blocks/buttons/editor.css 337 B
build/block-library/blocks/buttons/style-rtl.css 332 B
build/block-library/blocks/buttons/style.css 332 B
build/block-library/blocks/calendar/style-rtl.css 239 B
build/block-library/blocks/calendar/style.css 239 B
build/block-library/blocks/categories/editor-rtl.css 113 B
build/block-library/blocks/categories/editor.css 112 B
build/block-library/blocks/categories/style-rtl.css 124 B
build/block-library/blocks/categories/style.css 124 B
build/block-library/blocks/code/editor-rtl.css 53 B
build/block-library/blocks/code/editor.css 53 B
build/block-library/blocks/code/style-rtl.css 121 B
build/block-library/blocks/code/style.css 121 B
build/block-library/blocks/code/theme-rtl.css 124 B
build/block-library/blocks/code/theme.css 124 B
build/block-library/blocks/columns/editor-rtl.css 108 B
build/block-library/blocks/columns/editor.css 108 B
build/block-library/blocks/columns/style-rtl.css 421 B
build/block-library/blocks/columns/style.css 421 B
build/block-library/blocks/comment-author-avatar/editor-rtl.css 125 B
build/block-library/blocks/comment-author-avatar/editor.css 125 B
build/block-library/blocks/comment-content/style-rtl.css 92 B
build/block-library/blocks/comment-content/style.css 92 B
build/block-library/blocks/comment-template/style-rtl.css 199 B
build/block-library/blocks/comment-template/style.css 198 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 123 B
build/block-library/blocks/comments-pagination-numbers/editor.css 121 B
build/block-library/blocks/comments-pagination/editor-rtl.css 222 B
build/block-library/blocks/comments-pagination/editor.css 209 B
build/block-library/blocks/comments-pagination/style-rtl.css 235 B
build/block-library/blocks/comments-pagination/style.css 231 B
build/block-library/blocks/comments-title/editor-rtl.css 75 B
build/block-library/blocks/comments-title/editor.css 75 B
build/block-library/blocks/comments/editor-rtl.css 840 B
build/block-library/blocks/comments/editor.css 839 B
build/block-library/blocks/comments/style-rtl.css 637 B
build/block-library/blocks/comments/style.css 636 B
build/block-library/blocks/cover/editor-rtl.css 647 B
build/block-library/blocks/cover/editor.css 650 B
build/block-library/blocks/cover/style-rtl.css 1.69 kB
build/block-library/blocks/cover/style.css 1.68 kB
build/block-library/blocks/details/editor-rtl.css 65 B
build/block-library/blocks/details/editor.css 65 B
build/block-library/blocks/details/style-rtl.css 98 B
build/block-library/blocks/details/style.css 98 B
build/block-library/blocks/embed/editor-rtl.css 322 B
build/block-library/blocks/embed/editor.css 322 B
build/block-library/blocks/embed/style-rtl.css 410 B
build/block-library/blocks/embed/style.css 410 B
build/block-library/blocks/embed/theme-rtl.css 126 B
build/block-library/blocks/embed/theme.css 126 B
build/block-library/blocks/file/editor-rtl.css 316 B
build/block-library/blocks/file/editor.css 316 B
build/block-library/blocks/file/style-rtl.css 280 B
build/block-library/blocks/file/style.css 281 B
build/block-library/blocks/file/view.min.js 324 B
build/block-library/blocks/footnotes/style-rtl.css 201 B
build/block-library/blocks/footnotes/style.css 199 B
build/block-library/blocks/form-input/editor-rtl.css 227 B
build/block-library/blocks/form-input/editor.css 227 B
build/block-library/blocks/form-input/style-rtl.css 343 B
build/block-library/blocks/form-input/style.css 343 B
build/block-library/blocks/form-submission-notification/editor-rtl.css 340 B
build/block-library/blocks/form-submission-notification/editor.css 340 B
build/block-library/blocks/form-submit-button/style-rtl.css 69 B
build/block-library/blocks/form-submit-button/style.css 69 B
build/block-library/blocks/form/view.min.js 471 B
build/block-library/blocks/freeform/editor-rtl.css 2.61 kB
build/block-library/blocks/freeform/editor.css 2.61 kB
build/block-library/blocks/gallery/editor-rtl.css 947 B
build/block-library/blocks/gallery/editor.css 952 B
build/block-library/blocks/gallery/style-rtl.css 1.72 kB
build/block-library/blocks/gallery/style.css 1.72 kB
build/block-library/blocks/gallery/theme-rtl.css 108 B
build/block-library/blocks/gallery/theme.css 108 B
build/block-library/blocks/group/editor-rtl.css 654 B
build/block-library/blocks/group/editor.css 654 B
build/block-library/blocks/group/style-rtl.css 57 B
build/block-library/blocks/group/style.css 57 B
build/block-library/blocks/group/theme-rtl.css 78 B
build/block-library/blocks/group/theme.css 78 B
build/block-library/blocks/heading/style-rtl.css 189 B
build/block-library/blocks/heading/style.css 189 B
build/block-library/blocks/html/editor-rtl.css 336 B
build/block-library/blocks/html/editor.css 337 B
build/block-library/blocks/image/editor-rtl.css 863 B
build/block-library/blocks/image/editor.css 862 B
build/block-library/blocks/image/style-rtl.css 1.6 kB
build/block-library/blocks/image/style.css 1.59 kB
build/block-library/blocks/image/theme-rtl.css 126 B
build/block-library/blocks/image/theme.css 126 B
build/block-library/blocks/image/view.min.js 1.54 kB
build/block-library/blocks/latest-comments/style-rtl.css 357 B
build/block-library/blocks/latest-comments/style.css 357 B
build/block-library/blocks/latest-posts/editor-rtl.css 213 B
build/block-library/blocks/latest-posts/editor.css 212 B
build/block-library/blocks/latest-posts/style-rtl.css 478 B
build/block-library/blocks/latest-posts/style.css 478 B
build/block-library/blocks/list/style-rtl.css 88 B
build/block-library/blocks/list/style.css 88 B
build/block-library/blocks/media-text/editor-rtl.css 266 B
build/block-library/blocks/media-text/editor.css 263 B
build/block-library/blocks/media-text/style-rtl.css 505 B
build/block-library/blocks/media-text/style.css 503 B
build/block-library/blocks/more/editor-rtl.css 431 B
build/block-library/blocks/more/editor.css 431 B
build/block-library/blocks/navigation-link/editor-rtl.css 668 B
build/block-library/blocks/navigation-link/editor.css 669 B
build/block-library/blocks/navigation-link/style-rtl.css 259 B
build/block-library/blocks/navigation-link/style.css 257 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 296 B
build/block-library/blocks/navigation-submenu/editor.css 295 B
build/block-library/blocks/navigation/editor-rtl.css 2.25 kB
build/block-library/blocks/navigation/editor.css 2.26 kB
build/block-library/blocks/navigation/style-rtl.css 2.24 kB
build/block-library/blocks/navigation/style.css 2.23 kB
build/block-library/blocks/navigation/view.min.js 1.1 kB
build/block-library/blocks/nextpage/editor-rtl.css 395 B
build/block-library/blocks/nextpage/editor.css 395 B
build/block-library/blocks/page-list/editor-rtl.css 377 B
build/block-library/blocks/page-list/editor.css 377 B
build/block-library/blocks/page-list/style-rtl.css 175 B
build/block-library/blocks/page-list/style.css 175 B
build/block-library/blocks/paragraph/editor-rtl.css 235 B
build/block-library/blocks/paragraph/editor.css 235 B
build/block-library/blocks/paragraph/style-rtl.css 335 B
build/block-library/blocks/paragraph/style.css 335 B
build/block-library/blocks/post-author/style-rtl.css 175 B
build/block-library/blocks/post-author/style.css 176 B
build/block-library/blocks/post-comments-form/editor-rtl.css 96 B
build/block-library/blocks/post-comments-form/editor.css 96 B
build/block-library/blocks/post-comments-form/style-rtl.css 508 B
build/block-library/blocks/post-comments-form/style.css 508 B
build/block-library/blocks/post-content/editor-rtl.css 74 B
build/block-library/blocks/post-content/editor.css 74 B
build/block-library/blocks/post-date/style-rtl.css 61 B
build/block-library/blocks/post-date/style.css 61 B
build/block-library/blocks/post-excerpt/editor-rtl.css 71 B
build/block-library/blocks/post-excerpt/editor.css 71 B
build/block-library/blocks/post-excerpt/style-rtl.css 141 B
build/block-library/blocks/post-excerpt/style.css 141 B
build/block-library/blocks/post-featured-image/editor-rtl.css 666 B
build/block-library/blocks/post-featured-image/editor.css 662 B
build/block-library/blocks/post-featured-image/style-rtl.css 342 B
build/block-library/blocks/post-featured-image/style.css 342 B
build/block-library/blocks/post-navigation-link/style-rtl.css 215 B
build/block-library/blocks/post-navigation-link/style.css 214 B
build/block-library/blocks/post-template/editor-rtl.css 99 B
build/block-library/blocks/post-template/editor.css 98 B
build/block-library/blocks/post-template/style-rtl.css 409 B
build/block-library/blocks/post-template/style.css 408 B
build/block-library/blocks/post-terms/style-rtl.css 96 B
build/block-library/blocks/post-terms/style.css 96 B
build/block-library/blocks/post-time-to-read/style-rtl.css 69 B
build/block-library/blocks/post-time-to-read/style.css 69 B
build/block-library/blocks/post-title/style-rtl.css 100 B
build/block-library/blocks/post-title/style.css 100 B
build/block-library/blocks/preformatted/style-rtl.css 125 B
build/block-library/blocks/preformatted/style.css 125 B
build/block-library/blocks/pullquote/editor-rtl.css 135 B
build/block-library/blocks/pullquote/editor.css 135 B
build/block-library/blocks/pullquote/style-rtl.css 354 B
build/block-library/blocks/pullquote/style.css 354 B
build/block-library/blocks/pullquote/theme-rtl.css 168 B
build/block-library/blocks/pullquote/theme.css 168 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/query-pagination-numbers/editor.css 121 B
build/block-library/blocks/query-pagination/editor-rtl.css 221 B
build/block-library/blocks/query-pagination/editor.css 211 B
build/block-library/blocks/query-pagination/style-rtl.css 288 B
build/block-library/blocks/query-pagination/style.css 284 B
build/block-library/blocks/query-title/style-rtl.css 63 B
build/block-library/blocks/query-title/style.css 63 B
build/block-library/blocks/query/editor-rtl.css 486 B
build/block-library/blocks/query/editor.css 486 B
build/block-library/blocks/query/view.min.js 958 B
build/block-library/blocks/quote/style-rtl.css 237 B
build/block-library/blocks/quote/style.css 237 B
build/block-library/blocks/quote/theme-rtl.css 223 B
build/block-library/blocks/quote/theme.css 226 B
build/block-library/blocks/read-more/style-rtl.css 140 B
build/block-library/blocks/read-more/style.css 140 B
build/block-library/blocks/rss/editor-rtl.css 149 B
build/block-library/blocks/rss/editor.css 149 B
build/block-library/blocks/rss/style-rtl.css 289 B
build/block-library/blocks/rss/style.css 288 B
build/block-library/blocks/search/editor-rtl.css 184 B
build/block-library/blocks/search/editor.css 184 B
build/block-library/blocks/search/style-rtl.css 614 B
build/block-library/blocks/search/style.css 614 B
build/block-library/blocks/search/theme-rtl.css 114 B
build/block-library/blocks/search/theme.css 114 B
build/block-library/blocks/search/view.min.js 478 B
build/block-library/blocks/separator/editor-rtl.css 146 B
build/block-library/blocks/separator/editor.css 146 B
build/block-library/blocks/separator/style-rtl.css 229 B
build/block-library/blocks/separator/style.css 229 B
build/block-library/blocks/separator/theme-rtl.css 194 B
build/block-library/blocks/separator/theme.css 194 B
build/block-library/blocks/shortcode/editor-rtl.css 323 B
build/block-library/blocks/shortcode/editor.css 323 B
build/block-library/blocks/site-logo/editor-rtl.css 754 B
build/block-library/blocks/site-logo/editor.css 754 B
build/block-library/blocks/site-logo/style-rtl.css 204 B
build/block-library/blocks/site-logo/style.css 204 B
build/block-library/blocks/site-tagline/editor-rtl.css 86 B
build/block-library/blocks/site-tagline/editor.css 86 B
build/block-library/blocks/site-title/editor-rtl.css 116 B
build/block-library/blocks/site-title/editor.css 116 B
build/block-library/blocks/site-title/style-rtl.css 57 B
build/block-library/blocks/site-title/style.css 57 B
build/block-library/blocks/social-link/editor-rtl.css 184 B
build/block-library/blocks/social-link/editor.css 184 B
build/block-library/blocks/social-links/editor-rtl.css 682 B
build/block-library/blocks/social-links/editor.css 681 B
build/block-library/blocks/social-links/style-rtl.css 1.49 kB
build/block-library/blocks/social-links/style.css 1.48 kB
build/block-library/blocks/spacer/editor-rtl.css 348 B
build/block-library/blocks/spacer/editor.css 348 B
build/block-library/blocks/spacer/style-rtl.css 48 B
build/block-library/blocks/spacer/style.css 48 B
build/block-library/blocks/table/editor-rtl.css 395 B
build/block-library/blocks/table/editor.css 395 B
build/block-library/blocks/table/style-rtl.css 639 B
build/block-library/blocks/table/style.css 639 B
build/block-library/blocks/table/theme-rtl.css 146 B
build/block-library/blocks/table/theme.css 146 B
build/block-library/blocks/tag-cloud/style-rtl.css 251 B
build/block-library/blocks/tag-cloud/style.css 253 B
build/block-library/blocks/template-part/editor-rtl.css 403 B
build/block-library/blocks/template-part/editor.css 403 B
build/block-library/blocks/template-part/theme-rtl.css 101 B
build/block-library/blocks/template-part/theme.css 101 B
build/block-library/blocks/term-description/style-rtl.css 111 B
build/block-library/blocks/term-description/style.css 111 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B
build/block-library/blocks/text-columns/editor.css 95 B
build/block-library/blocks/text-columns/style-rtl.css 166 B
build/block-library/blocks/text-columns/style.css 166 B
build/block-library/blocks/verse/style-rtl.css 99 B
build/block-library/blocks/verse/style.css 99 B
build/block-library/blocks/video/editor-rtl.css 552 B
build/block-library/blocks/video/editor.css 555 B
build/block-library/blocks/video/style-rtl.css 185 B
build/block-library/blocks/video/style.css 185 B
build/block-library/blocks/video/theme-rtl.css 126 B
build/block-library/blocks/video/theme.css 126 B
build/block-library/classic-rtl.css 179 B
build/block-library/classic.css 179 B
build/block-library/common-rtl.css 1.1 kB
build/block-library/common.css 1.1 kB
build/block-library/editor-elements-rtl.css 75 B
build/block-library/editor-elements.css 75 B
build/block-library/editor-rtl.css 12.3 kB
build/block-library/editor.css 12.3 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/index.min.js 216 kB
build/block-library/reset-rtl.css 472 B
build/block-library/reset.css 472 B
build/block-library/style-rtl.css 14.8 kB
build/block-library/style.css 14.7 kB
build/block-library/theme-rtl.css 688 B
build/block-library/theme.css 693 B
build/block-serialization-default-parser/index.min.js 1.12 kB
build/block-serialization-spec-parser/index.min.js 2.87 kB
build/blocks/index.min.js 51.8 kB
build/commands/index.min.js 15.6 kB
build/commands/style-rtl.css 921 B
build/commands/style.css 918 B
build/components/index.min.js 226 kB
build/components/style-rtl.css 11.8 kB
build/components/style.css 11.8 kB
build/compose/index.min.js 12.6 kB
build/core-commands/index.min.js 2.77 kB
build/customize-widgets/index.min.js 12.1 kB
build/customize-widgets/style-rtl.css 1.34 kB
build/customize-widgets/style.css 1.33 kB
build/data-controls/index.min.js 640 B
build/data/index.min.js 8.93 kB
build/date/index.min.js 17.9 kB
build/deprecated/index.min.js 451 B
build/dom-ready/index.min.js 324 B
build/dom/index.min.js 4.65 kB
build/edit-post/classic-rtl.css 544 B
build/edit-post/classic.css 545 B
build/edit-post/index.min.js 25.2 kB
build/edit-post/style-rtl.css 5.66 kB
build/edit-post/style.css 5.66 kB
build/edit-site/index.min.js 212 kB
build/edit-site/style-rtl.css 15.8 kB
build/edit-site/style.css 15.9 kB
build/edit-widgets/index.min.js 17.3 kB
build/edit-widgets/style-rtl.css 4.23 kB
build/edit-widgets/style.css 4.23 kB
build/editor/style-rtl.css 5.43 kB
build/editor/style.css 5.43 kB
build/element/index.min.js 4.83 kB
build/escape-html/index.min.js 537 B
build/format-library/index.min.js 7.88 kB
build/format-library/style-rtl.css 478 B
build/format-library/style.css 477 B
build/hooks/index.min.js 1.55 kB
build/html-entities/index.min.js 448 B
build/i18n/index.min.js 3.58 kB
build/interactivity/file.min.js 447 B
build/interactivity/image.min.js 1.67 kB
build/interactivity/index.min.js 12.7 kB
build/interactivity/navigation.min.js 1.24 kB
build/interactivity/query.min.js 740 B
build/interactivity/router.min.js 1.29 kB
build/interactivity/search.min.js 618 B
build/is-shallow-equal/index.min.js 527 B
build/keyboard-shortcuts/index.min.js 1.74 kB
build/keycodes/index.min.js 1.46 kB
build/list-reusable-blocks/index.min.js 2.11 kB
build/list-reusable-blocks/style-rtl.css 836 B
build/list-reusable-blocks/style.css 836 B
build/media-utils/index.min.js 2.9 kB
build/modules/importmap-polyfill.min.js 12.2 kB
build/notices/index.min.js 948 B
build/nux/index.min.js 2 kB
build/nux/style-rtl.css 735 B
build/nux/style.css 732 B
build/patterns/index.min.js 5.74 kB
build/patterns/style-rtl.css 540 B
build/patterns/style.css 539 B
build/plugins/index.min.js 1.8 kB
build/preferences-persistence/index.min.js 2.07 kB
build/preferences/index.min.js 2.82 kB
build/preferences/style-rtl.css 698 B
build/preferences/style.css 700 B
build/primitives/index.min.js 975 B
build/priority-queue/index.min.js 1.52 kB
build/private-apis/index.min.js 1 kB
build/react-i18n/index.min.js 623 B
build/react-refresh-entry/index.min.js 9.47 kB
build/react-refresh-runtime/index.min.js 6.78 kB
build/redux-routine/index.min.js 2.7 kB
build/reusable-blocks/index.min.js 2.72 kB
build/reusable-blocks/style-rtl.css 243 B
build/reusable-blocks/style.css 243 B
build/rich-text/index.min.js 10.4 kB
build/router/index.min.js 1.79 kB
build/server-side-render/index.min.js 1.95 kB
build/shortcode/index.min.js 1.39 kB
build/style-engine/index.min.js 2.08 kB
build/token-list/index.min.js 582 B
build/url/index.min.js 3.72 kB
build/vendors/inert-polyfill.min.js 2.48 kB
build/vendors/react-dom.min.js 41.8 kB
build/vendors/react.min.js 4.02 kB
build/viewport/index.min.js 957 B
build/warning/index.min.js 249 B
build/widgets/index.min.js 7.21 kB
build/widgets/style-rtl.css 1.15 kB
build/widgets/style.css 1.16 kB
build/wordcount/index.min.js 1.02 kB

compressed-size-action

@@ -1128,7 +1132,7 @@ export function getPermalinkParts( state ) {
* @return {boolean} Is locked.
*/
export function isPostLocked( state ) {
return state.postLock.isLocked;
return state.postLock?.isLocked ?? false;
Copy link
Member Author

@desaiuditd desaiuditd Jun 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ This is irrelevant change to the issue. Without this certain unit tests started to fail complaining about postLock being undefined in the state. This will just make sure that it has valid fallback.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in the test file we usually just made sure a default is set. So for consistency probably best to update those tests too.

// In either case, we don't want to accidentally loose the changes made by other user.
// If we perform server side autosave, and the post is in draft, previous changes will be overwritten in the database.
// Hence, we will only perform local autosave.
autosave( { local: true } );
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ Ideally, isPostLocked check (which is part of isEditedPostSaveable check which in turn is part of isEditedPostAutosaveable) should be able to prevent this server autosave request. But somehow it seems like the data store at point of time in code execution is not properly updated. Hence, I'm still observing the network request for the autosave in the browser. Hence, I decided to put local: true to prevent the server autosave.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we perform server side autosave, and the post is in draft, previous changes will be overwritten in the database.

I don't think that's true. It creates a new autosave, not overriding any of the other user's changes. The original post and the other user's autosave both still exist.

So this change would break that.

FWIW it's possible to write e2e tests around post locking and autosaves... Sounds like now would be a good time to do that :-)

// update login state to true.
updateCurrentUserSession( { isActive: true } );
}
}
Copy link
Member Author

@desaiuditd desaiuditd Jun 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ This whole function (which is managing the current user session in data store) can be questionable and there could be better way to handle this. So I'm happy to take any advise of improvement here.

isLocked,
isTakeover,
user,
postId,
postLockUtils,
activePostLock,
postType,
isCurrentUserSessionActive,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ For now, this data (isCurrentUserSessionActive) is only being used in this component and could well be a local state instead of being in the data store. But I can think of few use cases where we would want to check for current user sessions. I myself thought about using the same in AutosaveMonitor component. (This was when I was exploring potential fix in this PR. Eventually the need did not arise. So I removed that code before committing.) But the point is, there is a use case and can be a need in future.

@georgeh
Copy link
Contributor

georgeh commented Jul 14, 2022

Thanks for tackling this. I was able to reproduce the error in trunk, but was not able to get your branch working in my wp-env environment. Could you rebase the branch and I'll try again?

This does look like a good approach. I initially was thinking that this should be rejecting the updates on the server side, but it looks like that is already happening and the client is working around that rejection.

@desaiuditd
Copy link
Member Author

@georgeh Sorry, I've not been able to get back to this PR. I got busy with other things. I'll try to revive this PR this weekend.

@desaiuditd desaiuditd marked this pull request as draft February 1, 2024 09:05
@desaiuditd desaiuditd force-pushed the fix/prevent-autosave-when-post-is-locked branch 4 times, most recently from 5d2f23b to 4179f51 Compare February 9, 2024 12:19
@desaiuditd desaiuditd marked this pull request as ready for review February 9, 2024 12:38
Copy link

github-actions bot commented Feb 9, 2024

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Unlinked Accounts

The following contributors have not linked their GitHub and WordPress.org accounts: @georgeh, @jayhill90.

Contributors, please read how to link your accounts to ensure your work is properly credited in WordPress releases.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Unlinked contributors: georgeh, jayhill90.

Co-authored-by: desaiuditd <desaiuditd@git.wordpress.org>
Co-authored-by: swissspidy <swissspidy@git.wordpress.org>
Co-authored-by: youknowriad <youknowriad@git.wordpress.org>
Co-authored-by: jsnajdr <jsnajdr@git.wordpress.org>
Co-authored-by: Mamaduka <mamaduka@git.wordpress.org>
Co-authored-by: nateinaction <nateinaction@git.wordpress.org>
Co-authored-by: desrosj <desrosj@git.wordpress.org>
Co-authored-by: matzeeable <mguenter@git.wordpress.org>
Co-authored-by: skorasaurus <skorasaurus@git.wordpress.org>
Co-authored-by: ryanboswell <ryan-boswell@git.wordpress.org>
Co-authored-by: mboynes <mboynes@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@desaiuditd desaiuditd force-pushed the fix/prevent-autosave-when-post-is-locked branch from 4179f51 to 6576ebc Compare February 9, 2024 12:46
So that we can prevent saving if the post is locked.

We also prevent disabling Preview button when the post is not saveable. This is ripple effect of adding isPostLocked check in `isEditedPostSaveable` selector. We can safely remove this check on `Preview` button, because #32341 will prevent any save actions under the hood.
- Prevent autosave right before releasing the post lock.
- Update current user session as per the heartbeat response.
- We need to prevent save/update actions if the post is locked right after user logs back in on the same page. To do this, we need to show the modal as soon as user logs back in. Hence, we will re-trigger heartbeat right after nonce is renewed, so that we can update isPostLocked in data store.
@desaiuditd desaiuditd force-pushed the fix/prevent-autosave-when-post-is-locked branch from 6576ebc to 1ccdeda Compare February 9, 2024 13:09
@desaiuditd
Copy link
Member Author

@georgeh I think this is ready for review.

@georgeh
Copy link
Contributor

georgeh commented Feb 9, 2024

@desaiuditd sorry I haven't been keeping up with the project and am not in a position to re-review

@desaiuditd
Copy link
Member Author

@desrosj @Mamaduka @mrfoxtalbot @johnbillion @aristath @ellatrix @ntsekouras @nerrad @jsnajdr @tyxla @andrewserong

How can I move this PR forward? Can any of you help to review and test it?

@desaiuditd
Copy link
Member Author

I've tested and verified on my local after syncing my branch with latest trunk. I can still see the bug occurring on trunk and this branch fixes it.

@desaiuditd
Copy link
Member Author

desaiuditd commented Feb 15, 2024

@WordPress/gutenberg-core @WordPress/gutenberg Apologies for a wider ping here. But this PR has got stale without any attention for quite some time now.

Can I get some feedback on the code changes and help to review, test and move it forward? Don't want it to become stale again.

@jsnajdr
Copy link
Member

jsnajdr commented Feb 15, 2024

Hi @desaiuditd 👋 I'm looking at this, trying to understand how do the heartbeats and post locks work.

One thing that immediately comes to mind are the admin-ajax.php requests. It would be nice if we had a REST endpoint for this.

@swissspidy
Copy link
Member

One thing that immediately comes to mind are the admin-ajax.php requests. It would be nice if we had a REST endpoint for this.

I once built a custom REST endpoint for post locking so that I don't have to use the heartbeat API:

https://github.com/GoogleForCreators/web-stories-wp/blob/0634e91314aeffb5fa461d84240f0eb54f9efd3f/includes/REST_API/Stories_Lock_Controller.php

@Mamaduka
Copy link
Member

@spacedmonkey proposed porting that or a similar API - #37789.

@@ -106,8 +106,8 @@ export default function PostPreviewButton( {
role,
onPreview,
} ) {
const { postId, currentPostLink, previewLink, isSaveable, isViewable } =
useSelect( ( select ) => {
const { postId, currentPostLink, previewLink, isViewable } = useSelect(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why remove the isSaveable check in this component?

isEditedPostSaveable returns false if the post is considered empty and it doesn't make sense to preview an empty post.

@@ -139,22 +139,6 @@ describe( 'PostPreviewButton', () => {
).toBeInTheDocument();
} );

it( 'should be disabled if post is not saveable.', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per my other comment, it doesn't seem right to remove this functionality.

@@ -1128,7 +1132,7 @@ export function getPermalinkParts( state ) {
* @return {boolean} Is locked.
*/
export function isPostLocked( state ) {
return state.postLock.isLocked;
return state.postLock?.isLocked ?? false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in the test file we usually just made sure a default is set. So for consistency probably best to update those tests too.

// In either case, we don't want to accidentally loose the changes made by other user.
// If we perform server side autosave, and the post is in draft, previous changes will be overwritten in the database.
// Hence, we will only perform local autosave.
autosave( { local: true } );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we perform server side autosave, and the post is in draft, previous changes will be overwritten in the database.

I don't think that's true. It creates a new autosave, not overriding any of the other user's changes. The original post and the other user's autosave both still exist.

So this change would break that.

FWIW it's possible to write e2e tests around post locking and autosaves... Sounds like now would be a good time to do that :-)

@@ -141,7 +211,7 @@ export default function PostLockedModal() {
removeAction( 'heartbeat.tick', hookName );
window.removeEventListener( 'beforeunload', releasePostLock );
};
}, [] );
}, [ isDraft, isLocked ] );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intentional? More dependencies means the effect is triggered more often. I think an empty dependencies array was deliberately chosen here.

@@ -185,6 +186,21 @@ export function getCurrentUser( state: State ): ET.User< 'edit' > {
return state.currentUser;
}

/**
*Returns a boolean flag for current user's active login session.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
*Returns a boolean flag for current user's active login session.
* Returns a boolean flag for current user's active login session.

Comment on lines +84 to +91
// Bail early, if the heartbeat has neither auth check data attribute nor nonce expiry attribute.
if (
! [ 'wp-auth-check', 'nonces_expired' ].some( ( attr ) =>
Object.prototype.hasOwnProperty.call( data, attr )
)
) {
return;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

auth-check.js in core only looks at wp-auth-check, not nonces_expired, see https://github.com/WordPress/wordpress-develop/blob/7b24083859c37d8ac75b9549f458bc389610eaef/src/js/_enqueues/lib/auth-check.js#L162-L168

So I'd remove the nonces_expired check here.

And then simplify to:

Suggested change
// Bail early, if the heartbeat has neither auth check data attribute nor nonce expiry attribute.
if (
! [ 'wp-auth-check', 'nonces_expired' ].some( ( attr ) =>
Object.prototype.hasOwnProperty.call( data, attr )
)
) {
return;
}
if ( ! 'wp-auth-check' in data ) {
return;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we used apiFetch for the heartbeat request, then we wouldn't need to care about nonces at all, because apiFetch handles them internally (nonce middleware). Automatically requesting a new one when the old one expires etc.

I'm not sure if admin-ajax.php is compatible with apiFetch or whether we'd need to create a REST endpoint first.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No that would require a REST endpoint. See the ither comments about that.

This comment here is still relevant for admin-ajax

*
* @return {Object} Action object.
*/
export function __experimentalUpdateCurrentUserSession( currentUserSession ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like local state. core-data was not really mean to store things like that. So can you explain more the reasoning here and what this is about?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this state could be very easily moved to the editor store, to the state.postLock object. That object already has plenty of fields (isLocked, isTakeover, user, ...), so why not add another isUserActive field there?

All other aspects of this user session check should be integrated into the post lock state, too. Why add another hook to heartbeat.tick, if we can just expand the existing receivePostLock function?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving this to the postLock object sounds confusing. Post lock state is coming from an entirely different API response and it's easy to accidentally override postLock.isUserActive (or vice-versa) in the process.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then it could be renamed to state.heartbeat, with subfields for post lock, auth check and possibly other things. They are all requested together, and also used together.

}
}

addAction( 'heartbeat.tick', checkUserLoginHookName, checkUserLogin );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already subscribe to this action in the hook down here. Was it a deliberate choice to separate these two logics. The reasoning is not clear to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Saving Related to saving functionality Needs Testing Needs further testing to be confirmed. [Type] Bug An existing feature does not function as intended
Projects
None yet
6 participants