Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Network Manager View Permissions on Opportunity Details #380

Merged
merged 7 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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
67 changes: 43 additions & 24 deletions commcare_connect/opportunity/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,49 @@
FILTER_COUNTRIES = [("+276", "Malawi"), ("+234", "Nigeria"), ("+27", "South Africa"), ("+91", "India")]


class OpportunityChangeForm(forms.ModelForm):
class OpportunityUserInviteForm(forms.Form):
def __init__(self, *args, **kwargs):
credentials = connect_id_client.fetch_credentials()
super().__init__(*args, **kwargs)

self.helper = FormHelper(self)
self.helper.layout = Layout(
Fieldset(
"",
Row(Field("users")),
Row(
Field("filter_country", wrapper_class="form-group col-md-6 mb-0"),
Field("filter_credential", wrapper_class="form-group col-md-6 mb-0"),
),
),
Submit("submit", "Submit"),
)

self.fields["users"] = forms.CharField(
widget=forms.Textarea,
help_text="Enter the phone numbers of the users you want to add to this opportunity, one on each line.",
required=False,
)
self.fields["filter_country"] = forms.CharField(
label="Filter By Country",
widget=forms.Select(choices=[("", "Select country")] + FILTER_COUNTRIES),
required=False,
)
self.fields["filter_credential"] = forms.CharField(
label="Filter By Credential",
widget=forms.Select(choices=[("", "Select credential")] + [(c.slug, c.name) for c in credentials]),
required=False,
)
self.initial["filter_country"] = [""]
self.initial["filter_credential"] = [""]

def clean_users(self):
user_data = self.cleaned_data["users"]
split_users = [line.strip() for line in user_data.splitlines() if line.strip()]
return split_users


class OpportunityChangeForm(forms.ModelForm, OpportunityUserInviteForm):
class Meta:
model = Opportunity
fields = [
Expand All @@ -42,7 +84,6 @@ class Meta:
]

def __init__(self, *args, **kwargs):
credentials = connect_id_client.fetch_credentials()
super().__init__(*args, **kwargs)

self.helper = FormHelper(self)
Expand Down Expand Up @@ -70,11 +111,6 @@ def __init__(self, *args, **kwargs):
Submit("submit", "Submit"),
)

self.fields["users"] = forms.CharField(
widget=forms.Textarea,
help_text="Enter the phone numbers of the users you want to add to this opportunity, one on each line.",
required=False,
)
self.fields["additional_users"] = forms.IntegerField(
required=False, help_text="Adds budget for additional users."
)
Expand All @@ -83,26 +119,9 @@ def __init__(self, *args, **kwargs):
required=False,
help_text="Extends opportunity end date for all users.",
)
self.fields["filter_country"] = forms.CharField(
label="Filter By Country",
widget=forms.Select(choices=[("", "Select country")] + FILTER_COUNTRIES),
required=False,
)
self.fields["filter_credential"] = forms.CharField(
label="Filter By Credential",
widget=forms.Select(choices=[("", "Select credential")] + [(c.slug, c.name) for c in credentials]),
required=False,
)
self.initial["end_date"] = self.instance.end_date.isoformat()
self.initial["filter_country"] = [""]
self.initial["filter_credential"] = [""]
self.currently_active = self.instance.active

def clean_users(self):
user_data = self.cleaned_data["users"]
split_users = [line.strip() for line in user_data.splitlines() if line.strip()]
return split_users

def clean_active(self):
active = self.cleaned_data["active"]
if active and not self.currently_active:
Expand Down
2 changes: 2 additions & 0 deletions commcare_connect/opportunity/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
fetch_attachment,
get_application,
import_catchment_area,
opportunity_user_invite,
payment_delete,
payment_import,
reject_visit,
Expand Down Expand Up @@ -103,4 +104,5 @@
path(
"<int:pk>/invite/<int:application_id>/apply/", view=apply_opportunity_invite, name="apply_opportunity_invite"
),
path("<int:pk>/user_invite/", view=opportunity_user_invite, name="user_invite"),
]
22 changes: 21 additions & 1 deletion commcare_connect/opportunity/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
OpportunityCreationForm,
OpportunityFinalizeForm,
OpportunityInitForm,
OpportunityUserInviteForm,
OpportunityVerificationFlagsConfigForm,
PaymentExportForm,
PaymentUnitForm,
Expand Down Expand Up @@ -275,11 +276,12 @@ def get(self, request, *args, **kwargs):
context = self.get_context_data(object=self.object)
return self.render_to_response(context)

def get_context_data(self, **kwargs):
def get_context_data(self, object, **kwargs):
context = super().get_context_data(**kwargs)
context["export_task_id"] = self.request.GET.get("export_task_id")
context["visit_export_form"] = VisitExportForm()
context["export_form"] = PaymentExportForm()
context["user_is_network_manager"] = object.managed and object.organization == self.request.org
return context


Expand Down Expand Up @@ -1009,3 +1011,21 @@ def apply_opportunity_invite(request, application_id, org_slug=None, pk=None):
f"Application for the opportunity '{application.managed_opportunity.name}' has been successfully submitted.",
)
return redirect("opportunity:list", org_slug)


@org_member_required
def opportunity_user_invite(request, org_slug=None, pk=None):
opportunity = get_object_or_404(Opportunity, organization=request.org, id=pk)
form = OpportunityUserInviteForm(data=request.POST or None)
if form.is_valid():
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this part shared with the other invite view? May be nice to create a shared function

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed. I have made some changes to make the forms inherit functionality. 516e6c9

users = form.cleaned_data["users"]
filter_country = form.cleaned_data["filter_country"]
filter_credential = form.cleaned_data["filter_credential"]
if users or filter_country or filter_credential:
add_connect_users.delay(users, opportunity.id, filter_country, filter_credential)
return redirect("opportunity:detail", request.org.slug, pk)
return render(
request,
"form.html",
dict(title=f"{request.org.slug} - {opportunity.name}", form_title="Invite Users", form=form),
)
4 changes: 4 additions & 0 deletions commcare_connect/organization/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ def is_admin(self):
def is_viewer(self):
return self.role == self.Role.VIEWER

@property
def is_program_manager(self):
return self.organization.program_manager and self.is_admin

class Meta:
db_table = "organization_membership"
unique_together = ("user", "organization")
Expand Down
13 changes: 12 additions & 1 deletion commcare_connect/templates/opportunity/opportunity_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,21 @@ <h1 class="mb-0">{{ object.name }}</h1>
<i class="bi bi-three-dots-vertical"></i>
</button>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="opportunity_details_dropdown">
{% if user_is_network_manager %}
<li>
<a class="dropdown-item"
href="{% url 'opportunity:user_invite' org_slug=request.org.slug pk=opportunity.id %}">
<i class="bi bi-pencil-fill pe-2"></i> Invite Users
</a>
</li>
{% else %}
<li>
<a class="dropdown-item"
href="{% url 'opportunity:edit' org_slug=request.org.slug pk=opportunity.id %}">
<i class="bi bi-pencil-fill pe-2"></i> Edit
</a>
</li>
{% endif %}
{% if not object.managed %}
<li>
<a class="dropdown-item"
Expand All @@ -37,7 +46,7 @@ <h1 class="mb-0">{{ object.name }}</h1>
</a>
</li>
{% endif %}
{% if object.managed and request.org_membership.is_admin and request.org_membership.program_manager or request.user.is_superuser %}
{% if object.managed and request.org_membership.is_program_manager or request.user.is_superuser %}
<li>
<a class="dropdown-item"
href="{% url "program:opportunity_application_list" org_slug=request.org.slug pk=opportunity.managedopportunity.program.id opp_id=opportunity.pk %}">
Expand All @@ -61,13 +70,15 @@ <h1 class="mb-0">{{ object.name }}</h1>
</a>
</li>
{% endif %}
{% if not object.managed or request.org_membership.is_program_manager %}
<li>
<a class="dropdown-item"
href="{% url 'opportunity:verification_flags_config' org_slug=request.org.slug pk=opportunity.id %}">
<i class="bi bi-plus-circle-fill pe-2"></i>
{% translate "Configure Verification Flags" %}
</a>
</li>
{% endif %}
<li>
<a class="dropdown-item"
href="{% url 'opportunity:suspended_users_list' org_slug=request.org.slug pk=opportunity.id %}">
Expand Down