Commit graph

54 commits

Author SHA1 Message Date
Bartosz Dziewoński af68c835bb Update exception handling for new code conventions
Change code to match the documented consensus formed on T321683:
https://www.mediawiki.org/wiki/Manual:Coding_conventions/PHP#Exception_handling

* Do not directly throw Exception, Error or MWException
* Document checked exceptions with @throws
* Do not document unchecked exceptions

For this extension, I think it makes sense to consider DOMException an
unchecked exception too (in addition to the usual LogicException and
RuntimeException).

Depends-On: Id07e301c3f20afa135e5469ee234a27354485652
Depends-On: I869af06896b9757af18488b916211c5a41a8c563
Depends-On: I42d9b7465d1406a22ef1b3f6d8de426c60c90e2c
Change-Id: Ic9d9efd031a87fa5a93143f714f0adb20f0dd956
2023-01-22 18:17:11 +00:00
Sam Smith 50853a3db6 EventDispatcher: Remove reference to $wgWMESchemaEditAttemptStepOversample
At the time of writing, $wgWMESchemaEditAttemptStepOversample is not a
global variable in PHP [0].

[0] https://codesearch.wmcloud.org/search/?q=WMESchemaEditAttemptStepOversample

Bug: T312016
Change-Id: I6a8abceddc9fce2f28f7a154fa2fc566538ed5e8
2022-10-03 12:05:23 +01:00
jenkins-bot 2ce1822484 Merge "Use cheaper getRawVal/getCheck instead of getVal where possible" 2022-09-03 05:33:08 +00:00
Thiemo Kreuz 62ddb8bceb Use cheaper getRawVal/getCheck instead of getVal where possible
getVal/getText can be expensive because they do Unicode normalization.
We can skip this when we know we aren't going to do anything meaningful
with the value anyway.

Change-Id: I9d939a44df6b67bcd8429096d89600ce1566ca39
2022-09-03 05:27:20 +00:00
Bartosz Dziewoński d33996f8b4 Notify users when a topic they are subscribed to is removed from a page
In the future the notifications can be improved to look up
the new location of the comment, using the permalinks data.

Depends-On: Ia8a21749a8edc20f34b2a3e445278ea6922b9109
Bug: T299657
Change-Id: I5f5e7b73fb84ff0d31fb8260b24066a17da71628
2022-08-25 03:52:58 +02:00
Umherirrender 0a53b4d468 EventDispatcher: Remove use of UserFactory in logAddedComments
Possible since 1828d40

Change-Id: I0cc49a101858177bd9f7e75c18003277dd97725d
2022-08-05 01:43:16 +02:00
Bartosz Dziewoński 880f9755e0 Separate ContentThreadItem and DatabaseThreadItem etc.
Rename ThreadItem to ContentThreadItem, then create a new ThreadItem
interface containing only the methods that we'll be able to implement
using only the persistently stored data (no parsing), then create a
DatabaseThreadItem. Do the same for CommentItem and HeadingItem.

ThreadItemSet gets a similar treatment, but it's basically only for
Phan's type checking. (This is sad.)

Change-Id: I1633049befe8ec169753b82eb876459af1f63fe8
2022-07-04 23:35:50 +02:00
Ed Sanders af54bae2ec Prefer late static binding over self::
While in many cases the class will never be sub-classed, it's easier
just to always use static:: and not worry about predicting which
classes might have problems in the future.

Change-Id: I23072a1701b5acf62bb3379a877de97627d8fcf3
2022-06-09 15:12:48 +01:00
Bartosz Dziewoński c7723baf72 CommentParser: Replace uses of Title with TitleValue
Another small step towards removing the reliance on global state.

Change-Id: Ifb4a5bcbef6606d02f1c7aa7385d72822cb0bad0
2022-03-18 18:24:34 +00:00
Reedy 524c8edf5c Use namespaced EventLogging class
Change-Id: Ic9f11b12edb5da08c2f4b31bea2a6517737ee6af
2022-03-06 16:10:40 +00:00
Bartosz Dziewoński 8e44b43df0 Split off ThreadItemSet from CommentParser
Goal:
-----
Finishing the work from Iadb7757debe000025e52770ca51ebcf24ca8ee66
by changing CommentParser::parse() to return a data object, instead of
the whole parser.

Changes:
--------
ThreadItemSet.php:
ThreadItemSet.js:
* New data class to access the results of parsing a discussion. Most
  methods and properties are moved from CommentParser with no changes.

CommentParser.php:
Parser.js:
* parse() returns a new ThreadItemSet.
* Remove methods moved to ThreadItemSet.
* Placeholder headings are generated slightly differently, as we process
  things in a different order.
* Grouping threads and computing IDs/names is no longer lazy. We always
  needed IDs/names anyway.
* computeId() explicitly uses a ThreadItemSet to check the existing IDs
  when de-duplicating.

controller.js:
* Move the code for turning some nodes annotated by CommentFormatter
  into a ThreadItemSet (previously a Parser) from controller#init to
  ThreadItemSet.static.newFromAnnotatedNodes, and rewrite it to handle
  assigning parents/replies and recalculating legacy IDs more nicely.
* mw.dt.pageThreads is now a ThreadItemSet.

Change-Id: I49bfe019aa460651447fd383f73eafa9d7180a92
2022-02-21 16:22:32 +00:00
Bartosz Dziewoński 4613ae78e7 Change CommentParser into a service
Goal:
-----
To have a method like CommentParser::parse(), which just takes a node
to parse and a title and returns plain data, so that we don't need to
keep track of the config to construct a CommentParser object (the
required config like content language is provided by services) and
we don't need to keep that object around after parsing.

Changes:
--------
CommentParser.php:
* …is now a service. Constructor only takes services as arguments.
  The node and title are passed to a new parse() method.
* parse() should return plain data, but I split this part to a separate
  patch for ease of review: I49bfe019aa460651447fd383f73eafa9d7180a92.
* CommentParser still cheats and accesses global state in a few places,
  e.g. calling Title::makeTitleSafe or CommentUtils::getTitleFromUrl,
  so we can't turn its tests into true unit tests. This work is left
  for future commits.

LanguageData.php:
* …is now a service, instead of a static class.

Parser.js:
* …is not a real service, but it's changed to behave in a similar way.
  Constructor takes only the required config as argument,
  and node and title are instead passed to a new parse() method.

CommentParserTest.php:
parser.test.js:
* Can be simplified, now that we don't need a useless node and title
  to test internal methods that don't use them.

testUtils.js:
* Can be simplified, now that we don't need to override internal
  ResourceLoader stuff just to change the parser config.

Change-Id: Iadb7757debe000025e52770ca51ebcf24ca8ee66
2022-02-19 19:51:57 +01:00
David Lynch d1e62d364d Log talk_page_edit events for adding a new topic
Bug: T301496
Change-Id: I618339f254c89db45891ee403f037c555afdda6e
2022-02-14 11:48:16 -06:00
Ed Sanders 6d655dee0a Remove DiscussionToolsEnableTopicSubscriptionBackend config
This is now deployed on all wikis, and going forward I don't think
we need to make this configurable.

Change-Id: I231976267ba6cdfeec622efaa15983a84c330649
2022-02-04 18:22:10 +00:00
Ed Sanders 34011b7a07 Parser: Pass in title of page being parsed
Will be used to parse selflinks in the future.

Change-Id: I2bc29d1c5c69cb6309f582f162f9af7d96ce8913
2022-01-12 21:17:59 +00:00
Umherirrender d32dcfbb3c Use ParserOptions::newFromAnon instead of ParserOptions::newCanonical
ParserOptions::newCanonical is deprecated.

Change-Id: I26667c9102c37d962ceaa81c082566819b503744
2021-12-18 20:15:02 +01:00
Ed Sanders d2443f7785 Rename DiscussionToolsAutoTopicSubWhere to DiscussionToolsAutoTopicSubEditor
Better describes that we are checking the editor used to make
the edit, rather than descibing some virtual "location".

Change options to 'discussiontoolsapi' and 'any'.

Change-Id: I3024517e70ed61c738e4bf46a2ac7b58c975d98a
2021-12-15 16:24:35 +00:00
Bartosz Dziewoński a96c52869b Fix PageRecord lookup
According to Daniel it only worked by accident, and stopped working
after de63ad823abe:

getPageByReference() used to do an opportunistic lookup by ID when given
an instance of PageIdentity -- which is correct for EventDispatcher,
but problematic in the general case, causing T296063.

The correct thing to do here is to use getPageById(), since the canonical
association between revision and page is by page ID.

Bug: T297431
Change-Id: Icc1df0c9ca5345e65ef5f8daf0815013d7db0943
2021-12-10 12:46:55 +00:00
Ed Sanders 8e4f08182e Add missing typehints
Change-Id: Ia25c5bea1834a3fdd26f32a9d5ed097789329824
2021-12-01 14:57:09 +00:00
David Lynch 17a3ac295e Fixes for talk_page_edit logging
* Add a N/A value for edit counts from anonymous users
* Only oversample with $wgDTSchemaEditAttemptStepOversample if the edit
  is from DiscussionTools
* Consider $wgWMESchemaEditAttemptStepOversample for oversampling

Bug: T286076
Bug: T295995
Depends-On: Ieb3f6c6e1775c1ef53747c37003b17e3634d1c44
Change-Id: I91245a61dfbde8b5ec9b2893b9170cc4d73f7b0a
2021-11-19 17:02:15 +00:00
Bartosz Dziewoński 8d3cf30f60 Automatic topic subscriptions (only for reply tool and new topic tool)
Bug: T284836
Change-Id: I0f98c26c997f66b7a43cd4b971fe72a37d12db5d
2021-11-15 22:45:42 +01:00
Bartosz Dziewoński 0d57aa9762 Automatic topic subscriptions (on any edit)
Bug: T284836
Change-Id: Ia42ad087218fd91a0cdd1664157d1049738e3c01
2021-11-15 22:45:42 +01:00
Ed Sanders 0fba9b0048 Suppress events from comments that are more than 10 minutes old
Bug: T290803
Change-Id: Ic0e23f439eef8a1b785f408d4557bec0abe9104b
2021-11-09 16:37:46 +00:00
David Lynch df47f9fda3 Logging for new comments
Bug: T286076
Change-Id: Ic78a49aedcb03d160d74ba3fa9660f3583f0e568
2021-10-28 21:50:23 +00:00
jenkins-bot abd6c2fedd Merge "Enhance Echo user talk edit and mention notifications" 2021-09-24 02:17:57 +00:00
Bartosz Dziewoński 435b0c65c7 Enhance Echo user talk edit and mention notifications
If the user talk edit or mention coincides with exactly one new comment:
* Change the primary link to be a direct link to the comment
* Add a text snippet to notifications that don't already include one
  (user talk edits that are not new sections).

This is done for all such notifications, regardless of whether anyone
has topic subscriptions enabled.

Bug: T281590
Bug: T253082
Change-Id: I98fbca8e57845cd7c82ad533c393db953e4e5643
2021-09-20 15:05:42 +02:00
Bartosz Dziewoński 0ae97ef550 Deduplicate logic for subscribable headings
Change-Id: I1cd96cf0bcce2101455702f1350d8a4336c60790
2021-09-07 21:38:35 +00:00
Bartosz Dziewoński 4bbbdc9703 EventDispatcher: Try really, really hard to read from master
Follow-up to 37d6825c14.

Bug: T289717
Depends-On: I2a614915c7d9ffbc4f466204b2684478fb52f30e
Change-Id: Id2e040a19e457a2a8f4121b04ebd43bf6ea64181
2021-08-25 21:38:10 +02:00
Bartosz Dziewoński bcd92a5d33 Minor cleanups in topic subscription code
For automatic topic subscriptions, I plan to introduce a third
subscription state to indicate them. This patch includes minor tweaks
I wanted to add while working on that:

* Introduce constants instead of numbers
* Remove a TODO that doesn't seem like a good idea any more
* Remove a `"length": 1` on sub_state that did not do anything
  (but it might have been meant to indicate that it was supposed
  to be a boolean, which would be wrong)

Bug: T284836
Change-Id: I6e6096968ad38510102287bccd349090b6ca4280
2021-08-17 22:22:15 +02:00
jenkins-bot 781992de2d Merge "Create a hidden revision tag for talk page comments" 2021-08-17 02:07:10 +00:00
jenkins-bot e090c455cc Merge "EventDispatcher: Fix ignoring level 3+ headings" 2021-08-16 22:08:42 +00:00
jenkins-bot 2cd97c4be5 Merge "Handle highlighting and scrolling to comments for bundled notifications" 2021-08-16 20:43:37 +00:00
Bartosz Dziewoński db28a3d3a7 Handle highlighting and scrolling to comments for bundled notifications
Notifications are bundled by section, so instead of linking to the
comment, link to the section.

Additionally, add a parameter to the URL listing all the comment IDs
from the bundle, and highlight them all and scroll to the topmost one.

Having to handle both URL fragments and URL query parameters makes
this code kind of a mess :(

Also, some unexpected changes became necessary:

* EventDispatcher.php: Store the section title in events using
  HeadingItem::getLinkableTitle() instead of ThreadItem::getText().
  The result is mostly the same, except in case of wacky markup like
  images or extension tags. We can more reliably use it to link to the
  section on the page, and we already use getLinkableTitle() when
  generating edit summaries in the reply tool for this reason.

* dt.init.less: Change the mix-blend-mode for the highlights from
  'multiply' to 'darken', so that multiple overlapping highlights do
  not look more opaque. This affects how the highlights look on
  non-white backgrounds and images (they're less blue, and on darker
  backgrounds entirely invisible), but it seems worth it.

Bug: T286620
Change-Id: I21bb5c003abc2747f0350d3f3af558dfb55693e9
2021-08-16 22:03:30 +02:00
Bartosz Dziewoński ad04b24ffd Create a hidden revision tag for talk page comments
Bug: T262107
Depends-On: I21159d03eebaf46ad94f4273ba698a59b8019185
Change-Id: Iceddfaf6a4bcc5e8b5c85c8cd5638bf14aa7db03
2021-08-16 15:42:51 +00:00
Bartosz Dziewoński 47510a22f3 EventDispatcher: Fix ignoring level 3+ headings
The code (prior to d25825a754) assumed
that level 3+ headings would always follow a level 2 heading or the
placeholder heading, but we don't generate a placeholder heading if
there are no comments in section zero.

Add more tests to confirm that comments under level 3+ headings (that
are not sub-headings of level 2), and level 1 headings, are ignored
when generating notifications, and do not mess with normal headings.

Bug: T288775
Change-Id: Ic57b56752a4797cb01234f66e0ed7b849752bd70
2021-08-16 15:42:06 +00:00
Bartosz Dziewoński d25825a754 EventDispatcher: Remove failing invariant check
To be investigated in the future.

Bug: T288775
Change-Id: Ic27418a0ec976347be5fa586bbd32cc4a0d8d511
2021-08-12 22:37:51 +02:00
jenkins-bot 10c23d0eb1 Merge "Deal with document body consistently" 2021-08-06 03:08:28 +00:00
Bartosz Dziewoński 8de8d80cde Deal with document body consistently
Use `DOMCompat::getBody( ... )` as a nicer getter than
`->getElementsByTagName( 'body' )->item( 0 )`.

Remove overly defensive checks and redundant annotations on its
return value. Since we're dealing with HTML documents throughout,
the document body is guaranteed to exist.

We previously needed some of them to convince Phan when it thought
the body may be null, but this seems to no longer be needed.

Change-Id: If7aee7b6adbfa78269c7ba28b26a6eaa21fe935b
2021-08-03 15:12:55 +02:00
Bartosz Dziewoński a5099739a6 Improve notifications for comments posted in close succession
In case 4 and case 6, no notifications are expected. In all other
cases we now get the expected notifications.

Bug: T285528
Change-Id: I9e813bb3a053bc1232783f9eae1ad75672b4fa7e
2021-08-01 12:27:33 +02:00
C. Scott Ananian 25272e7a4a Don't refer directly to PHP dom extension classes; avoid nonstandard behavior
These changes ensure that DiscussionTools is independent of DOM
library choice, and will not break if/when Parsoid switches to an
alternate (more standards-compliant) DOM library.

We run `phan` against the Dodo standards-compliant DOM library,
so this ends up flagging uses of non-standard PHP extensions to
the DOM.  These will be suppressed for now with a "Nonstandard DOM"
comment that can be grepped for, since they will eventually
will need to be rewritten or worked around.

Most frequent issues:

* Node::nodeValue and Node::textContent and Element::getAttribute()
can return null in a spec-compliant implementation.  Add `?? ''` to
make spec-compliant results consistent w/ what PHP returns.

* DOMXPath doesn't accept anything except DOMDocument.  These uses
should be replaced with DOMCompat::querySelectorAll() or similar
(which end up using DOMXPath under the covers for DOMDocument any way,
but are implemented more efficiently in a spec-compliant
implementation).

* A couple of times we have code like:
  `while ($node->firstChild!==null) { $node = $node->firstChild; }`
and phan's analysis isn't strong enough to determine that $node is still
non-null after the while.  This same issue should appear with DOMDocument
but phan doesn't complain for some reason.

One apparently legit issue:

* Node::insertBefore() is once called in a funny way which leans on
the fact that the second option is optional in PHP.  This seems to be
a workaround for an ancient PHP bug, and can probably be safely
removed.

Bug: T287611
Bug: T217867
Change-Id: I3c4f41c3819770f85d68157c9f690d650b7266a3
2021-07-30 18:15:40 -04:00
Bartosz Dziewoński d0e4aeaecb Fix notifications when new comment is under subheading
The user interface only allows you to subscribe to level 2 headings.
But we would generate events for whatever heading was the closest,
If it was e.g. level 3, no one would receive that notification.

Now we generate events for the closest level 2 heading, or we don't
generate the event at all if there isn't one (if the only headings are
of level 3 and below, or level 1, or if the comment is added before
the first heading on the page).

Bug: T286736
Change-Id: Iae99853070e353ab81c9cc29ef1d53c877adfc66
2021-07-24 05:28:10 +02:00
Bartosz Dziewoński 801b57b0f4 Add PHPUnit integration tests for EventDispatcher
Bug: T286608
Change-Id: I711483be80d455f4439e96d37844ee4552619a92
2021-07-24 05:28:04 +02:00
libraryupgrader b0884b177c build: Updating dependencies
composer:
* mediawiki/mediawiki-codesniffer: 36.0.0 → 37.0.0

npm:
* postcss: 7.0.35 → 7.0.36
  * https://npmjs.com/advisories/1693 (CVE-2021-23368)
* glob-parent: 5.1.1 → 5.1.2
  * https://npmjs.com/advisories/1751 (CVE-2020-28469)
* trim-newlines: 3.0.0 → 3.0.1
  * https://npmjs.com/advisories/1753 (CVE-2021-33623)

Change-Id: I7a71e23da561599da417db3b3077b78d91173bbc
2021-07-22 16:29:04 +00:00
Bartosz Dziewoński 37d6825c14 EventDispatcher: Ensure we fetch page content from the primary database
We used an internal API requests to fetch page content because it was
easy, but there's no way to guarantee that it returns data from the
primary database.

Use ParserOutputAccess::getParserOutput() to fetch from cache if
available. Also, use canonical output instead of user-specific,
not that it should matter.

Bug: T285895
Change-Id: I7dcd9659be77746dc2a0c4eeae2319887936b555
2021-07-01 14:52:13 +00:00
Bartosz Dziewoński 067f0c36de Config option to enable topic subscriptions backend and dtenable=1 URL parameter
…without making the topic subscriptions feature available in user preferences.

Follow-up to these commits, which added these checks in ad-hoc ways:
* 9420f22e9d
* f3422f40a6
* 23a490deca
* a555db7892

Bug: T284491
Change-Id: If2e3fb1e06d1cc489fbca14796ed77c83bb52991
2021-06-14 16:18:18 +02:00
Bartosz Dziewoński 4353b68646 EventDispatcher: Read revision IDs to compare from master
Bug: T284175
Change-Id: Iec99ea0afc659969108104cf5b2627856711544d
2021-06-02 19:47:35 +00:00
libraryupgrader 12fb65b9f1 build: Updating composer dependencies
* mediawiki/mediawiki-codesniffer: 35.0.0 → 36.0.0
* php-parallel-lint/php-parallel-lint: 1.2.0 → 1.3.0

Change-Id: I5c152292e83e7f3441e2c08b7d0ad23ac90f194b
2021-05-05 11:14:52 +00:00
Ed Sanders 2f40fd96b1 EventDispatcher: Store comment name in event metadata
This will probably be useful later, so better to ensure
the data is captured now.

Change-Id: I8936ee85a2775ad48839e9c3ebf5bc3d5355c501
2021-04-22 16:23:39 +00:00
Ed Sanders a9537782ac EventDispatcher: Compare new comments by name, not ID
Change-Id: I9d7907dda0f443e4e3b0463a127ea4def68051f3
2021-04-22 16:15:09 +00:00
Ed Sanders e20fcea122 EventDispatcher: Only generate events if author matches user
Bug: T280783
Change-Id: I8a0ea2ac3aefb66b693ee219b88619248bb25fb2
2021-04-22 16:14:01 +00:00