mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	export: Support export of Custom emojis.
Export of RealmEmoji should also include the image file of those emojis. Here, we export emojis both for local and S3 backend in a method with is similar to attachments and avatars. Added tests for the same.
This commit is contained in:
		@@ -840,8 +840,9 @@ def write_message_partial_for_query(realm: Realm, message_query: Any, dump_file_
 | 
			
		||||
def export_uploads_and_avatars(realm: Realm, output_dir: Path) -> None:
 | 
			
		||||
    uploads_output_dir = os.path.join(output_dir, 'uploads')
 | 
			
		||||
    avatars_output_dir = os.path.join(output_dir, 'avatars')
 | 
			
		||||
    emoji_output_dir = os.path.join(output_dir, 'emoji')
 | 
			
		||||
 | 
			
		||||
    for output_dir in (uploads_output_dir, avatars_output_dir):
 | 
			
		||||
    for output_dir in (uploads_output_dir, avatars_output_dir, emoji_output_dir):
 | 
			
		||||
        if not os.path.exists(output_dir):
 | 
			
		||||
            os.makedirs(output_dir)
 | 
			
		||||
 | 
			
		||||
@@ -853,6 +854,9 @@ def export_uploads_and_avatars(realm: Realm, output_dir: Path) -> None:
 | 
			
		||||
        export_avatars_from_local(realm,
 | 
			
		||||
                                  local_dir=os.path.join(settings.LOCAL_UPLOADS_DIR, "avatars"),
 | 
			
		||||
                                  output_dir=avatars_output_dir)
 | 
			
		||||
        export_emoji_from_local(realm,
 | 
			
		||||
                                local_dir=os.path.join(settings.LOCAL_UPLOADS_DIR, "avatars"),
 | 
			
		||||
                                output_dir=emoji_output_dir)
 | 
			
		||||
    else:
 | 
			
		||||
        # Some bigger installations will have their data stored on S3.
 | 
			
		||||
        export_files_from_s3(realm,
 | 
			
		||||
@@ -862,9 +866,14 @@ def export_uploads_and_avatars(realm: Realm, output_dir: Path) -> None:
 | 
			
		||||
        export_files_from_s3(realm,
 | 
			
		||||
                             settings.S3_AUTH_UPLOADS_BUCKET,
 | 
			
		||||
                             output_dir=uploads_output_dir)
 | 
			
		||||
        export_files_from_s3(realm,
 | 
			
		||||
                             settings.S3_AVATAR_BUCKET,
 | 
			
		||||
                             output_dir=emoji_output_dir,
 | 
			
		||||
                             processing_emoji=True)
 | 
			
		||||
 | 
			
		||||
def export_files_from_s3(realm: Realm, bucket_name: str, output_dir: Path,
 | 
			
		||||
                         processing_avatars: bool=False) -> None:
 | 
			
		||||
                         processing_avatars: bool=False,
 | 
			
		||||
                         processing_emoji: bool=False) -> None:
 | 
			
		||||
    conn = S3Connection(settings.S3_KEY, settings.S3_SECRET_KEY)
 | 
			
		||||
    bucket = conn.get_bucket(bucket_name, validate=True)
 | 
			
		||||
    records = []
 | 
			
		||||
@@ -880,6 +889,8 @@ def export_files_from_s3(realm: Realm, bucket_name: str, output_dir: Path,
 | 
			
		||||
            avatar_hash_values.add(avatar_path)
 | 
			
		||||
            avatar_hash_values.add(avatar_path + ".original")
 | 
			
		||||
            user_ids.add(user_profile.id)
 | 
			
		||||
    if processing_emoji:
 | 
			
		||||
        bucket_list = bucket.list(prefix="%s/emoji/images/" % (realm.id,))
 | 
			
		||||
    else:
 | 
			
		||||
        bucket_list = bucket.list(prefix="%s/" % (realm.id,))
 | 
			
		||||
 | 
			
		||||
@@ -919,7 +930,7 @@ def export_files_from_s3(realm: Realm, bucket_name: str, output_dir: Path,
 | 
			
		||||
            record['realm_id'] = user_profile.realm_id
 | 
			
		||||
        record['user_profile_email'] = user_profile.email
 | 
			
		||||
 | 
			
		||||
        if processing_avatars:
 | 
			
		||||
        if processing_avatars or processing_emoji:
 | 
			
		||||
            filename = os.path.join(output_dir, key.name)
 | 
			
		||||
            record['path'] = key.name
 | 
			
		||||
        else:
 | 
			
		||||
@@ -1014,6 +1025,34 @@ def export_avatars_from_local(realm: Realm, local_dir: Path, output_dir: Path) -
 | 
			
		||||
    with open(os.path.join(output_dir, "records.json"), "w") as records_file:
 | 
			
		||||
        ujson.dump(records, records_file, indent=4)
 | 
			
		||||
 | 
			
		||||
def export_emoji_from_local(realm: Realm, local_dir: Path, output_dir: Path) -> None:
 | 
			
		||||
 | 
			
		||||
    count = 0
 | 
			
		||||
    records = []
 | 
			
		||||
    for realm_emoji in RealmEmoji.objects.filter(realm_id=realm.id):
 | 
			
		||||
        emoji_path = RealmEmoji.PATH_ID_TEMPLATE.format(
 | 
			
		||||
            realm_id=realm.id,
 | 
			
		||||
            emoji_file_name=realm_emoji.file_name
 | 
			
		||||
        )
 | 
			
		||||
        local_path = os.path.join(local_dir, emoji_path)
 | 
			
		||||
        output_path = os.path.join(output_dir, emoji_path)
 | 
			
		||||
        os.makedirs(os.path.dirname(output_path), exist_ok=True)
 | 
			
		||||
        subprocess.check_call(["cp", "-a", local_path, output_path])
 | 
			
		||||
        record = dict(realm_id=realm.id,
 | 
			
		||||
                      author=realm_emoji.author.id,
 | 
			
		||||
                      path=emoji_path,
 | 
			
		||||
                      s3_path=emoji_path,
 | 
			
		||||
                      file_name=realm_emoji.file_name,
 | 
			
		||||
                      name=realm_emoji.name,
 | 
			
		||||
                      deactivated=realm_emoji.deactivated)
 | 
			
		||||
        records.append(record)
 | 
			
		||||
 | 
			
		||||
        count += 1
 | 
			
		||||
        if (count % 100 == 0):
 | 
			
		||||
            logging.info("Finished %s" % (count,))
 | 
			
		||||
    with open(os.path.join(output_dir, "records.json"), "w") as records_file:
 | 
			
		||||
        ujson.dump(records, records_file, indent=4)
 | 
			
		||||
 | 
			
		||||
def do_write_stats_file_for_realm_export(output_dir: Path) -> None:
 | 
			
		||||
    stats_file = os.path.join(output_dir, 'stats.txt')
 | 
			
		||||
    realm_file = os.path.join(output_dir, 'realm.json')
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,7 @@ from zerver.lib.export import (
 | 
			
		||||
from zerver.lib.upload import (
 | 
			
		||||
    claim_attachment,
 | 
			
		||||
    upload_message_file,
 | 
			
		||||
    upload_emoji_image,
 | 
			
		||||
)
 | 
			
		||||
from zerver.lib.utils import (
 | 
			
		||||
    query_chunker,
 | 
			
		||||
@@ -34,10 +35,15 @@ from zerver.lib.test_runner import slow
 | 
			
		||||
from zerver.models import (
 | 
			
		||||
    Message,
 | 
			
		||||
    Realm,
 | 
			
		||||
    RealmEmoji,
 | 
			
		||||
    Recipient,
 | 
			
		||||
    UserMessage,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
from zerver.lib.test_helpers import (
 | 
			
		||||
    get_test_image_file,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
def rm_tree(path: str) -> None:
 | 
			
		||||
    if os.path.exists(path):
 | 
			
		||||
        shutil.rmtree(path)
 | 
			
		||||
@@ -207,9 +213,10 @@ class ExportTest(ZulipTestCase):
 | 
			
		||||
        result['attachment'] = read_file('attachment.json')
 | 
			
		||||
        result['message'] = read_file('message.json')
 | 
			
		||||
        result['uploads_dir'] = os.path.join(output_dir, 'uploads')
 | 
			
		||||
        result['emoji_dir'] = os.path.join(output_dir, 'emoji')
 | 
			
		||||
        return result
 | 
			
		||||
 | 
			
		||||
    def test_attachment(self) -> None:
 | 
			
		||||
    def test_attachment_and_emoji(self) -> None:
 | 
			
		||||
        message = Message.objects.all()[0]
 | 
			
		||||
        user_profile = message.sender
 | 
			
		||||
        url = upload_message_file(u'dummy.txt', len(b'zulip!'), u'text/plain', b'zulip!', user_profile)
 | 
			
		||||
@@ -222,6 +229,9 @@ class ExportTest(ZulipTestCase):
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        realm = Realm.objects.get(string_id='zulip')
 | 
			
		||||
        with get_test_image_file('img.png') as img_file:
 | 
			
		||||
            upload_emoji_image(img_file, '1.png', user_profile)
 | 
			
		||||
 | 
			
		||||
        full_data = self._export_realm(realm)
 | 
			
		||||
 | 
			
		||||
        data = full_data['attachment']
 | 
			
		||||
@@ -233,9 +243,17 @@ class ExportTest(ZulipTestCase):
 | 
			
		||||
        with open(fn) as f:
 | 
			
		||||
            self.assertEqual(f.read(), 'zulip!')
 | 
			
		||||
 | 
			
		||||
        fn = os.path.join(full_data['emoji_dir'],
 | 
			
		||||
                          RealmEmoji.PATH_ID_TEMPLATE.format(realm_id=realm.id, emoji_file_name='1.png'))
 | 
			
		||||
        fn = fn.replace('1.png', '')
 | 
			
		||||
        self.assertEqual('1.png', os.listdir(fn)[0])
 | 
			
		||||
 | 
			
		||||
    def test_zulip_realm(self) -> None:
 | 
			
		||||
        realm = Realm.objects.get(string_id='zulip')
 | 
			
		||||
        realm_emoji = RealmEmoji.objects.get(realm=realm)
 | 
			
		||||
        realm_emoji.delete()
 | 
			
		||||
        full_data = self._export_realm(realm)
 | 
			
		||||
        realm_emoji.save()
 | 
			
		||||
 | 
			
		||||
        data = full_data['realm']
 | 
			
		||||
        self.assertEqual(len(data['zerver_userprofile_crossrealm']), 0)
 | 
			
		||||
@@ -278,7 +296,11 @@ class ExportTest(ZulipTestCase):
 | 
			
		||||
        hamlet = self.example_user('hamlet')
 | 
			
		||||
        user_ids = set([cordelia.id, hamlet.id])
 | 
			
		||||
 | 
			
		||||
        realm_emoji = RealmEmoji.objects.get(realm=realm)
 | 
			
		||||
        realm_emoji.delete()
 | 
			
		||||
        full_data = self._export_realm(realm, exportable_user_ids=user_ids)
 | 
			
		||||
        realm_emoji.save()
 | 
			
		||||
 | 
			
		||||
        data = full_data['realm']
 | 
			
		||||
        exported_user_emails = get_set('zerver_userprofile', 'email')
 | 
			
		||||
        self.assertIn(self.example_email('cordelia'), exported_user_emails)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user