From 5e0cad0420154397659f9b97bdae5eacd007cb79 Mon Sep 17 00:00:00 2001
From: rine <k.schmid@liqd.net>
Date: Mon, 7 Nov 2022 11:39:37 +0100
Subject: [PATCH 1/2] tests/budgeting: add tests for ordering (default) filters
 in different phases

---
 .../budgeting/test_proposals_api_filtering.py | 107 ++++++++++++++++--
 tests/budgeting/test_views_integration.py     |  36 +++++-
 2 files changed, 129 insertions(+), 14 deletions(-)

diff --git a/tests/budgeting/test_proposals_api_filtering.py b/tests/budgeting/test_proposals_api_filtering.py
index 166a0ac852..2fbe356af4 100644
--- a/tests/budgeting/test_proposals_api_filtering.py
+++ b/tests/budgeting/test_proposals_api_filtering.py
@@ -1,3 +1,5 @@
+from datetime import timedelta
+
 import pytest
 from dateutil.parser import parse
 from django.urls import reverse
@@ -11,11 +13,19 @@
 
 
 @pytest.mark.django_db
-def test_proposal_list_mixins(apiclient, phase_factory, proposal_factory,
-                              category_factory, label_factory):
-    phase, module, project, proposal = setup_phase(phase_factory,
-                                                   proposal_factory,
-                                                   phases.SupportPhase)
+def test_proposal_list_filter_mixin(apiclient, phase_factory, proposal_factory,
+                                    category_factory, label_factory):
+    support_phase, module, project, proposal = setup_phase(phase_factory,
+                                                           proposal_factory,
+                                                           phases.SupportPhase)
+    voting_phase = phase_factory(
+        phase_content=phases.VotingPhase(),
+        module=module,
+        start_date=support_phase.end_date + timedelta(hours=2),
+        end_date=support_phase.end_date + timedelta(hours=3),
+    )
+    between_phases = support_phase.end_date + timedelta(hours=1)
+
     category1 = category_factory(module=module)
     category2 = category_factory(module=module)
 
@@ -63,7 +73,6 @@ def test_proposal_list_mixins(apiclient, phase_factory, proposal_factory,
     # with labels
     label1 = label_factory(module=module)
     label2 = label_factory(module=module)
-
     response = apiclient.get(url)
     assert 'filters' in response.data
     assert len(response.data['filters']) == 5
@@ -73,13 +82,33 @@ def test_proposal_list_mixins(apiclient, phase_factory, proposal_factory,
     assert (str(label2.pk), label2.name) in \
            response.data['filters']['labels']['choices']
 
-    with freeze_phase(phase):
+    # ordering choices and default in different phases
+    with freeze_phase(support_phase):
+        response = apiclient.get(url)
+    assert response.data['filters']['ordering']['choices'] == \
+           [('-created', _('Most recent')),
+            ('-positive_rating_count', _('Most support')),
+            ('-comment_count', _('Most commented')),
+            ('dailyrandom', _('Random'))]
+    assert response.data['filters']['ordering']['default'] == 'dailyrandom'
+
+    with freeze_time(between_phases):
         response = apiclient.get(url)
-        assert response.data['filters']['ordering']['choices'] == \
-               [('-created', _('Most recent')),
-                ('-positive_rating_count', _('Most support')),
-                ('-comment_count', _('Most commented')),
-                ('dailyrandom', _('Random'))]
+    assert response.data['filters']['ordering']['choices'] == \
+           [('-created', _('Most recent')),
+            ('-positive_rating_count', _('Most support')),
+            ('-comment_count', _('Most commented')),
+            ('dailyrandom', _('Random'))]
+    assert response.data['filters']['ordering']['default'] == \
+           '-positive_rating_count'
+
+    with freeze_phase(voting_phase):
+        response = apiclient.get(url)
+    assert response.data['filters']['ordering']['choices'] == \
+           [('-created', _('Most recent')),
+            ('-comment_count', _('Most commented')),
+            ('dailyrandom', _('Random'))]
+    assert response.data['filters']['ordering']['default'] == 'dailyrandom'
 
     phase_factory(phase_content=phases.RatingPhase(), module=module)
     response = apiclient.get(url)
@@ -408,6 +437,60 @@ def test_proposal_ordering_filter(
     assert ordered_pks == [8, 2, 4, 7, 6, 5, 1, 3]
 
 
+@pytest.mark.django_db
+def test_proposal_default_ordering_filter(
+        apiclient, module, phase_factory, proposal_factory,
+        rating_factory):
+
+    support_phase = phase_factory(
+        phase_content=phases.SupportPhase(),
+        module=module,
+        start_date=parse('2022-01-01 00:00:00 UTC'),
+        end_date=parse('2022-01-01 10:00:00 UTC'),
+    )
+    voting_phase = phase_factory(
+        phase_content=phases.VotingPhase(),
+        module=module,
+        start_date=parse('2022-01-01 14:00:00 UTC'),
+        end_date=parse('2022-01-01 18:00:00 UTC'),
+    )
+
+    between_phases = parse('2022-01-01 12:00:00 UTC')
+
+    url = reverse('proposals-list',
+                  kwargs={'module_pk': module.pk})
+
+    proposal_factory(pk=1,
+                     module=module)
+    proposal_2 = proposal_factory(pk=2,
+                                  module=module)
+    proposal_3 = proposal_factory(pk=3,
+                                  module=module)
+
+    rating_factory(content_object=proposal_2, value=1)
+    rating_factory(content_object=proposal_2, value=1)
+    rating_factory(content_object=proposal_3, value=1)
+
+    # dailyrandom is default during support
+    # dailyrandom order for '2022-01-01' is [2, 1, 3]
+    with freeze_phase(support_phase):
+        response = apiclient.get(url)
+    ordered_pks = [proposal['pk'] for proposal in response.data['results']]
+    assert ordered_pks == [2, 1, 3]
+
+    # support is default between support and voting phase
+    with freeze_time(between_phases):
+        response = apiclient.get(url)
+    ordered_pks = [proposal['pk'] for proposal in response.data['results']]
+    assert ordered_pks == [2, 3, 1]
+
+    # dailyrandom is default during voting
+    with freeze_phase(voting_phase):
+        response = apiclient.get(url)
+    ordered_pks = [proposal['pk'] for proposal in response.data['results']]
+    assert ordered_pks == [2, 1, 3]
+
+
 @pytest.mark.django_db
 def test_proposal_filter_combinations(
         apiclient, module, proposal_factory, category_factory,
diff --git a/tests/budgeting/test_views_integration.py b/tests/budgeting/test_views_integration.py
index fec45faf6b..0b4982562e 100644
--- a/tests/budgeting/test_views_integration.py
+++ b/tests/budgeting/test_views_integration.py
@@ -1,7 +1,7 @@
 import pytest
 from django.core import mail
 from django.urls import reverse
-from django.utils.translation import gettext
+from django.utils.translation import gettext_lazy as _
 
 from adhocracy4.test.helpers import assert_template_response
 from adhocracy4.test.helpers import freeze_phase
@@ -9,6 +9,7 @@
 from adhocracy4.test.helpers import setup_phase
 from meinberlin.apps.budgeting import models
 from meinberlin.apps.budgeting import phases
+from meinberlin.apps.budgeting import views
 
 
 @pytest.mark.django_db
@@ -22,6 +23,37 @@ def test_list_view(client, phase_factory, proposal_factory):
             response, 'meinberlin_budgeting/proposal_list.html')
 
 
+@pytest.mark.django_db
+def test_list_view_ordering_choices(client, phase_factory, proposal_factory):
+    phase, module, project, item = setup_phase(
+        phase_factory, proposal_factory, phases.RatingPhase)
+    url = project.get_absolute_url()
+    with freeze_phase(phase):
+        response = client.get(url)
+        view = response.context['view']
+        ordering_choices = views.get_ordering_choices(view)
+        assert ordering_choices == (
+            ('-created', _('Most recent')),
+            ('-positive_rating_count', _('Most popular')),
+            ('-comment_count', _('Most commented')),
+            ('dailyrandom', _('Random'))
+        )
+
+    phase, module, project, item = setup_phase(
+        phase_factory, proposal_factory, phases.SupportPhase)
+    url = project.get_absolute_url()
+    with freeze_phase(phase):
+        response = client.get(url)
+        view = response.context['view']
+        ordering_choices = views.get_ordering_choices(view)
+        assert ordering_choices == (
+            ('-created', _('Most recent')),
+            ('-positive_rating_count', _('Most support')),
+            ('-comment_count', _('Most commented')),
+            ('dailyrandom', _('Random'))
+        )
+
+
 @pytest.mark.django_db
 def test_list_view_token_form(client, user, phase_factory, proposal_factory,
                               voting_token_factory, module_factory):
@@ -63,7 +95,7 @@ def test_list_view_token_form(client, user, phase_factory, proposal_factory,
 
         response = client.post(url, data)
         assert 'token' in response.context_data['token_form'].errors
-        msg = gettext('This token is not valid')
+        msg = _('This token is not valid')
         assert msg in response.context_data['token_form'].errors['token']
         assert 'voting_token' not in client.session
 

From 85ed36b42314193edb674049fb56b475372096d9 Mon Sep 17 00:00:00 2001
From: rine <k.schmid@liqd.net>
Date: Mon, 7 Nov 2022 11:46:02 +0100
Subject: [PATCH 2/2] apps/budgeting//tests/budgeting: change rule view_support
 to consider different project accesses and test rules view_support and
 support_proposal

---
 meinberlin/apps/budgeting/predicates.py       |  23 ++-
 meinberlin/apps/budgeting/rules.py            |   2 +
 tests/budgeting/rules/test_rules_support.py   | 181 +++++++++++++++++
 .../rules/test_rules_view_support.py          | 182 ++++++++++++++++++
 4 files changed, 383 insertions(+), 5 deletions(-)
 create mode 100644 tests/budgeting/rules/test_rules_support.py
 create mode 100644 tests/budgeting/rules/test_rules_view_support.py

diff --git a/meinberlin/apps/budgeting/predicates.py b/meinberlin/apps/budgeting/predicates.py
index 19d05f82c9..8f50ba5ca1 100644
--- a/meinberlin/apps/budgeting/predicates.py
+++ b/meinberlin/apps/budgeting/predicates.py
@@ -1,8 +1,10 @@
 import rules
 from rules import predicates as rules_predicates
 
+from adhocracy4.modules.predicates import is_allowed_moderate_project
 from adhocracy4.modules.predicates import is_context_member
 from adhocracy4.modules.predicates import is_live_context
+from adhocracy4.modules.predicates import is_public_context
 from adhocracy4.modules.predicates import module_is_between_phases
 from adhocracy4.phases.predicates import has_feature_active
 from adhocracy4.phases.predicates import phase_allows_delete_vote
@@ -35,22 +37,33 @@ def phase_allows_support(user, item):
 @rules.predicate
 def is_allowed_support_item(user, item):
     if item:
-        return rules_predicates.is_superuser(user) | \
+        return is_allowed_moderate_project(user, item) | \
             (is_context_member(user, item) &
              is_live_context(user, item) &
              phase_allows_support(user, item))
     return False
 
 
+@rules.predicate
+def phase_allows_view_support(module, item_class):
+    if module:
+        return has_feature_active(module, item_class, 'support') | \
+            module_is_between_phases('meinberlin_budgeting:support',
+                                     'meinberlin_budgeting:voting',
+                                     module)
+    return False
+
+
 @rules.predicate
 def is_allowed_view_support(item_class):
     @rules.predicate
     def _view_support(user, module):
         if module:
-            return has_feature_active(module, item_class, 'support')\
-                | module_is_between_phases('meinberlin_budgeting:support',
-                                           'meinberlin_budgeting:voting',
-                                           module)
+            return is_allowed_moderate_project(user, module) | \
+                ((is_public_context(user, module) |
+                  is_context_member(user, module)) &
+                 is_live_context(user, module) &
+                 phase_allows_view_support(module, item_class))
         return False
 
     return _view_support
diff --git a/meinberlin/apps/budgeting/rules.py b/meinberlin/apps/budgeting/rules.py
index 51ed6e1908..f96b1c99dc 100644
--- a/meinberlin/apps/budgeting/rules.py
+++ b/meinberlin/apps/budgeting/rules.py
@@ -20,6 +20,8 @@
     module_predicates.is_allowed_add_item(models.Proposal)
 )
 
+# is_allowed_support_item is needed, because support also uses
+# the rating api which checks rate_proposal permission
 rules.add_perm(
     'meinberlin_budgeting.rate_proposal',
     module_predicates.is_allowed_rate_item | is_allowed_support_item
diff --git a/tests/budgeting/rules/test_rules_support.py b/tests/budgeting/rules/test_rules_support.py
new file mode 100644
index 0000000000..c555c03a58
--- /dev/null
+++ b/tests/budgeting/rules/test_rules_support.py
@@ -0,0 +1,181 @@
+from datetime import timedelta
+
+import pytest
+import rules
+from freezegun import freeze_time
+
+from adhocracy4.projects.enums import Access
+from adhocracy4.test.helpers import freeze_phase
+from adhocracy4.test.helpers import freeze_post_phase
+from adhocracy4.test.helpers import freeze_pre_phase
+from adhocracy4.test.helpers import setup_phase
+from adhocracy4.test.helpers import setup_users
+from meinberlin.apps.budgeting import phases
+
+perm_name = 'meinberlin_budgeting.support_proposal'
+
+
+def test_perm_exists():
+    assert rules.perm_exists(perm_name)
+
+
+@pytest.mark.django_db
+def test_pre_phase(phase_factory, proposal_factory, user, admin):
+    phase, module, project, item = setup_phase(phase_factory, proposal_factory,
+                                               phases.RequestPhase)
+    anonymous, moderator, initiator = setup_users(project)
+
+    assert project.access == Access.PUBLIC
+    with freeze_pre_phase(phase):
+        assert not rules.has_perm(perm_name, anonymous, item)
+        assert not rules.has_perm(perm_name, user, item)
+        assert rules.has_perm(perm_name, moderator, item)
+        assert rules.has_perm(perm_name, initiator, item)
+        assert rules.has_perm(perm_name, admin, item)
+
+
+@pytest.mark.django_db
+def test_support_phase_active(phase_factory, proposal_factory, user, admin):
+    phase, module, project, item = setup_phase(phase_factory, proposal_factory,
+                                               phases.SupportPhase)
+    anonymous, moderator, initiator = setup_users(project)
+
+    assert project.access == Access.PUBLIC
+    with freeze_phase(phase):
+        assert not rules.has_perm(perm_name, anonymous, item)
+        assert rules.has_perm(perm_name, user, item)
+        assert rules.has_perm(perm_name, moderator, item)
+        assert rules.has_perm(perm_name, initiator, item)
+        assert rules.has_perm(perm_name, admin, item)
+
+
+@pytest.mark.django_db
+def test_between_support_and_voting_phase(phase_factory, proposal_factory,
+                                          user, admin):
+    support_phase, module, project, item = setup_phase(phase_factory,
+                                                       proposal_factory,
+                                                       phases.SupportPhase)
+    phase_factory(
+        phase_content=phases.VotingPhase,
+        module=module,
+        start_date=support_phase.end_date + timedelta(hours=2),
+        end_date=support_phase.end_date + timedelta(hours=3),
+        type='meinberlin_budgeting:voting'
+    )
+    between_phases = support_phase.end_date + timedelta(hours=1)
+
+    anonymous, moderator, initiator = setup_users(project)
+
+    assert project.access == Access.PUBLIC
+    with freeze_time(between_phases):
+        assert not rules.has_perm(perm_name, anonymous, item)
+        assert not rules.has_perm(perm_name, user, item)
+        assert rules.has_perm(perm_name, moderator, item)
+        assert rules.has_perm(perm_name, initiator, item)
+        assert rules.has_perm(perm_name, admin, item)
+
+
+@pytest.mark.django_db
+def test_voting_phase_active(phase_factory, proposal_factory, user, admin):
+    phase, module, project, item = setup_phase(phase_factory, proposal_factory,
+                                               phases.VotingPhase)
+    anonymous, moderator, initiator = setup_users(project)
+
+    assert project.access == Access.PUBLIC
+    with freeze_phase(phase):
+        assert not rules.has_perm(perm_name, anonymous, item)
+        assert not rules.has_perm(perm_name, user, item)
+        assert rules.has_perm(perm_name, moderator, item)
+        assert rules.has_perm(perm_name, initiator, item)
+        assert rules.has_perm(perm_name, admin, item)
+
+
+@pytest.mark.django_db
+def test_rating_phase_active(phase_factory, proposal_factory, user, admin):
+    phase, module, project, item = setup_phase(phase_factory, proposal_factory,
+                                               phases.RatingPhase)
+    anonymous, moderator, initiator = setup_users(project)
+
+    assert project.access == Access.PUBLIC
+    with freeze_phase(phase):
+        assert not rules.has_perm(perm_name, anonymous, item)
+        assert not rules.has_perm(perm_name, user, item)
+        assert rules.has_perm(perm_name, moderator, item)
+        assert rules.has_perm(perm_name, initiator, item)
+        assert rules.has_perm(perm_name, admin, item)
+
+
+@pytest.mark.django_db
+def test_phase_active_project_private(phase_factory, proposal_factory,
+                                      user, user2, admin):
+    phase, _, project, item = setup_phase(
+        phase_factory, proposal_factory, phases.SupportPhase,
+        module__project__access=Access.PRIVATE)
+    anonymous, moderator, initiator = setup_users(project)
+
+    participant = user2
+    project.participants.add(participant)
+
+    assert project.access == Access.PRIVATE
+    with freeze_phase(phase):
+        assert not rules.has_perm(perm_name, anonymous, item)
+        assert not rules.has_perm(perm_name, user, item)
+        assert rules.has_perm(perm_name, participant, item)
+        assert rules.has_perm(perm_name, moderator, item)
+        assert rules.has_perm(perm_name, initiator, item)
+        assert rules.has_perm(perm_name, admin, item)
+
+
+@pytest.mark.django_db
+def test_phase_active_project_semipublic(phase_factory, proposal_factory,
+                                         user, user2, admin):
+    phase, _, project, item = setup_phase(
+        phase_factory, proposal_factory, phases.SupportPhase,
+        module__project__access=Access.SEMIPUBLIC)
+    anonymous, moderator, initiator = setup_users(project)
+
+    participant = user2
+    project.participants.add(participant)
+
+    assert project.access == Access.SEMIPUBLIC
+    with freeze_phase(phase):
+        assert not rules.has_perm(perm_name, anonymous, item)
+        assert not rules.has_perm(perm_name, user, item)
+        assert rules.has_perm(perm_name, participant, item)
+        assert rules.has_perm(perm_name, moderator, item)
+        assert rules.has_perm(perm_name, initiator, item)
+        assert rules.has_perm(perm_name, admin, item)
+
+
+@pytest.mark.django_db
+def test_phase_active_project_draft(phase_factory, proposal_factory,
+                                    user, admin):
+    phase, _, project, item = setup_phase(phase_factory, proposal_factory,
+                                          phases.SupportPhase,
+                                          module__project__is_draft=True)
+    anonymous, moderator, initiator = setup_users(project)
+
+    assert project.is_draft
+    with freeze_phase(phase):
+        assert not rules.has_perm(perm_name, anonymous, item)
+        assert not rules.has_perm(perm_name, user, item)
+        assert rules.has_perm(perm_name, moderator, item)
+        assert rules.has_perm(perm_name, initiator, item)
+        assert rules.has_perm(perm_name, admin, item)
+
+
+@pytest.mark.django_db
+def test_post_phase_project_archived(phase_factory, proposal_factory,
+                                     user, admin):
+    phase, _, project, item = setup_phase(phase_factory, proposal_factory,
+                                          phases.SupportPhase,
+                                          module__project__is_archived=True)
+    anonymous, moderator, initiator = setup_users(project)
+
+    assert project.is_archived
+    with freeze_post_phase(phase):
+        assert not rules.has_perm(perm_name, anonymous, item)
+        assert not rules.has_perm(perm_name, user, item)
+        assert rules.has_perm(perm_name, moderator, item)
+        assert rules.has_perm(perm_name, initiator, item)
+        assert rules.has_perm(perm_name, admin, item)
diff --git a/tests/budgeting/rules/test_rules_view_support.py b/tests/budgeting/rules/test_rules_view_support.py
new file mode 100644
index 0000000000..89903bac69
--- /dev/null
+++ b/tests/budgeting/rules/test_rules_view_support.py
@@ -0,0 +1,182 @@
+from datetime import timedelta
+
+import pytest
+import rules
+from freezegun import freeze_time
+
+from adhocracy4.projects.enums import Access
+from adhocracy4.test.helpers import freeze_phase
+from adhocracy4.test.helpers import freeze_post_phase
+from adhocracy4.test.helpers import freeze_pre_phase
+from adhocracy4.test.helpers import setup_phase
+from adhocracy4.test.helpers import setup_users
+from meinberlin.apps.budgeting import phases
+
+perm_name = 'meinberlin_budgeting.view_support'
+
+
+def test_perm_exists():
+    assert rules.perm_exists(perm_name)
+
+
+@pytest.mark.django_db
+def test_pre_phase(phase_factory, proposal_factory, user, admin):
+    phase, module, project, item = setup_phase(phase_factory, proposal_factory,
+                                               phases.CollectPhase)
+    anonymous, moderator, initiator = setup_users(project)
+
+    assert project.is_public
+    with freeze_pre_phase(phase):
+        assert not rules.has_perm(perm_name, anonymous, module)
+        assert not rules.has_perm(perm_name, user, module)
+        assert rules.has_perm(perm_name, moderator, module)
+        assert rules.has_perm(perm_name, initiator, module)
+        assert rules.has_perm(perm_name, admin, module)
+
+
+@pytest.mark.django_db
+def test_support_phase_active(phase_factory, proposal_factory, user, admin):
+    phase, module, project, item = setup_phase(phase_factory, proposal_factory,
+                                               phases.SupportPhase)
+    anonymous, moderator, initiator = setup_users(project)
+
+    assert project.is_public
+    with freeze_phase(phase):
+        assert rules.has_perm(perm_name, anonymous, module)
+        assert rules.has_perm(perm_name, user, module)
+        assert rules.has_perm(perm_name, moderator, module)
+        assert rules.has_perm(perm_name, initiator, module)
+        assert rules.has_perm(perm_name, admin, module)
+
+
+@pytest.mark.django_db
+def test_between_support_and_voting_phase(phase_factory, proposal_factory,
+                                          user, admin):
+    support_phase, module, project, item = setup_phase(phase_factory,
+                                                       proposal_factory,
+                                                       phases.SupportPhase)
+    phase_factory(
+        phase_content=phases.VotingPhase,
+        module=module,
+        start_date=support_phase.end_date + timedelta(hours=2),
+        end_date=support_phase.end_date + timedelta(hours=3),
+        type='meinberlin_budgeting:voting'
+    )
+    between_phases = support_phase.end_date + timedelta(hours=1)
+
+    anonymous, moderator, initiator = setup_users(project)
+
+    assert project.is_public
+    with freeze_time(between_phases):
+        assert rules.has_perm(perm_name, anonymous, module)
+        assert rules.has_perm(perm_name, user, module)
+        assert rules.has_perm(perm_name, moderator, module)
+        assert rules.has_perm(perm_name, initiator, module)
+        assert rules.has_perm(perm_name, admin, module)
+
+
+@pytest.mark.django_db
+def test_voting_phase_active(phase_factory, proposal_factory, user, admin):
+    phase, module, project, item = setup_phase(phase_factory, proposal_factory,
+                                               phases.VotingPhase)
+    anonymous, moderator, initiator = setup_users(project)
+
+    assert project.is_public
+    with freeze_phase(phase):
+        assert not rules.has_perm(perm_name, anonymous, module)
+        assert not rules.has_perm(perm_name, user, module)
+        assert rules.has_perm(perm_name, moderator, module)
+        assert rules.has_perm(perm_name, initiator, module)
+        assert rules.has_perm(perm_name, admin, module)
+
+
+@pytest.mark.django_db
+def test_rating_phase_active(phase_factory, proposal_factory, user, admin):
+    phase, module, project, item = setup_phase(phase_factory, proposal_factory,
+                                               phases.RatingPhase)
+    anonymous, moderator, initiator = setup_users(project)
+
+    assert project.is_public
+    with freeze_phase(phase):
+        assert not rules.has_perm(perm_name, anonymous, module)
+        assert not rules.has_perm(perm_name, user, module)
+        assert rules.has_perm(perm_name, moderator, module)
+        assert rules.has_perm(perm_name, initiator, module)
+        assert rules.has_perm(perm_name, admin, module)
+
+
+@pytest.mark.django_db
+def test_phase_active_project_private(phase_factory, proposal_factory,
+                                      user, user2, admin):
+    phase, module, project, item = setup_phase(
+        phase_factory, proposal_factory, phases.SupportPhase,
+        module__project__access=Access.PRIVATE)
+    anonymous, moderator, initiator = setup_users(project)
+
+    participant = user2
+    project.participants.add(participant)
+
+    assert project.access == Access.PRIVATE
+    with freeze_phase(phase):
+        assert not rules.has_perm(perm_name, anonymous, module)
+        assert not rules.has_perm(perm_name, user, module)
+        assert rules.has_perm(perm_name, participant, module)
+        assert rules.has_perm(perm_name, moderator, module)
+        assert rules.has_perm(perm_name, initiator, module)
+        assert rules.has_perm(perm_name, admin, module)
+
+
+@pytest.mark.django_db
+def test_phase_active_project_semipublic(phase_factory, proposal_factory,
+                                         user, user2, admin):
+    phase, module, project, item = setup_phase(
+        phase_factory, proposal_factory, phases.SupportPhase,
+        module__project__access=Access.SEMIPUBLIC)
+    anonymous, moderator, initiator = setup_users(project)
+
+    participant = user2
+    project.participants.add(participant)
+
+    assert project.access == Access.SEMIPUBLIC
+    with freeze_phase(phase):
+        assert rules.has_perm(perm_name, anonymous, module)
+        assert rules.has_perm(perm_name, user, module)
+        assert rules.has_perm(perm_name, participant, module)
+        assert rules.has_perm(perm_name, moderator, module)
+        assert rules.has_perm(perm_name, initiator, module)
+        assert rules.has_perm(perm_name, admin, module)
+
+
+@pytest.mark.django_db
+def test_phase_active_project_draft(phase_factory, proposal_factory, user,
+                                    admin):
+    phase, module, project, item = setup_phase(phase_factory, proposal_factory,
+                                               phases.SupportPhase,
+                                               module__project__is_draft=True)
+    anonymous, moderator, initiator = setup_users(project)
+
+    assert project.is_draft
+    with freeze_phase(phase):
+        assert not rules.has_perm(perm_name, anonymous, module)
+        assert not rules.has_perm(perm_name, user, module)
+        assert rules.has_perm(perm_name, moderator, module)
+        assert rules.has_perm(perm_name, initiator, module)
+        assert rules.has_perm(perm_name, admin, module)
+
+
+@pytest.mark.django_db
+def test_post_phase_project_archived(phase_factory, proposal_factory, user,
+                                     admin):
+    phase, module, project, item = setup_phase(
+        phase_factory, proposal_factory,
+        phases.SupportPhase,
+        module__project__is_archived=True)
+    anonymous, moderator, initiator = setup_users(project)
+
+    assert project.is_archived
+    with freeze_post_phase(phase):
+        assert not rules.has_perm(perm_name, anonymous, module)
+        assert not rules.has_perm(perm_name, user, module)
+        assert rules.has_perm(perm_name, moderator, module)
+        assert rules.has_perm(perm_name, initiator, module)
+        assert rules.has_perm(perm_name, admin, module)