Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions moderator/moderate/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class EventAdmin(admin.ModelAdmin):
"created_at",
"event_date",
"archived",
"is_nda",
"allow_nda_community",
)
actions = [export_questions_csv]
date_hierarchy = "created_at"
Expand All @@ -89,7 +89,7 @@ class EventAdmin(admin.ModelAdmin):
"moderators__last_name",
]
ordering = ["-created_at"]
list_filter = ["archived", "is_nda"]
list_filter = ["archived", "allow_nda_community"]
autocomplete_fields = ["moderators"]


Expand Down
12 changes: 7 additions & 5 deletions moderator/moderate/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,9 @@ def __init__(self, *args, **kwargs):
if not self.user.userprofile.is_employee:
# An NDA community member would lose sight of their own event if it
# were not opted in to the NDA community.
self.fields["is_nda"].disabled = True
self.fields["is_nda"].initial = True
self.fields["is_nda"].help_text = (
self.fields["allow_nda_community"].disabled = True
self.fields["allow_nda_community"].initial = True
self.fields["allow_nda_community"].help_text = (
"Only staff can change who an event is open to."
)

Expand All @@ -159,7 +159,7 @@ class Meta:
model = Event
fields = [
"name",
"is_nda",
"allow_nda_community",
"body",
"is_moderated",
"moderators",
Expand All @@ -185,7 +185,9 @@ class Meta:
"placeholder": "Event date",
}
),
"is_nda": forms.CheckboxInput(attrs={"class": "form-check-input"}),
"allow_nda_community": forms.CheckboxInput(
attrs={"class": "form-check-input"}
),
"is_moderated": forms.CheckboxInput(attrs={"class": "form-check-input"}),
"users_can_vote": forms.CheckboxInput(attrs={"class": "form-check-input"}),
"archived": forms.CheckboxInput(attrs={"class": "form-check-input"}),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 5.2.13 on 2026-08-04 09:19
# Generated by Django 5.2.13 on 2026-08-11 10:38

from django.db import migrations, models

Expand Down
6 changes: 2 additions & 4 deletions moderator/moderate/migrations/0024_backfill_is_employee.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
from django.db import migrations
# Generated by Django 5.2.13 on 2026-08-11 10:38

# Kept separate from the schema migration: MySQL cannot roll DDL back, so a
# failure here would otherwise leave the column added and the migration
# unrecorded.
from django.db import migrations

# Staff domains that do not carry the "mozilla" substring.
EMPLOYEE_EMAIL_DOMAINS = frozenset({"thunderbird.net", "getpocket.com"})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from django.db import migrations
# Generated by Django 5.2.13 on 2026-08-11 10:38

# Dropping the old column is split out so it can be applied on a later deploy,
# once no instance is running code that still reads is_nda_member.
from django.db import migrations


class Migration(migrations.Migration):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.2.13 on 2026-08-11 10:38

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
("moderate", "0025_remove_mozillianprofile_is_nda_member"),
]

operations = [
migrations.RenameField(
model_name="event",
old_name="is_nda",
new_name="allow_nda_community",
),
]
5 changes: 3 additions & 2 deletions moderator/moderate/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ def visible_to(self, user):
# A subquery rather than a join on moderators: joining would duplicate
# rows and inflate the Count() annotations the listing views add.
return self.filter(
models.Q(is_nda=True) | models.Q(pk__in=user.events_moderated.values("pk"))
models.Q(allow_nda_community=True)
| models.Q(pk__in=user.events_moderated.values("pk"))
)


Expand All @@ -91,7 +92,7 @@ class Event(models.Model):
slug = models.SlugField(max_length=400, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
event_date = models.DateField(null=True, blank=True, default=default_date)
is_nda = models.BooleanField(default=False)
allow_nda_community = models.BooleanField(default=False)
created_by = models.ForeignKey(
User, null=True, blank=True, on_delete=models.SET_NULL
)
Expand Down
4 changes: 2 additions & 2 deletions moderator/moderate/templates/create_event.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@
{{ floating(event_form.event_date, "Event date") }}
{% if user_can_edit %}
{{ check(event_form.users_can_vote, "Allow users to vote on questions") }}
{{ check(event_form.is_nda,
{{ check(event_form.allow_nda_community,
'Allow <a target="_blank" href="https://people.mozilla.org/a/nda">NDA Community members</a>',
help=event_form.is_nda.help_text) }}
help=event_form.allow_nda_community.help_text) }}
{{ check(event_form.is_moderated, "Moderated event (questions need approval)") }}
{% if event %}
{{ check(event_form.archived, "Archive this event") }}
Expand Down
2 changes: 1 addition & 1 deletion moderator/moderate/templates/questions.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
{{ event.event_date|date('F j, Y') }}
</time>
{% endif %}
{% if event.is_nda %}<span class="badge bg-success-subtle text-success-emphasis">NDA Community</span>{% endif %}
{% if event.allow_nda_community %}<span class="badge bg-success-subtle text-success-emphasis">Open to NDA Community</span>{% endif %}
{% if event.is_moderated %}<span class="badge bg-info-subtle text-info-emphasis">Moderated</span>{% endif %}
{% if event.archived %}<span class="badge bg-secondary-subtle text-secondary-emphasis">Archived</span>{% endif %}
</div>
Expand Down
24 changes: 13 additions & 11 deletions moderator/moderate/tests/test_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,59 +34,61 @@ def test_question_form_accepts_valid_text():
def test_event_form_forces_nda_for_community_member(make_user):
"""A community member would lose sight of an event that is not opted in."""
user = make_user("contributor")
form = EventForm(_event_data(user, is_nda=False), user=user)
form = EventForm(_event_data(user, allow_nda_community=False), user=user)
assert form.is_valid(), form.errors
assert form.save().is_nda is True
assert form.save().allow_nda_community is True


@pytest.mark.django_db
def test_event_form_forces_nda_when_community_member_omits_the_field(make_user):
user = make_user("contributor")
form = EventForm(_event_data(user), user=user)
assert form.is_valid(), form.errors
assert form.save().is_nda is True
assert form.save().allow_nda_community is True


@pytest.mark.django_db
def test_event_form_lets_employee_opt_out(make_user):
user = make_user("staff", is_employee=True)
form = EventForm(_event_data(user, is_nda=False), user=user)
form = EventForm(_event_data(user, allow_nda_community=False), user=user)
assert form.is_valid(), form.errors
assert form.save().is_nda is False
assert form.save().allow_nda_community is False


@pytest.mark.django_db
def test_event_form_lets_employee_opt_in(make_user):
user = make_user("staff", is_employee=True)
form = EventForm(_event_data(user, is_nda=True), user=user)
form = EventForm(_event_data(user, allow_nda_community=True), user=user)
assert form.is_valid(), form.errors
assert form.save().is_nda is True
assert form.save().allow_nda_community is True


@pytest.mark.django_db
def test_event_form_community_moderator_cannot_change_existing_value(make_user):
staff = make_user("staff", is_employee=True)
contributor = make_user("contributor")
event = Event.objects.create(name="Staff only", is_nda=False, created_by=staff)
event = Event.objects.create(
name="Staff only", allow_nda_community=False, created_by=staff
)
event.moderators.set([staff, contributor])

form = EventForm(
_event_data(
contributor,
name="Staff only",
moderators=[staff.pk, contributor.pk],
is_nda=True,
allow_nda_community=True,
),
instance=event,
user=contributor,
)
assert form.is_valid(), form.errors
assert form.save().is_nda is False
assert form.save().allow_nda_community is False


@pytest.mark.django_db
def test_event_form_no_longer_blocks_community_member_from_nda_events(make_user):
"""The old "only NDA members can create NDA events" rule is gone."""
user = make_user("contributor")
form = EventForm(_event_data(user, is_nda=True), user=user)
form = EventForm(_event_data(user, allow_nda_community=True), user=user)
assert form.is_valid(), form.errors
12 changes: 6 additions & 6 deletions moderator/moderate/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ def test_event_questions_count_property():
@pytest.mark.django_db
def test_visible_to_returns_opted_in_and_moderated_events(make_user):
contributor = make_user("contributor")
community = Event.objects.create(name="Community", is_nda=True)
moderated = Event.objects.create(name="Moderated", is_nda=False)
community = Event.objects.create(name="Community", allow_nda_community=True)
moderated = Event.objects.create(name="Moderated", allow_nda_community=False)
moderated.moderators.set([contributor])
Event.objects.create(name="Staff Only", is_nda=False)
Event.objects.create(name="Staff Only", allow_nda_community=False)

visible = Event.objects.visible_to(contributor)
assert set(visible.values_list("name", flat=True)) == {"Community", "Moderated"}
Expand All @@ -89,8 +89,8 @@ def test_visible_to_returns_opted_in_and_moderated_events(make_user):

@pytest.mark.django_db
def test_visible_to_returns_everything_for_employees_and_superusers(make_user):
Event.objects.create(name="Staff Only", is_nda=False)
Event.objects.create(name="Community", is_nda=True)
Event.objects.create(name="Staff Only", allow_nda_community=False)
Event.objects.create(name="Community", allow_nda_community=True)

for user in [
make_user("staff", is_employee=True),
Expand All @@ -103,7 +103,7 @@ def test_visible_to_returns_everything_for_employees_and_superusers(make_user):
def test_visible_to_does_not_inflate_annotations(make_user):
"""The moderator clause must not join and double the Count() annotations."""
contributor = make_user("contributor")
event = Event.objects.create(name="Staff Only", is_nda=False)
event = Event.objects.create(name="Staff Only", allow_nda_community=False)
event.moderators.set([contributor, make_user("staff", is_employee=True)])
for i in range(3):
Question.objects.create(
Expand Down
8 changes: 5 additions & 3 deletions moderator/moderate/tests/test_urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,10 @@ def test_archive_event_rejects_future_event():

def _make_events(archived=False):
staff_only = Event.objects.create(
name="Staff Only Event", is_nda=False, archived=archived
name="Staff Only Event", allow_nda_community=False, archived=archived
)
community = Event.objects.create(
name="Community Welcome Event", is_nda=True, archived=archived
name="Community Welcome Event", allow_nda_community=True, archived=archived
)
return staff_only, community

Expand Down Expand Up @@ -341,7 +341,9 @@ def test_upvote_404s_for_non_numeric_question_id(make_user):
@pytest.mark.django_db
def test_upvote_respects_voting_switch_on_nda_event(make_user):
"""Opting an event in to the NDA community must not re-enable voting."""
event = Event.objects.create(name="No Voting", is_nda=True, users_can_vote=False)
event = Event.objects.create(
name="No Voting", allow_nda_community=True, users_can_vote=False
)
question = Question.objects.create(
event=event, question="A question with enough text.", is_accepted=True
)
Expand Down
Loading