snapshot of https://github.com/zulip/zulip.git @ 48c69911c7dd4e03b20552eb3bd77ad8151c1357 (2026-09-15)
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
This commit is contained in:
96
zerver/migrations/0509_fix_emoji_metadata.py
Normal file
96
zerver/migrations/0509_fix_emoji_metadata.py
Normal file
@@ -0,0 +1,96 @@
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
import boto3
|
||||
from botocore.client import Config
|
||||
from django.conf import settings
|
||||
from django.db import migrations
|
||||
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
||||
from django.db.migrations.state import StateApps
|
||||
from django.db.models import Exists, OuterRef
|
||||
|
||||
|
||||
def fix_emoji_metadata(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None:
|
||||
if settings.LOCAL_UPLOADS_DIR is not None:
|
||||
return
|
||||
|
||||
bucket = boto3.resource(
|
||||
"s3",
|
||||
aws_access_key_id=settings.S3_KEY,
|
||||
aws_secret_access_key=settings.S3_SECRET_KEY,
|
||||
region_name=settings.S3_REGION,
|
||||
endpoint_url=settings.S3_ENDPOINT_URL,
|
||||
config=Config(
|
||||
signature_version=None,
|
||||
s3={"addressing_style": settings.S3_ADDRESSING_STYLE},
|
||||
),
|
||||
).Bucket(settings.S3_AVATAR_BUCKET)
|
||||
|
||||
Realm = apps.get_model("zerver", "Realm")
|
||||
RealmEmoji = apps.get_model("zerver", "RealmEmoji")
|
||||
UserProfile = apps.get_model("zerver", "UserProfile")
|
||||
|
||||
for realm in Realm.objects.filter(
|
||||
Exists(RealmEmoji.objects.filter(realm_id=OuterRef("id")))
|
||||
).only("id"):
|
||||
fallback_owner = (
|
||||
UserProfile.objects.filter(realm=realm.id, is_bot=False, role=100, is_active=True)
|
||||
.order_by("id")
|
||||
.first()
|
||||
)
|
||||
assert fallback_owner is not None
|
||||
|
||||
emoji_by_filename: dict[str, Any] = {}
|
||||
for emoji in RealmEmoji.objects.filter(realm_id=realm.id).exclude(file_name=None):
|
||||
assert emoji.file_name is not None
|
||||
if emoji.author_id is None:
|
||||
emoji.author_id = fallback_owner.id
|
||||
emoji.save(update_fields=["author_id"])
|
||||
if emoji.file_name not in emoji_by_filename:
|
||||
# Slack imports may have multiple RealmEmoji rows for
|
||||
# the same file_name; we pick one arbitrarily
|
||||
emoji_by_filename[emoji.file_name] = emoji
|
||||
|
||||
for obj_summary in bucket.objects.filter(Prefix=f"{realm.id}/emoji/images/"):
|
||||
match = re.match(r"^\d+/emoji/images/(.+)$", obj_summary.key)
|
||||
assert match
|
||||
emoji_filename = match.group(1)
|
||||
if emoji_filename not in emoji_by_filename:
|
||||
continue
|
||||
emoji = emoji_by_filename[emoji_filename]
|
||||
assert emoji.author_id is not None
|
||||
|
||||
head = bucket.meta.client.head_object(Bucket=bucket.name, Key=obj_summary.key)
|
||||
metadata = head["Metadata"]
|
||||
changed = False
|
||||
if metadata.get("realm_id") is None:
|
||||
metadata["realm_id"] = str(realm.id)
|
||||
changed = True
|
||||
if metadata.get("user_profile_id") is None:
|
||||
metadata["user_profile_id"] = str(emoji.author_id)
|
||||
changed = True
|
||||
|
||||
if not changed:
|
||||
continue
|
||||
|
||||
assert not head.get("ContentDisposition")
|
||||
obj_summary.copy_from(
|
||||
ContentType=head["ContentType"],
|
||||
CopySource=f"{bucket.name}/{obj_summary.key}",
|
||||
Metadata=metadata,
|
||||
MetadataDirective="REPLACE",
|
||||
)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
atomic = False
|
||||
|
||||
dependencies = [
|
||||
("zerver", "0508_realmuserdefault_receives_typing_notifications_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(
|
||||
fix_emoji_metadata, reverse_code=migrations.RunPython.noop, elidable=True
|
||||
)
|
||||
]
|
||||
Reference in New Issue
Block a user