Removing `.alert` from the dark theme seems acceptable,
as there is nowhere in the codebase we're setting a
`text-shadow` value that would require `none` here.
This helps preserve the original form in production.
The new "Import from" option button allows user to automate the
process, so this is not required in that case.
Updates the example banner in the devtools banner design page
for the changes to the demo organization banner.
This removes all uses of the banner-link class, but we keep the CSS
rules, since they're part of a component we may use elsewhere.
Updates the navbar alert banner for demo organizations to have
buttons that align with the general bannner design.
All users have a button that opens the help center article about
demo organizations. Demo organization owners have an additional
button that opens the modal to convert a demo organization into
a permanent organization.
Part of #34447.
Updates handle_demo_organization_conversion to only set up the
event listeners for the current convert organization banner in
the organization settings overlay for admins.
Moves code for launching the modal to convert the demo organization
to a permanent organization to do_convert_demo_organization.
Prep for adding a button to the navbar alert banner for demo
organization owners that will also launch the modal to convert
the organization.
Moves the get_demo_organization_deadline_days_remaining helper from
"web/src/navbar_alerts.ts" to "web/src/demo_organizations_ui.ts".
Prep commit for updating the navbar alert for demo organization to
have a button that opens the modal for converting the organization
to a permanent organization.
Instead of using the "tip" formatting for the note suggesting
updating the name for the owner's account before inviting other
users, to be just normal text at the top of the modal.
Part of #34447.
Instead of having two separate "create_without_add_button" and
"create" functions for handling creation and editing UI, this
commit updates code to use only "create" function with a
parameter passed to determine whether we want "Add" button with
the widget or not.
Replaced "server" with "system" so that the macro can be used with all
integrations with integration scripts, irrespective of whether it needs
to be run from a server or a user's machine.
Replaced "bot" with "integration script" to ensure that the integration
script is not confused with the Zulip bot user that is created using the
UI in the instruction above this instruction.
For the DM conversation with the current user, use "Messages with
yourself" for the message header bar and tooltip.
Fixes#33321.
Co-authored-by: Lauryn Menard <lauryn@zulip.com>
For the DM conversation with the current user, show "Messages with
yourself" for the title, which is determined by the filter for the
message list view.
Co-authored-by: Lauryn Menard <lauryn@zulip.com>
Adds "You" and "Drafts from conversations with yourself" as
labels in the drafts overlay for the DM conversation with
the current user.
Co-authored-by: Lauryn Menard <lauryn@zulip.com>
When the compose box is closed, if the selected message is for the
direct conversation with the current user, then we show "Message
yourself" as the compose reply button text.
Adds `decode_dm_recipients_user_ids_from_url` helper function to
hash_util, which parses a narrow URL for DM recipient user IDs.
Checks that "dm" operand, which should be a string of user emails,
also passes the check for all the email addresses being valid
compose recipients.
Co-Authored-By: Lauryn Menard <lauryn@zulip.com>
When the current user opens the compose box to send a DM to
themself, use "Message yourself" as the placeholder text when
the compose box is empty.
Adds `is_direct_message_conversation_with_self` as a helper
function to people.ts that checks a list of user IDs to see
if it only contains the current user's ID. This function is
useful for additional parts of the web app UI where we want
to show a distinct message/text for this case.
Co-authored-by: Lauryn Menard <lauryn@zulip.com>
This commit updates the Slack incoming webhook endpoint to use the same
Slack reformatting functions (`convert_to_zulip_markdown` and
`replace_links`) that are used for Slack data import and cleaning up any
duplicative functions.
This was previously not possible because the Slack reformatting regex in
`slack_message_conversion.py` could not handle these cases:
- Formatting applied to non-ASCII characters (e.g., emoji).
- Formatted strings separated by exactly one character.
- Formatted strings appearing immediately after a new line.
Fixes part of #31162.
The Slack text regexes match specific characters before and after the
formatted string to ensure that they only match at word boundaries.
However, because the capture groups consume each matching character,
including the characters used to determine word boundaries, two
formatted strings separated by a single matching character result in one
string not being matched, as the trailing whitespace is already
consumed and cannot also match as the leading pre-match whitespace for
the next character.
Switch to a look-ahead regex for the trailing word boundary
characters. This is zero-width, and as such the next match can still
also consume the same characters.
This also fixes Slack webhook integrations'
`test_message_with_complex_formatted_mentions` which was previously
expecting false output.
Fixes part of #30827.
The inner capture group of Slack text regex is used to capture the
formatted text, so basically all characters but the formatting
characters like *, ~, and _.
It currently does this by specifying a range of characters to be
captured except the formatting characters. This unintentionally excluded
non-ASCII characters like emoji.
This commit simplifies the inner capture groups of the Slack text regex
to explicitly exclude formatting characters (e.g., *, ~, _) instead of
using an allowlist to not include them.
This change is part of the effort to make `convert_to_zulip_markdown`
compatible with output from `render_blocks` and `render_attachments`,
which may contain emoji.
The inner capture groups of the Slack text regex tries to captures the
formatted string. For an unclear reason, we're currently using two
similar capture groups despite the fact that only using the second
capture groups would suffice.
This removes the first capture groups.
This prep commit modifies the Slack text regex in
`slack_message_conversion.py` to use the `re.MULTILINE` flag capture
formatted strings that are adjacent to newline or end of line.
These kinds of strings are likely not uncommon to be generated by Slack
exporter itself and our Slack message block and attachment formatters
(`render_blocks` and `render_attachments`) also produces them.
This also fixes Slack webhook integration's
`test_message_with_complex_formatted_texts` which was previously
expecting false output.
Fixes part of #30827.
In `convert_markdown_syntax`, `re.finditer` is used to iterate over each
`match` found in the `text`. In each iteration, we create the Zulip
formatting equivalent of the current `match` and do a `text.replace()`
to replace all strings in `text` that matches the current `match`.
Since we're planning to add the `re.MULTILINE` flag to `re.finditer`, it
would be problematic if the first and last capture group of `match` are
zero-width characters (newlines). This is because
`convert_markdown_syntax` would reformat all identical strike-through
and bold formatted strings as many time as there are identical `match`es
of them.
Consider the following:
---
original text: "*foo*\n*foo*"
1. <re.Match object; span=(0, 5), match='*foo*'>
1st replace -> "**foo**\n**foo**"
2. <re.Match object; span=(6, 11), match='*foo*'>
2nd replace -> "***foo***\n***foo***"
---
This commit uses `re.sub` instead of `re.finditer`, which does replace
operation only on the specific piece of the original text the `match` is
from.
This updates the patterns to use a more unicode-aware pattern for their
first and last capture groups. The new patterns have the same
behaviours, but they're expressed in a more coherent way.
For example, the existing patterns lists what characters to look for,
skipping ceratin characters it don't want to match (e.g, closing
brackets & quote are skipped). The new pattern narrows down what it
looks for (whitespace, punctuation, symbols) and explicitly list what it
don't want to match (closing quote and bracket, etc).
This also refactors the `convert_markdown_syntax` to use the `regex`
module instead of the `re` module because the `regex` module has full
unicode support.
The `push.{EXTERNAL_HOST}` formula effectively assumes that the host
in EXTERNAL_HOST is zulipdev.com -- it's relying on the fact that
push.zulipdev.com is in DNS as an alias of zulipdev.com. That's a
special fact that wouldn't be true of most hostnames.
It especially isn't true of IP addresses. If one has set
EXTERNAL_HOST to a value like `192.168.0.2:9991` -- for example in
order to reach the dev server from a separate machine, such as a
physical mobile device:
https://github.com/zulip/zulip-mobile/blob/main/docs/howto/dev-server.md
then setting ZULIP_SERVICES_URL to `http://push.192.168.0.2:9991`
is definitely not going to work. For example:
https://chat.zulip.org/#narrow/channel/243-mobile-team/topic/notifications.20from.20dev.20server/near/2159863
In the dev server, the point with ZULIP_SERVICES_URL is that it
should point back to the same dev server. So use a formula that
says that more directly and so more reliably.
Tests are a different matter: we want a distinct URL there, because
we'll be inspecting the URLs in requests. But in tests there's also
no requirement that the two hosts have anything to do with each
other; so the existing formula is fine there, and keep it in place.
(In tests it'd probably be better to use proper RFC 6761 test
domains, like `chat.example.com` and `push.example.net`. But
that's an independent question.)
This was broken, due the mechanism simply using our
is_guest/is_realm_admin/etc. role setters, but failing to adjust system
group memberships - resulting in corrupted database state.
We need to ensure that change_user_role is called for setting user role.
There are two relevant codepaths that run the sync based on
AUTH_LDAP_USER_FLAGS_BY_GROUP and thus need to get this right:
1. manage.py sync_ldap_user_data
2. Just-in-time user creation when a user without a Zulip account logs
in for the first using their ldap credentials. After
get_or_build_user returns, django-auth-ldap sees that the user
account has just been created, and proceeds to run ._populate_user().
Now that both user.save() and do_change_user_realm will be getting
called together, we need to ensure this always happens atomically.
This imposes the need to override _get_or_create_user to put it in a
transaction. The troublesome consequence is that this new
`atomic(savepoint=False)` causes the usual type of issue, where tests
testing error get their transaction rolled back and cannot continue
executing.
To get around that, we add a test helper
`artificial_transaction_savepoint` which allows these tests to wrap
their problematic blocks in an artificial transaction which provides a
savepoint, thus preventing the full test transaction rollback derailing
the rest of the test.
Without these overrides, we cannot test the functionality in DEVELOPMENT
and TESTING.
There are two codepaths that we're covering here:
1. The sync which happens via `sync_ldap_user_data`.
2. The sync which happens during just-in-time user creation upon first
login via ldap.
Both codepaths end up triggering ldap_user._get_or_create_user().