python: Pre-fix a few spots for better Black formatting.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg 2020-09-01 17:50:08 -07:00 committed by Tim Abbott
parent c67ea05423
commit f91d287447
33 changed files with 123 additions and 97 deletions

View File

@ -124,8 +124,10 @@ _properties = {
Confirmation.INVITATION: ConfirmationType('check_prereg_key_and_redirect',
validity_in_days=settings.INVITATION_LINK_VALIDITY_DAYS),
Confirmation.EMAIL_CHANGE: ConfirmationType('zerver.views.user_settings.confirm_email_change'),
Confirmation.UNSUBSCRIBE: ConfirmationType('zerver.views.unsubscribe.email_unsubscribe',
validity_in_days=1000000), # should never expire
Confirmation.UNSUBSCRIBE: ConfirmationType(
'zerver.views.unsubscribe.email_unsubscribe',
validity_in_days=1000000, # should never expire
),
Confirmation.MULTIUSE_INVITE: ConfirmationType(
'zerver.views.registration.accounts_home_from_multiuse_invite',
validity_in_days=settings.INVITATION_LINK_VALIDITY_DAYS),

View File

@ -47,10 +47,11 @@ output = subprocess.check_output(['/usr/sbin/rabbitmqctl', 'list_consumers'],
consumers: Dict[str, int] = defaultdict(int)
sys.path.append(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))))
queues = set(normal_queues).union({
queues = {
*normal_queues,
# These queues may not be present if settings.TORNADO_PROCESSES > 1
'notify_tornado',
})
}
for queue_name in queues:
queue_name = queue_name.strip()

View File

@ -97,9 +97,9 @@ def restore_backup(tarball_file: IO[bytes]) -> None:
run(
[
os.path.join(
settings.DEPLOY_ROOT, "scripts", "setup", "terminate-psql-sessions",
settings.DEPLOY_ROOT, "scripts", "setup", "terminate-psql-sessions"
),
db["NAME"],
db["NAME"]
],
env=postgres_env,
)
@ -136,8 +136,8 @@ def restore_backup(tarball_file: IO[bytes]) -> None:
run(
[
os.path.join(settings.DEPLOY_ROOT, "scripts", "zulip-puppet-apply"),
"-f",
],
"-f"
]
)
# Now, restore the the database backup using pg_restore. This

View File

@ -28,7 +28,7 @@ EXCLUDED_URLS = [
'https://www.udemy.com/course/the-complete-react-native-and-redux-course/',
]
VNU_IGNORE = re.compile(r'|'.join([
VNU_IGNORE = [
# Real errors that should be fixed.
r'Duplicate ID “[^”]*”\.',
r'The first occurrence of ID “[^”]*” was here\.',
@ -39,7 +39,8 @@ VNU_IGNORE = re.compile(r'|'.join([
# Warnings that are probably less important.
r'The “type” attribute is unnecessary for JavaScript resources\.',
]))
]
VNU_IGNORE_REGEX = re.compile(r'|'.join(VNU_IGNORE))
class BaseDocumentationSpider(scrapy.Spider):
@ -91,7 +92,7 @@ class BaseDocumentationSpider(scrapy.Spider):
def callback(response: Response) -> None:
vnu_out = json.loads(response.text)
for message in vnu_out['messages']:
if not VNU_IGNORE.fullmatch(message['message']):
if not VNU_IGNORE_REGEX.fullmatch(message['message']):
self.logger.error(
'"%s":%d.%d-%d.%d: %s: %s',
url,

View File

@ -174,15 +174,15 @@ SPLIT_BOUNDARY = '?.!' # Used to split string into sentences.
SPLIT_BOUNDARY_REGEX = re.compile(fr'[{SPLIT_BOUNDARY}]')
# Regexes which check capitalization in sentences.
DISALLOWED_REGEXES = [re.compile(regex) for regex in [
DISALLOWED = [
r'^[a-z](?!\})', # Checks if the sentence starts with a lower case character.
r'^[A-Z][a-z]+[\sa-z0-9]+[A-Z]', # Checks if an upper case character exists
# after a lower case character when the first character is in upper case.
]]
]
DISALLOWED_REGEX = re.compile(r"|".join(DISALLOWED))
BANNED_WORDS = {
'realm': ('The term realm should not appear in user-facing strings. '
'Use organization instead.'),
'realm': 'The term realm should not appear in user-facing strings. Use organization instead.',
}
def get_safe_phrase(phrase: str) -> str:
@ -232,18 +232,7 @@ def get_safe_text(text: str) -> str:
def is_capitalized(safe_text: str) -> bool:
sentences = SPLIT_BOUNDARY_REGEX.split(safe_text)
sentences = [sentence.strip()
for sentence in sentences if sentence.strip()]
if not sentences:
return False
for sentence in sentences:
for regex in DISALLOWED_REGEXES:
if regex.search(sentence):
return False
return True
return not any(DISALLOWED_REGEX.search(sentence.strip()) for sentence in sentences)
def check_banned_words(text: str) -> List[str]:
lower_cased_text = text.lower()

View File

@ -72,7 +72,7 @@ WORD_SET = {
'uses', 'using', 'used',
}
imperative_forms = sorted([
imperative_forms = [
'add', 'allow', 'amend', 'bump', 'calculate', 'change', 'clean', 'commit',
'correct', 'create', 'darken', 'disable', 'display', 'document', 'dry',
'end', 'enforce', 'enqueue', 'extract', 'finish', 'fix', 'format', 'guard',
@ -81,7 +81,8 @@ imperative_forms = sorted([
'refactor', 'remove', 'rename', 'reorder', 'replace', 'require', 'restore',
'send', 'separate', 'set', 'show', 'simplify', 'skip', 'sort', 'speed',
'start', 'support', 'take', 'test', 'truncate', 'update', 'use',
])
]
imperative_forms.sort()
def head_binary_search(key: Text, words: List[str]) -> str:

View File

@ -22,7 +22,7 @@ import responses
from django.conf import settings
from django.test.utils import get_runner
target_fully_covered = {path for target in [
target_fully_covered = [
'analytics/lib/*.py',
'analytics/models.py',
'analytics/tests/*.py',
@ -51,9 +51,9 @@ target_fully_covered = {path for target in [
# 'zerver/webhooks/*/*.py',
# 'zerver/webhooks/*/*/*.py',
'zerver/worker/*.py',
] for path in glob.glob(target)}
]
not_yet_fully_covered = {path for target in [
not_yet_fully_covered = [
# Analytics fixtures library is used to generate test fixtures;
# isn't properly accounted for in test coverage analysis since it
# runs before tests.
@ -136,9 +136,12 @@ not_yet_fully_covered = {path for target in [
'zerver/webhooks/teamcity/view.py',
'zerver/webhooks/travis/view.py',
'zerver/webhooks/zapier/view.py',
] for path in glob.glob(target)}
]
enforce_fully_covered = sorted(target_fully_covered - not_yet_fully_covered)
enforce_fully_covered = sorted(
{path for target in target_fully_covered for path in glob.glob(target)}
- {path for target in not_yet_fully_covered for path in glob.glob(target)}
)
FAILED_TEST_PATH = 'var/last_test_failure.json'

View File

@ -102,10 +102,9 @@ class IsCapitalizedTestCase(TestCase):
string = ""
capitalized = is_capitalized(string)
self.assertFalse(capitalized)
self.assertTrue(capitalized)
string = ("Please re-enter your password to confirm your identity."
" (Forgotten it?)")
string = "Please re-enter your password to confirm your identity. (Forgotten it?)"
capitalized = is_capitalized(string)
self.assertTrue(capitalized)

View File

@ -300,7 +300,8 @@ def build_recipient(type_id: int, recipient_id: int, type: int) -> ZerverFieldsT
recipient = Recipient(
type_id=type_id, # stream id
id=recipient_id,
type=type)
type=type,
)
recipient_dict = model_to_dict(recipient)
return recipient_dict

View File

@ -1534,7 +1534,8 @@ def do_send_messages(messages_maybe_none: Sequence[Optional[MutableMapping[str,
if message['stream'] is None:
stream_id = message['message'].recipient.type_id
message['stream'] = Stream.objects.select_related().get(id=stream_id)
assert message['stream'] is not None # assert needed because stubs for django are missing
# assert needed because stubs for django are missing
assert message['stream'] is not None
realm_id = message['stream'].realm_id
# Deliver events to the real-time push system, as well as
@ -1592,7 +1593,9 @@ def do_send_messages(messages_maybe_none: Sequence[Optional[MutableMapping[str,
# notify new_message request if it's a public stream,
# ensuring that in the tornado server, non-public stream
# messages are only associated to their subscribed users.
assert message['stream'] is not None # assert needed because stubs for django are missing
# assert needed because stubs for django are missing
assert message['stream'] is not None
if message['stream'].is_public():
event['realm_id'] = message['stream'].realm_id
event['stream_name'] = message['stream'].name

View File

@ -25,8 +25,7 @@ ALL_HOTSPOTS: Dict[str, Dict[str, str]] = {
},
'intro_gear': {
'title': _('Settings'),
'description': _('Go to Settings to configure your '
'notifications and display settings.'),
'description': _('Go to Settings to configure your notifications and display settings.'),
},
'intro_compose': {
'title': _('Compose'),

View File

@ -405,8 +405,7 @@ class FencedBlockPreprocessor(markdown.preprocessors.Preprocessor):
def format_spoiler(self, header: str, text: str) -> str:
output = []
header_div_open_html = '<div class="spoiler-block"><div class="spoiler-header">'
end_header_start_content_html = '</div><div class="spoiler-content"' \
' aria-hidden="true">'
end_header_start_content_html = '</div><div class="spoiler-content" aria-hidden="true">'
footer_html = '</div></div>'
output.append(self.placeholder(header_div_open_html))

View File

@ -17,7 +17,7 @@ def is_disposable_domain(domain: str) -> bool:
return False
return domain.lower() in DISPOSABLE_DOMAINS
ZULIP_RESERVED_SUBDOMAINS = frozenset([
ZULIP_RESERVED_SUBDOMAINS = {
# zulip terms
'stream', 'channel', 'topic', 'thread', 'installation', 'organization', 'realm',
'team', 'subdomain', 'activity', 'octopus', 'acme', 'push',
@ -40,12 +40,12 @@ ZULIP_RESERVED_SUBDOMAINS = frozenset([
# Things that sound like security
'auth', 'authentication', 'security',
# tech blogs
'engineering', 'infrastructure', 'tooling', 'tools', 'javascript', 'python'])
'engineering', 'infrastructure', 'tooling', 'tools', 'javascript', 'python'}
# Most of this list was curated from the following sources:
# http://wiki.dwscoalition.org/notes/List_of_reserved_subdomains (license: CC-BY-SA 3.0)
# https://stackoverflow.com/questions/11868191/which-saas-subdomains-to-block (license: CC-BY-SA 2.5)
GENERIC_RESERVED_SUBDOMAINS = frozenset([
GENERIC_RESERVED_SUBDOMAINS = {
'about', 'abuse', 'account', 'ad', 'admanager', 'admin', 'admindashboard',
'administrator', 'adsense', 'adword', 'affiliate', 'alpha', 'anonymous',
'api', 'assets', 'audio', 'badges', 'beta', 'billing', 'biz', 'blog',
@ -77,12 +77,12 @@ GENERIC_RESERVED_SUBDOMAINS = frozenset([
'testers', 'ticket', 'tool', 'tos', 'trac', 'translate', 'update',
'upgrade', 'uploads', 'use', 'user', 'username', 'validation', 'videos',
'volunteer', 'web', 'webdisk', 'webmail', 'webmaster', 'whm', 'whois',
'wiki', 'www', 'www0', 'www8', 'www9', 'xml', 'xmpp', 'xoxo'])
'wiki', 'www', 'www0', 'www8', 'www9', 'xml', 'xmpp', 'xoxo'}
DISPOSABLE_DOMAINS = frozenset(blacklist)
DISPOSABLE_DOMAINS = set(blacklist)
WHITELISTED_EMAIL_DOMAINS = frozenset([
WHITELISTED_EMAIL_DOMAINS = {
# Controlled by https://www.abine.com; more legitimate than most
# disposable domains
'opayq.com', 'abinemail.com', 'blurmail.net', 'maskmemail.com',
])
}

View File

@ -94,18 +94,19 @@ class Database:
# what the database is as runtime.
# Also we export ZULIP_DB_NAME which is ignored by dev platform but
# recognised by test platform and used to migrate correct db.
env_prelude = [
manage_py = [
'env',
'DJANGO_SETTINGS_MODULE=' + self.settings,
'ZULIP_DB_NAME=' + self.database_name,
'./manage.py',
]
run([
*env_prelude, './manage.py', 'migrate', '--no-input',
*manage_py, 'migrate', '--no-input'
])
run([
*env_prelude, './manage.py', 'get_migration_status', '--output='+self.migration_status_file,
*manage_py, 'get_migration_status', '--output='+self.migration_status_file
])
def what_to_do_with_migrations(self) -> str:

View File

@ -79,9 +79,9 @@ class TextTestResult(runner.TextTestResult):
def addSkip(self, test: TestCase, reason: str) -> None:
TestResult.addSkip(self, test, reason)
self.stream.writeln("** Skipping {}: {}".format( # type: ignore[attr-defined] # https://github.com/python/typeshed/issues/3139
test.id(),
reason))
self.stream.writeln( # type: ignore[attr-defined] # https://github.com/python/typeshed/issues/3139
"** Skipping {}: {}".format(test.id(), reason)
)
self.stream.flush()
class RemoteTestResult(django_runner.RemoteTestResult):

View File

@ -182,11 +182,11 @@ def resize_emoji(image_data: bytes, size: int=DEFAULT_EMOJI_SIZE) -> bytes:
# results in resized gifs being broken. To work around this we
# only resize under certain conditions to minimize the chance of
# creating ugly gifs.
should_resize = any((
im.size[0] != im.size[1], # not square
im.size[0] > MAX_EMOJI_GIF_SIZE, # dimensions too large
len(image_data) > MAX_EMOJI_GIF_FILE_SIZE_BYTES, # filesize too large
))
should_resize = (
im.size[0] != im.size[1] # not square
or im.size[0] > MAX_EMOJI_GIF_SIZE # dimensions too large
or len(image_data) > MAX_EMOJI_GIF_FILE_SIZE_BYTES # filesize too large
)
return resize_gif(im, size) if should_resize else image_data
else:
im = exif_rotate(im)

View File

@ -153,7 +153,6 @@ def query_chunker(queries: List[Any],
q = q.order_by('id')
min_id = -1
while True:
assert db_chunk_size is not None # Hint for mypy, but also workaround for mypy bug #3442.
rows = list(q.filter(id__gt=min_id)[0:db_chunk_size])
if len(rows) == 0:
break

View File

@ -53,7 +53,8 @@ def get_imap_messages() -> Generator[EmailMessage, None, None]:
assert isinstance(msg_data[0], tuple)
msg_as_bytes = msg_data[0][1]
message = email.message_from_bytes(msg_as_bytes, policy=email.policy.default)
assert isinstance(message, EmailMessage) # https://github.com/python/typeshed/issues/2417
# https://github.com/python/typeshed/issues/2417
assert isinstance(message, EmailMessage)
yield message
mbox.store(message_id, '+FLAGS', '\\Deleted')
mbox.expunge()

View File

@ -94,7 +94,8 @@ Example:
else:
with open(fixture_path, "rb") as fp:
message = email.message_from_binary_file(fp, policy=email.policy.default)
assert isinstance(message, EmailMessage) # https://github.com/python/typeshed/issues/2417
# https://github.com/python/typeshed/issues/2417
assert isinstance(message, EmailMessage)
return message
def _prepare_message(self, message: EmailMessage, realm: Realm, stream_name: str) -> None:

View File

@ -383,7 +383,8 @@ class RateLimitMiddleware(MiddlewareMixin):
def process_exception(self, request: HttpRequest,
exception: Exception) -> Optional[HttpResponse]:
if isinstance(exception, RateLimited):
secs_to_freedom = float(str(exception)) # secs_to_freedom is passed to RateLimited when raising
# secs_to_freedom is passed to RateLimited when raising
secs_to_freedom = float(str(exception))
resp = json_error(
_("API usage exceeded rate limit"),
data={'retry-after': secs_to_freedom},

View File

@ -1409,7 +1409,7 @@ def filter_to_valid_prereg_users(query: QuerySet) -> QuerySet:
class MultiuseInvite(models.Model):
id: int = models.AutoField(auto_created=True, primary_key=True, verbose_name='ID')
referred_by: UserProfile = models.ForeignKey(UserProfile, on_delete=CASCADE) # Optional[UserProfile]
referred_by: UserProfile = models.ForeignKey(UserProfile, on_delete=CASCADE)
streams: Manager = models.ManyToManyField('Stream')
realm: Realm = models.ForeignKey(Realm, on_delete=CASCADE)
invited_as: int = models.PositiveSmallIntegerField(default=PreregistrationUser.INVITE_AS['MEMBER'])
@ -2599,7 +2599,8 @@ class UserPresence(models.Model):
@staticmethod
def status_from_string(status: str) -> Optional[int]:
if status == 'active':
status_val: Optional[int] = UserPresence.ACTIVE # See https://github.com/python/mypy/issues/2611
# See https://github.com/python/mypy/issues/2611
status_val: Optional[int] = UserPresence.ACTIVE
elif status == 'idle':
status_val = UserPresence.IDLE
else:

View File

@ -576,7 +576,8 @@ class RateLimitAuthenticationTests(ZulipTestCase):
with mock.patch('time.time', return_value=start_time + 11.0):
self.assertIsNone(attempt_authentication(username, wrong_password))
self.assertEqual(attempt_authentication(username, correct_password), expected_user_profile) # Correct password
# Correct password
self.assertEqual(attempt_authentication(username, correct_password), expected_user_profile)
# A correct login attempt should reset the rate limits for this user profile,
# so the next two attempts shouldn't get limited:
self.assertIsNone(attempt_authentication(username, wrong_password))
@ -1704,7 +1705,7 @@ class SAMLAuthBackendTest(SocialAuthBase):
relay_state = orjson.dumps(dict(
state_token=SAMLAuthBackend.put_data_in_redis({"subdomain": "zulip"}),
)).decode()
post_params = {"RelayState": relay_state, 'SAMLResponse': 'dGVzdA=='} # base64 encoded 'test'
post_params = {"RelayState": relay_state, 'SAMLResponse': base64.b64encode(b"test").decode()}
result = self.client_post('/complete/saml/', post_params)
self.assertEqual(result.status_code, 302)
self.assertIn('login', result.url)
@ -1756,7 +1757,7 @@ class SAMLAuthBackendTest(SocialAuthBase):
relay_state = orjson.dumps(dict(
state_token=SAMLAuthBackend.put_data_in_redis({"subdomain": "zulip"}),
)).decode()
post_params = {"RelayState": relay_state, 'SAMLResponse': 'dGVzdA=='}
post_params = {"RelayState": relay_state, 'SAMLResponse': base64.b64encode(b"test").decode()}
result = self.client_post('/complete/saml/', post_params)
self.assertEqual(result.status_code, 302)
self.assertIn('login', result.url)
@ -4626,7 +4627,8 @@ class TestZulipLDAPUserPopulator(ZulipLDAPTestCase):
do_deactivate_user(othello)
mock_logger = mock.MagicMock()
result = sync_user_from_ldap(othello, mock_logger)
self.assertEqual(mock_logger.method_calls, []) # In this case the logger shouldn't be used.
# In this case the logger shouldn't be used.
self.assertEqual(mock_logger.method_calls, [])
self.assertFalse(result)
def test_update_user_avatar(self) -> None:

View File

@ -1290,7 +1290,8 @@ class TestContentTypeUnspecifiedCharset(ZulipTestCase):
message_as_string = message_as_string.replace("Content-Type: text/plain; charset=\"us-ascii\"",
"Content-Type: text/plain")
incoming_message = message_from_string(message_as_string, policy=email.policy.default)
assert isinstance(incoming_message, EmailMessage) # https://github.com/python/typeshed/issues/2417
# https://github.com/python/typeshed/issues/2417
assert isinstance(incoming_message, EmailMessage)
user_profile = self.example_user('hamlet')
self.login_user(user_profile)

View File

@ -285,7 +285,8 @@ class TestArchiveMessagesGeneral(ArchiveMessagesTestingBase):
# Insert an exception near the end of the archiving process of a chunk:
with mock.patch("zerver.lib.retention.delete_messages", side_effect=Exception):
with self.assertRaises(Exception):
archive_messages(chunk_size=1000) # Specify large chunk_size to ensure things happen in a single batch
# Specify large chunk_size to ensure things happen in a single batch
archive_messages(chunk_size=1000)
# Archiving code has been executed, but because we got an exception, things should have been rolled back:
self._verify_archive_data([], [])
@ -373,7 +374,8 @@ class TestArchiveMessagesGeneral(ArchiveMessagesTestingBase):
restore_all_data_from_archive()
# Attachments should have been restored:
self.assertEqual(Attachment.objects.count(), 3)
self.assertEqual(ArchivedAttachment.objects.count(), 3) # Archived data doesn't get deleted by restoring.
# Archived data doesn't get deleted by restoring.
self.assertEqual(ArchivedAttachment.objects.count(), 3)
self.assertEqual(
list(Attachment.objects.distinct('messages__id').order_by('messages__id').values_list(
'messages__id', flat=True)),

View File

@ -64,7 +64,8 @@ class SlackMessageConversion(ZulipTestCase):
{"id": "U09TYF5Sk",
"name": "Jane",
"is_mirror_dummy": False,
"deleted": True}] # Deleted users don't have 'real_name' key in Slack
"deleted": True, # Deleted users don't have 'real_name' key in Slack
}]
channel_map = {'general': ('C5Z73A7RA', 137)}
message = 'Hi <@U08RGD1RD|john>: How are you? <#C5Z73A7RA|general>'
text, mentioned_users, has_link = convert_to_zulip_markdown(message, users, channel_map, slack_user_map)

View File

@ -3392,7 +3392,8 @@ class SubscriptionAPITest(ZulipTestCase):
self.assert_json_success(result)
json = result.json()
for key, val in json_dict.items():
self.assertEqual(sorted(val), sorted(json[key])) # we don't care about the order of the items
# we don't care about the order of the items
self.assertEqual(sorted(val), sorted(json[key]))
user = get_user(email, realm)
new_streams = self.get_streams(user)
self.assertEqual(sorted(new_streams), sorted(new_subs))
@ -3425,7 +3426,8 @@ class SubscriptionAPITest(ZulipTestCase):
"""
random_streams = self.make_random_stream_names(self.streams)
self.assertNotEqual(len(random_streams), 0) # necessary for full test coverage
streams_to_remove = random_streams[:1] # pick only one fake stream, to make checking the error message easy
# pick only one fake stream, to make checking the error message easy
streams_to_remove = random_streams[:1]
result = self.client_delete("/json/users/me/subscriptions",
{"subscriptions": orjson.dumps(streams_to_remove).decode()})
self.assert_json_error(result, f"Stream(s) ({random_streams[0]}) do not exist")

View File

@ -256,7 +256,8 @@ class EventQueue:
self.queue: Deque[Dict[str, Any]] = deque()
self.next_event_id: int = 0
self.newest_pruned_id: Optional[int] = -1 # will only be None for migration from old versions
# will only be None for migration from old versions
self.newest_pruned_id: Optional[int] = -1
self.id: str = id
self.virtual_events: Dict[str, Dict[str, Any]] = {}

View File

@ -558,7 +558,8 @@ def log_into_subdomain(request: HttpRequest, token: str) -> HttpResponse:
call login_or_register_remote_user, passing all the authentication
result data that has been stored in redis, associated with this token.
"""
if not has_api_key_format(token): # The tokens are intended to have the same format as API keys.
# The tokens are intended to have the same format as API keys.
if not has_api_key_format(token):
logging.warning("log_into_subdomain: Malformed token given: %s", token)
return HttpResponse(status=400)

View File

@ -208,11 +208,14 @@ def join_bigbluebutton(request: HttpRequest, meeting_id: str = REQ(validator=che
if payload.find("returncode").text != "SUCCESS":
return json_error(_("Big Blue Button server returned an unexpected error."))
join_params = urlencode({ # type: ignore[type-var] # https://github.com/python/typeshed/issues/4234
"meetingID": meeting_id,
"password": password,
"fullName": request.user.full_name
}, quote_via=quote)
join_params = urlencode( # type: ignore[type-var] # https://github.com/python/typeshed/issues/4234
{
"meetingID": meeting_id,
"password": password,
"fullName": request.user.full_name,
},
quote_via=quote,
)
checksum = hashlib.sha1(("join" + join_params + settings.BIG_BLUE_BUTTON_SECRET).encode()).hexdigest()
redirect_url_base = add_query_to_redirect_url(settings.BIG_BLUE_BUTTON_URL + "api/join", join_params)

View File

@ -71,7 +71,7 @@ def repo_comment_handler(payload: Dict[str, Any], action: str) -> List[Dict[str,
repo_name = payload["repository"]["name"]
subject = BITBUCKET_TOPIC_TEMPLATE.format(repository_name=repo_name)
sha = payload["commit"]
commit_url = payload["repository"]["links"]["self"][0]["href"][:-6] # remove the "browse" at the end
commit_url = payload["repository"]["links"]["self"][0]["href"][: -len("browse")]
commit_url += f"commits/{sha}"
message = payload["comment"]["text"]
if action == "deleted their comment":

View File

@ -238,7 +238,8 @@ class GitlabHookTests(WebhookTestCase):
def test_note_merge_request_event_message_without_merge_request_title(self) -> None:
expected_topic = "my-awesome-project / MR #1"
expected_message = "Tomasz Kolek [commented](https://gitlab.com/tomaszkolek0/my-awesome-project/merge_requests/1#note_14171860) on [MR #1](https://gitlab.com/tomaszkolek0/my-awesome-project/merge_requests/1):\n\n~~~ quote\nNice merge request!\n~~~"
self.url = self.build_webhook_url(use_merge_request_title="false") # To keep things as valid JSON.
# To keep things as valid JSON.
self.url = self.build_webhook_url(use_merge_request_title="false")
self.check_webhook("note_hook__merge_request_note", expected_topic, expected_message)
def test_note_merge_request_with_custom_topic_in_url(self) -> None:

View File

@ -1045,7 +1045,8 @@ class ZulipRemoteUserBackend(RemoteUserBackend, ExternalAuthMethod):
auth_backend_name = "RemoteUser"
name = "remoteuser"
display_icon = None
sort_order = 9000 # If configured, this backend should have its button near the top of the list.
# If configured, this backend should have its button near the top of the list.
sort_order = 9000
create_unknown_user = False
@ -1199,7 +1200,8 @@ def social_associate_user_helper(backend: BaseAuth, return_data: Dict[str, Any],
# Some authentications methods like Apple and SAML send
# first name and last name as separate attributes. In that case
# we construct the full name from them.
return_data["full_name"] = f"{first_name or ''} {last_name or ''}".strip() # strip removes the unnecessary ' '
# strip removes the unnecessary ' '
return_data["full_name"] = f"{first_name or ''} {last_name or ''}".strip()
return user_profile

View File

@ -469,19 +469,24 @@ TWITTER_ACCESS_TOKEN_SECRET = get_secret("twitter_access_token_secret")
# These are the bots that Zulip sends automated messages as.
INTERNAL_BOTS = [{'var_name': 'NOTIFICATION_BOT',
'email_template': 'notification-bot@%s',
'name': 'Notification Bot'},
'name': 'Notification Bot',
},
{'var_name': 'EMAIL_GATEWAY_BOT',
'email_template': 'emailgateway@%s',
'name': 'Email Gateway'},
'name': 'Email Gateway',
},
{'var_name': 'NAGIOS_SEND_BOT',
'email_template': 'nagios-send-bot@%s',
'name': 'Nagios Send Bot'},
'name': 'Nagios Send Bot',
},
{'var_name': 'NAGIOS_RECEIVE_BOT',
'email_template': 'nagios-receive-bot@%s',
'name': 'Nagios Receive Bot'},
'name': 'Nagios Receive Bot',
},
{'var_name': 'WELCOME_BOT',
'email_template': 'welcome-bot@%s',
'name': 'Welcome Bot'}]
'name': 'Welcome Bot',
}]
# Bots that are created for each realm like the reminder-bot goes here.
REALM_INTERNAL_BOTS: List[Dict[str, str]] = []
@ -490,17 +495,20 @@ REALM_INTERNAL_BOTS: List[Dict[str, str]] = []
DISABLED_REALM_INTERNAL_BOTS = [
{'var_name': 'REMINDER_BOT',
'email_template': 'reminder-bot@%s',
'name': 'Reminder Bot'},
'name': 'Reminder Bot',
},
]
if PRODUCTION:
INTERNAL_BOTS += [
{'var_name': 'NAGIOS_STAGING_SEND_BOT',
'email_template': 'nagios-staging-send-bot@%s',
'name': 'Nagios Staging Send Bot'},
'name': 'Nagios Staging Send Bot',
},
{'var_name': 'NAGIOS_STAGING_RECEIVE_BOT',
'email_template': 'nagios-staging-receive-bot@%s',
'name': 'Nagios Staging Receive Bot'},
'name': 'Nagios Staging Receive Bot',
},
]
INTERNAL_BOT_DOMAIN = "zulip.com"