Skip to content

feat(users): add user archiving feature and update tests#1901

Open
Pwngo wants to merge 2 commits into
tjcsl:devfrom
Pwngo:feature/archive-users
Open

feat(users): add user archiving feature and update tests#1901
Pwngo wants to merge 2 commits into
tjcsl:devfrom
Pwngo:feature/archive-users

Conversation

@Pwngo

@Pwngo Pwngo commented May 12, 2026

Copy link
Copy Markdown

Proposed changes

  • Add user archiving as an admin action
  • Add a management command that takes a CSV of users as input
  • Add a parameter to this file that will archive users instead of deleting them

Brief description of rationale

Closes #1815

@Pwngo Pwngo requested a review from a team as a code owner May 12, 2026 22:03
@coveralls

coveralls commented May 12, 2026

Copy link
Copy Markdown

Coverage Status

coverage: 78.964% (-0.3%) from 79.252% — Pwngo:feature/archive-users into tjcsl:dev

@aarushtools aarushtools left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Ethan,

Thanks for the PR, you're off to a good start. In addition to my comments, does this PR do other things like removing archived users from search results? Remember it should function basically like a delete but without actually deleting the user.


def handle_archive(self, *, senior_grad_year: int):
users = get_user_model().objects.filter(graduation_year__lt=senior_grad_year).exclude(user_type="alum")
archived_count, already_archived_count = get_user_model().archive_users(users)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be a queryset method instead of a manager method, because the input is always a filtered collection

archived_count, already_archived_count = user_model.archive_users(users)
self.stdout.write(self.style.SUCCESS(f"Archived users: {archived_count}"))
if already_archived_count:
self.stdout.write(self.style.WARNING(f"Already archived users: {already_archived_count}"))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like what you're doing with the identifiers for filtering being derived from the CSV columns, but I think it's better if you hardcode it in to prevent anything bad from accidentally happening. Use username as the only column in the spreadsheet


@admin.register(User)
class UserAdmin(admin.ModelAdmin):
@admin.action(description="Archive selected users")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

Comment thread intranet/apps/users/models.py Outdated

return not self.username.startswith("INVALID_USER") and not self.user_locked

@classmethod

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docstrings (although it will be in a different place since I don't want this on the manager)

@Pwngo Pwngo force-pushed the feature/archive-users branch from 1e3e2e8 to d784cf4 Compare May 18, 2026 20:18
@Pwngo Pwngo requested a review from aarushtools May 18, 2026 20:27
@Pwngo

Pwngo commented May 18, 2026

Copy link
Copy Markdown
Author

Archiving sets user_locked=True on users, and search results are filtered to user.is_active only. is_active returns False when user_locked=True, so archived users are excluded from search results.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

User archival feature

3 participants