Customize Profile Pic (#1876) (#1994)

This commit is contained in:
daveoconnor
2025-11-04 12:08:20 -08:00
committed by GitHub
parent c8eb4ff375
commit 8cdb57b08c
7 changed files with 108 additions and 7 deletions

View File

@@ -15,6 +15,7 @@
- [`sync_mailinglist_stats`](#sync_mailinglist_stats)
- [`update_library_version_dependencies`](#update_library_version_dependencies)
- [`release_tasks`](#release_tasks)
- [`refresh_users_github_photos`](#refresh_users_github_photos)
## `boost_setup`
@@ -323,3 +324,35 @@ For this to work `SLACK_BOT_API` must be set in the `.env` file.
```bash
./manage.py link_contributors_to_users
```
## `refresh_users_github_photos`
**Purpose**: Refresh GitHub profile photos for all users who have a GitHub username. This command fetches the latest profile photo from GitHub for each user and updates their local profile image. This is useful for local dev/testing, isn't used for production where a periodic celery task is used.
**Example**
```bash
./manage.py refresh_users_github_photos
```
**Options**
| Options | Format | Description |
|--------------|--------|----------------------------------------------------------------------------------------------|
| `--dry-run` | bool | Show which users would be updated without actually updating them. Useful for testing. |
**Usage Examples**
Refresh photos for all users with GitHub usernames:
```bash
./manage.py refresh_users_github_photos
```
Preview which users would be updated:
```bash
./manage.py refresh_users_github_photos --dry-run
```
**Process**
- Calls the `refresh_users_github_photos()` Celery task which queues photo updates for all users with GitHub usernames
- With `--dry-run`, displays information about which users would be updated without making any changes

View File

@@ -140,10 +140,11 @@ class UserProfilePhotoForm(forms.ModelForm):
old_image = self.instance.image
# Save the new image
user = super().save(commit=False)
if old_image:
if not old_image:
# reset image on image delete checked
user.image_uploaded = False
elif self.cleaned_data["image"] != old_image:
# Delete the old image file if there's a new image being uploaded
if self.cleaned_data["image"] != old_image:
old_image.delete(save=False)
if self.cleaned_data.get("image"):
@@ -155,6 +156,7 @@ class UserProfilePhotoForm(forms.ModelForm):
new_image.name = f"{user.profile_image_filename_root}.{file_extension}"
user.image = new_image
user.image_uploaded = True
if commit:
user.save()

View File

@@ -0,0 +1,39 @@
import djclick as click
from django.contrib.auth import get_user_model
from users.tasks import refresh_users_github_photos
User = get_user_model()
@click.command()
@click.option(
"--dry-run",
is_flag=True,
help="Show which users would be updated without actually updating them",
default=False,
)
def command(dry_run):
"""Refresh GitHub photos for all users who have a GitHub username.
This command fetches the latest profile photo from GitHub for each user
and updates their local profile image. This is useful for keeping user
avatars up-to-date as users change their GitHub profile photos.
When run without --dry-run, this calls the refresh_users_github_photos()
Celery task which queues photo updates for all users with GitHub usernames.
With --dry-run, displays information about which users would be updated
without making any changes.
"""
users = User.objects.exclude(github_username="")
user_count = users.count()
if dry_run:
click.secho(f"Refreshing {user_count} users, Github users:", fg="yellow")
for user in users:
click.echo(f" - User {user.pk}: {user.github_username}")
else:
click.secho(f"Refreshing photos, {user_count} users", fg="green")
refresh_users_github_photos()
click.secho(f"Triggered photo refresh task, {user_count} users", fg="green")

View File

@@ -0,0 +1,21 @@
# Generated by Django 5.2.7 on 2025-10-31 22:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("users", "0018_user_is_commit_author_name_overridden"),
]
operations = [
migrations.AddField(
model_name="user",
name="image_uploaded",
field=models.BooleanField(
default=False,
help_text="Indicates if the user manually uploaded an image, prevents import overwrites",
),
),
]

View File

@@ -230,6 +230,10 @@ class User(BaseUser):
format="JPEG",
options={"quality": 90},
)
image_uploaded = models.BooleanField(
default=False,
help_text="Indicates if the user manually uploaded an image, prevents import overwrites",
)
claimed = models.BooleanField(
_("claimed"),
default=True,

View File

@@ -31,7 +31,7 @@ def import_social_profile_data(sender, instance, created, **kwargs):
elif instance.provider == GOOGLE:
avatar_url = instance.extra_data.get("picture")
if avatar_url:
if avatar_url and not instance.user.image_uploaded:
instance.user.save_image_from_provider(avatar_url)
instance.user.display_name = instance.extra_data.get("name")

View File

@@ -4,6 +4,7 @@ import structlog
from django.contrib.auth import get_user_model
from django.core.mail import send_mail
from django.db.models import Q
from django.utils import timezone
from django.conf import settings
@@ -47,10 +48,11 @@ def update_user_github_photo(user_pk):
@app.task
def refresh_users_github_photos():
"""
Refreshes the GitHub photos for all users who have a GitHub username.
Refreshes the GitHub photos for all users who have a GitHub username and haven't
uploaded an image manually.
This is intended to be run periodically to ensure user photos are up-to-date.
"""
users = User.objects.exclude(github_username="")
users = User.objects.exclude(Q(github_username="") | Q(image_uploaded=True))
for user in users:
try:
logger.info(f"updating {user.pk=}")