Skip to content
Snippets Groups Projects
Unverified Commit 3858f86b authored by Fredrik Jonsson's avatar Fredrik Jonsson Committed by GitHub
Browse files

Merge pull request #1127 from OpenTechFund/feature/new-workflow-request-community-review

Adding new workflow, SingleStageCommunityDefinition.
parents c069fdec f8291df3
No related branches found
No related tags found
No related merge requests found
# Generated by Django 2.0.10 on 2019-03-25 13:00
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('funds', '0058_add_group_toggle'),
]
operations = [
migrations.AlterField(
model_name='applicationbase',
name='workflow_name',
field=models.CharField(choices=[('single', 'Request'), ('single_ext', 'Request with external review'), ('single_com', 'Request with community review'), ('double', 'Concept & Proposal')], default='single', max_length=100, verbose_name='Workflow'),
),
migrations.AlterField(
model_name='applicationsubmission',
name='workflow_name',
field=models.CharField(choices=[('single', 'Request'), ('single_ext', 'Request with external review'), ('single_com', 'Request with community review'), ('double', 'Concept & Proposal')], default='single', max_length=100, verbose_name='Workflow'),
),
migrations.AlterField(
model_name='labbase',
name='workflow_name',
field=models.CharField(choices=[('single', 'Request'), ('single_ext', 'Request with external review'), ('single_com', 'Request with community review'), ('double', 'Concept & Proposal')], default='single', max_length=100, verbose_name='Workflow'),
),
migrations.AlterField(
model_name='roundbase',
name='workflow_name',
field=models.CharField(choices=[('single', 'Request'), ('single_ext', 'Request with external review'), ('single_com', 'Request with community review'), ('double', 'Concept & Proposal')], default='single', max_length=100, verbose_name='Workflow'),
),
]
...@@ -12,7 +12,7 @@ from wagtail.contrib.forms.models import AbstractEmailForm ...@@ -12,7 +12,7 @@ from wagtail.contrib.forms.models import AbstractEmailForm
from opentech.apply.activity.messaging import messenger, MESSAGES from opentech.apply.activity.messaging import messenger, MESSAGES
from opentech.apply.stream_forms.models import AbstractStreamForm from opentech.apply.stream_forms.models import AbstractStreamForm
from opentech.apply.users.groups import REVIEWER_GROUP_NAME, STAFF_GROUP_NAME, PARTNER_GROUP_NAME from opentech.apply.users.groups import REVIEWER_GROUP_NAME, STAFF_GROUP_NAME, PARTNER_GROUP_NAME, COMMUNITY_REVIEWER_GROUP_NAME
from ..workflow import WORKFLOWS from ..workflow import WORKFLOWS
...@@ -21,6 +21,7 @@ LIMIT_TO_STAFF = {'groups__name': STAFF_GROUP_NAME} ...@@ -21,6 +21,7 @@ LIMIT_TO_STAFF = {'groups__name': STAFF_GROUP_NAME}
LIMIT_TO_REVIEWERS = {'groups__name': REVIEWER_GROUP_NAME} LIMIT_TO_REVIEWERS = {'groups__name': REVIEWER_GROUP_NAME}
LIMIT_TO_STAFF_AND_REVIEWERS = {'groups__name__in': [STAFF_GROUP_NAME, REVIEWER_GROUP_NAME]} LIMIT_TO_STAFF_AND_REVIEWERS = {'groups__name__in': [STAFF_GROUP_NAME, REVIEWER_GROUP_NAME]}
LIMIT_TO_PARTNERS = {'groups__name': PARTNER_GROUP_NAME} LIMIT_TO_PARTNERS = {'groups__name': PARTNER_GROUP_NAME}
LIMIT_TO_COMMUNITY_REVIEWERS = {'groups__name': COMMUNITY_REVIEWER_GROUP_NAME}
def admin_url(page): def admin_url(page):
......
...@@ -70,6 +70,7 @@ class Phase: ...@@ -70,6 +70,7 @@ class Phase:
public_name = phase name displayed to applicants in the system public_name = phase name displayed to applicants in the system
future_name = phase_name displayed to applicants if they haven't passed this stage future_name = phase_name displayed to applicants if they haven't passed this stage
""" """
def __init__(self, name, display, stage, permissions, step, public=None, future=None, transitions=dict()): def __init__(self, name, display, stage, permissions, step, public=None, future=None, transitions=dict()):
self.name = name self.name = name
self.display_name = display self.display_name = display
...@@ -142,7 +143,9 @@ applicant_can = lambda user: user.is_applicant # NOQA ...@@ -142,7 +143,9 @@ applicant_can = lambda user: user.is_applicant # NOQA
reviewer_can = lambda user: user.is_reviewer # NOQA reviewer_can = lambda user: user.is_reviewer # NOQA
partner_can = lambda user: user.is_partner # NOQA partner_can = lambda user: user.is_partner # NOQA
community_can = lambda user: user.is_community_reviewer # NOQA
def make_permissions(edit=list(), review=list(), view=[staff_can, applicant_can, reviewer_can]): def make_permissions(edit=list(), review=list(), view=[staff_can, applicant_can, reviewer_can]):
...@@ -161,6 +164,8 @@ hidden_from_applicant_permissions = make_permissions(edit=[staff_can], review=[s ...@@ -161,6 +164,8 @@ hidden_from_applicant_permissions = make_permissions(edit=[staff_can], review=[s
reviewer_review_permissions = make_permissions(edit=[staff_can, partner_can], review=[staff_can, reviewer_can, partner_can]) reviewer_review_permissions = make_permissions(edit=[staff_can, partner_can], review=[staff_can, reviewer_can, partner_can])
community_review_permissions = make_permissions(edit=[staff_can], review=[staff_can, reviewer_can, community_can])
applicant_edit_permissions = make_permissions(edit=[applicant_can], review=[staff_can]) applicant_edit_permissions = make_permissions(edit=[applicant_can], review=[staff_can])
staff_applicant_edit_permissions = make_permissions(edit=[staff_can, applicant_can]) staff_applicant_edit_permissions = make_permissions(edit=[staff_can, applicant_can])
...@@ -172,6 +177,8 @@ Request = Stage('Request', False) ...@@ -172,6 +177,8 @@ Request = Stage('Request', False)
RequestExt = Stage('RequestExt', True) RequestExt = Stage('RequestExt', True)
RequestCom = Stage('RequestCom', True)
Concept = Stage('Concept', False) Concept = Stage('Concept', False)
Proposal = Stage('Proposal', True) Proposal = Stage('Proposal', True)
...@@ -400,6 +407,154 @@ SingleStageExternalDefinition = [ ...@@ -400,6 +407,154 @@ SingleStageExternalDefinition = [
] ]
SingleStageCommunityDefinition = [
{
INITIAL_STATE: {
'transitions': {
'com_internal_review': 'Open Review',
'com_open_call': 'Open Call (public)',
'com_community_review': 'Open Community Review',
'com_rejected': 'Dismiss',
'com_more_info': 'Request More Information',
'com_determination': 'Ready For Determination',
},
'display': 'Screening',
'public': 'Application Received',
'stage': RequestCom,
'permissions': default_permissions,
},
'com_more_info': {
'transitions': {
INITIAL_STATE: {
'display': 'Submit',
'permissions': {UserPermissions.APPLICANT, UserPermissions.STAFF, UserPermissions.LEAD, UserPermissions.ADMIN},
'method': 'create_revision',
},
},
'display': 'More information required',
'stage': RequestCom,
'permissions': applicant_edit_permissions,
},
'com_open_call': {
'transitions': {
'com_rejected': 'Dismiss',
'com_more_info': 'Request More Information',
},
'display': 'Open Call (public)',
'stage': RequestCom,
'permissions': staff_edit_permissions,
},
},
{
'com_community_review': {
'transitions': {
'com_internal_review': 'Open Review',
'com_rejected': 'Dismiss',
},
'display': 'Community Review',
'public': 'OTF Review',
'stage': RequestCom,
'permissions': community_review_permissions,
},
},
{
'com_internal_review': {
'transitions': {
'com_post_review_discussion': 'Close Review',
},
'display': 'Internal Review',
'public': 'OTF Review',
'stage': RequestCom,
'permissions': default_permissions,
},
},
{
'com_post_review_discussion': {
'transitions': {
'com_external_review': 'Open AC review',
'com_rejected': 'Dismiss',
'com_post_review_more_info': 'Request More Information',
'com_determination': 'Ready For Determination',
},
'display': 'Ready For Discussion',
'stage': RequestCom,
'permissions': hidden_from_applicant_permissions,
},
'com_post_review_more_info': {
'transitions': {
'com_post_review_discussion': {
'display': 'Submit',
'permissions': {UserPermissions.APPLICANT, UserPermissions.STAFF, UserPermissions.LEAD, UserPermissions.ADMIN},
'method': 'create_revision',
},
},
'display': 'More information required',
'stage': RequestCom,
'permissions': applicant_edit_permissions,
},
},
{
'com_external_review': {
'transitions': {
'com_post_external_review_discussion': 'Close Review',
},
'display': 'Advisory Council Review',
'stage': RequestCom,
'permissions': reviewer_review_permissions,
},
},
{
'com_post_external_review_discussion': {
'transitions': {
'com_accepted': 'Accept',
'com_rejected': 'Dismiss',
'com_post_external_review_more_info': 'Request More Information',
'com_determination': 'Ready For Determination',
},
'display': 'Ready For Discussion',
'stage': RequestCom,
'permissions': hidden_from_applicant_permissions,
},
'com_post_external_review_more_info': {
'transitions': {
'com_post_external_review_discussion': {
'display': 'Submit',
'permissions': {UserPermissions.APPLICANT, UserPermissions.STAFF, UserPermissions.LEAD, UserPermissions.ADMIN},
'method': 'create_revision',
},
},
'display': 'More information required',
'stage': RequestCom,
'permissions': applicant_edit_permissions,
},
},
{
'com_determination': {
'transitions': {
'com_accepted': 'Accept',
'com_rejected': 'Dismiss',
},
'display': 'Ready for Determination',
'permissions': hidden_from_applicant_permissions,
'stage': RequestCom,
},
},
{
'com_accepted': {
'display': 'Accepted',
'future': 'Application Outcome',
'stage': RequestCom,
'permissions': staff_applicant_edit_permissions,
},
'com_rejected': {
'display': 'Dismissed',
'stage': RequestCom,
'permissions': no_permissions,
},
},
]
DoubleStageDefinition = [ DoubleStageDefinition = [
{ {
INITIAL_STATE: { INITIAL_STATE: {
...@@ -660,12 +815,15 @@ Request = Workflow('Request', 'single', **phase_data(SingleStageDefinition)) ...@@ -660,12 +815,15 @@ Request = Workflow('Request', 'single', **phase_data(SingleStageDefinition))
RequestExternal = Workflow('Request with external review', 'single_ext', **phase_data(SingleStageExternalDefinition)) RequestExternal = Workflow('Request with external review', 'single_ext', **phase_data(SingleStageExternalDefinition))
RequestCommunity = Workflow('Request with community review', 'single_com', **phase_data(SingleStageCommunityDefinition))
ConceptProposal = Workflow('Concept & Proposal', 'double', **phase_data(DoubleStageDefinition)) ConceptProposal = Workflow('Concept & Proposal', 'double', **phase_data(DoubleStageDefinition))
WORKFLOWS = { WORKFLOWS = {
Request.admin_name: Request, Request.admin_name: Request,
RequestExternal.admin_name: RequestExternal, RequestExternal.admin_name: RequestExternal,
RequestCommunity.admin_name: RequestCommunity,
ConceptProposal.admin_name: ConceptProposal, ConceptProposal.admin_name: ConceptProposal,
} }
...@@ -733,6 +891,7 @@ DETERMINATION_RESPONSE_PHASES = [ ...@@ -733,6 +891,7 @@ DETERMINATION_RESPONSE_PHASES = [
'concept_review_discussion', 'concept_review_discussion',
'post_external_review_discussion', 'post_external_review_discussion',
'ext_post_external_review_discussion', 'ext_post_external_review_discussion',
'com_post_external_review_discussion',
] ]
...@@ -817,3 +976,7 @@ PHASES_MAPPING = { ...@@ -817,3 +976,7 @@ PHASES_MAPPING = {
'statuses': phases_matching('rejected'), 'statuses': phases_matching('rejected'),
}, },
} }
OPEN_CALL_PHASES = [
'com_open_call',
]
...@@ -2,6 +2,7 @@ STAFF_GROUP_NAME = 'Staff' ...@@ -2,6 +2,7 @@ STAFF_GROUP_NAME = 'Staff'
REVIEWER_GROUP_NAME = 'Reviewer' REVIEWER_GROUP_NAME = 'Reviewer'
TEAMADMIN_GROUP_NAME = 'Team Admin' TEAMADMIN_GROUP_NAME = 'Team Admin'
PARTNER_GROUP_NAME = 'Partner' PARTNER_GROUP_NAME = 'Partner'
COMMUNITY_REVIEWER_GROUP_NAME = 'Community reviewer'
GROUPS = [ GROUPS = [
{ {
...@@ -20,4 +21,8 @@ GROUPS = [ ...@@ -20,4 +21,8 @@ GROUPS = [
'name': PARTNER_GROUP_NAME, 'name': PARTNER_GROUP_NAME,
'permissions': [], 'permissions': [],
}, },
{
'name': COMMUNITY_REVIEWER_GROUP_NAME,
'permissions': [],
},
] ]
# Generated by Django 2.0.9 on 2018-12-19 13:21
from __future__ import unicode_literals
from django.core.exceptions import ObjectDoesNotExist
from django.core.management.sql import emit_post_migrate_signal
from django.db import migrations
from opentech.apply.users.groups import GROUPS, COMMUNITY_REVIEWER_GROUP_NAME
def add_groups(apps, schema_editor):
# Workaround for https://code.djangoproject.com/ticket/23422
db_alias = schema_editor.connection.alias
emit_post_migrate_signal(2, False, db_alias)
Group = apps.get_model('auth.Group')
Permission = apps.get_model('auth.Permission')
for group_data in GROUPS:
group, created = Group.objects.get_or_create(name=group_data['name'])
for permission in group_data['permissions']:
try:
group.permissions.add(Permission.objects.get(codename=permission))
except ObjectDoesNotExist:
print("Could not find the '%s' permission" % permission)
def remove_groups(apps, schema_editor):
Group = apps.get_model('auth.Group')
Group.objects.filter(name__in=[COMMUNITY_REVIEWER_GROUP_NAME]).delete()
class Migration(migrations.Migration):
dependencies = [
('users', '0009_add_partner_group'),
]
operations = [
migrations.RunPython(add_groups, remove_groups)
]
...@@ -4,7 +4,7 @@ from django.contrib.auth.models import AbstractUser, BaseUserManager ...@@ -4,7 +4,7 @@ from django.contrib.auth.models import AbstractUser, BaseUserManager
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from .groups import REVIEWER_GROUP_NAME, STAFF_GROUP_NAME, PARTNER_GROUP_NAME from .groups import REVIEWER_GROUP_NAME, STAFF_GROUP_NAME, PARTNER_GROUP_NAME, COMMUNITY_REVIEWER_GROUP_NAME
from .utils import send_activation_email from .utils import send_activation_email
...@@ -20,6 +20,9 @@ class UserQuerySet(models.QuerySet): ...@@ -20,6 +20,9 @@ class UserQuerySet(models.QuerySet):
def partners(self): def partners(self):
return self.filter(groups__name=PARTNER_GROUP_NAME) return self.filter(groups__name=PARTNER_GROUP_NAME)
def community_reviewers(self):
return self.filter(groups__name=COMMUNITY_REVIEWER_GROUP_NAME)
class UserManager(BaseUserManager.from_queryset(UserQuerySet)): class UserManager(BaseUserManager.from_queryset(UserQuerySet)):
use_in_migrations = True use_in_migrations = True
...@@ -104,6 +107,10 @@ class User(AbstractUser): ...@@ -104,6 +107,10 @@ class User(AbstractUser):
def is_partner(self): def is_partner(self):
return self.groups.filter(name=PARTNER_GROUP_NAME).exists() return self.groups.filter(name=PARTNER_GROUP_NAME).exists()
@cached_property
def is_community_reviewer(self):
return self.groups.filter(name=COMMUNITY_REVIEWER_GROUP_NAME).exists()
@cached_property @cached_property
def is_applicant(self): def is_applicant(self):
return not self.is_apply_staff and not self.is_reviewer and not self.is_partner return not self.is_apply_staff and not self.is_reviewer and not self.is_partner
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment