mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			72 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			72 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
from django.db import connection, migrations
 | 
						|
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
 | 
						|
from django.db.migrations.state import StateApps
 | 
						|
 | 
						|
 | 
						|
def fill_new_columns(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None:
 | 
						|
    UserPresence = apps.get_model("zerver", "UserPresence")
 | 
						|
 | 
						|
    # In theory, we'd like to preserve the distinction between the
 | 
						|
    # IDLE and ACTIVE statuses in legacy data.  However, there is no
 | 
						|
    # correct way to do so; the previous data structure only stored
 | 
						|
    # the current IDLE/ACTIVE status of the last update for each
 | 
						|
    # (user, client) pair. There's no way to know whether the last
 | 
						|
    # time the user had the other status with that client was minutes
 | 
						|
    # or months beforehand.
 | 
						|
    #
 | 
						|
    # So the only sane thing we can do with this migration is to treat
 | 
						|
    # the last presence update as having been a PRESENCE_ACTIVE_STATUS
 | 
						|
    # event. This will result in some currently-idle users being
 | 
						|
    # incorrectly recorded as having been active at the last moment
 | 
						|
    # that they were idle before this migration.  This error is
 | 
						|
    # unlikely to be significant in practice, and in any case is an
 | 
						|
    # unavoidable flaw caused by the legacy previous data model.
 | 
						|
    with connection.cursor() as cursor:
 | 
						|
        cursor.execute(
 | 
						|
            "SELECT realm_id, user_profile_id, MAX(timestamp) FROM zerver_userpresenceold WHERE status IN (1, 2) GROUP BY realm_id, user_profile_id"
 | 
						|
        )
 | 
						|
        latest_presence_per_user = cursor.fetchall()
 | 
						|
 | 
						|
    UserPresence.objects.bulk_create(
 | 
						|
        [
 | 
						|
            UserPresence(
 | 
						|
                user_profile_id=presence_row[1],
 | 
						|
                realm_id=presence_row[0],
 | 
						|
                last_connected_time=presence_row[2],
 | 
						|
                last_active_time=presence_row[2],
 | 
						|
            )
 | 
						|
            for presence_row in latest_presence_per_user
 | 
						|
        ],
 | 
						|
        # Limit the size of individual network requests for very large
 | 
						|
        # servers.
 | 
						|
        batch_size=10000,
 | 
						|
        # If the UserPresence worker has already started, or a user
 | 
						|
        # has changed their invisible status while migrations are
 | 
						|
        # running, then some UserPresence rows may exist. Those will
 | 
						|
        # generally be newer than what we have here, so ignoring
 | 
						|
        # conflicts so we can complete backfilling users who don't
 | 
						|
        # have more current data is the right resolution.
 | 
						|
        ignore_conflicts=True,
 | 
						|
    )
 | 
						|
 | 
						|
 | 
						|
def clear_new_columns(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None:
 | 
						|
    UserPresence = apps.get_model("zerver", "UserPresence")
 | 
						|
    UserPresence.objects.all().delete()
 | 
						|
 | 
						|
 | 
						|
class Migration(migrations.Migration):
 | 
						|
    """
 | 
						|
    Ports data from the UserPresence model into the new one.
 | 
						|
    """
 | 
						|
 | 
						|
    atomic = False
 | 
						|
 | 
						|
    dependencies = [
 | 
						|
        ("zerver", "0443_userpresence_new_table_schema"),
 | 
						|
    ]
 | 
						|
 | 
						|
    operations = [
 | 
						|
        migrations.RunPython(fill_new_columns, reverse_code=clear_new_columns, elidable=True)
 | 
						|
    ]
 |