Add Co-applicants feature to submissions#4492
Conversation
|
@sandeepsajan0 Add some sane max limit and ratelimit the feature. @frankduncan mentioned on a meeting today that they had issues with spammers etc. misusing the ability to create accounts. Account creation is ratelimited and since this feature will be a way to create accounts we should rarelimit. Adding a sane max number of co-applicants is a good precaution as well. @wes-otf Maybe ten (10)? |
|
yeah I think 10 would be perfect |
c55867f to
be48f51
Compare
ed56b85 to
1bc2891
Compare
@frjo We are creating users after the co-applicant accepts the invite, so we are safe from user creation spam. Also, there is an env var for the max number of invites for a submission, so invite spam is also handled.
|
|
This functionality is so fantastic! Been playing with it a little bit locally today and will have a few tweaks, but overall really nice job! |
frjo
left a comment
There was a problem hiding this comment.
Works really well overall, nice! Some minor text changes.
| {% if not can_accept %} | ||
| {% trans "But You can't accept this invite because you already hold a responsible position in" %} {{ ORG_SHORT_NAME }} | ||
| {% else %} | ||
| {% blocktrans %} Click on link if you want to accept it.{% endblocktrans %} |
There was a problem hiding this comment.
Remove space before "Click". Also add empty line after.
| <div class="bg-gray-100 max-w-[70%] mx-auto mt-6 px-10 pt-6 pb-4 border border-gray-300 rounded-sm"> | ||
| {% if is_valid %} | ||
| <p>{% trans "You've been invited to join the submission" %} "{{ invite.submission.title }}" {% trans "as a co-applicant with email" %} <i>{{ invite.invited_user_email }}</i>. {% trans "Please respond to the invitation by choosing accept or decline." %}</p> | ||
| <p>{% trans "If you accept, you’ll be automatically signed up or logged in and taken directly to" %} {% if two_factor_required %}{% trans "two factor authentication and then to" %} {% endif %} {% trans "the submission." %}</p> |
There was a problem hiding this comment.
"the application" instead of "the submission"
| {% if is_valid %} | ||
| <p>{% trans "You've been invited to join the submission" %} "{{ invite.submission.title }}" {% trans "as a co-applicant with email" %} <i>{{ invite.invited_user_email }}</i>. {% trans "Please respond to the invitation by choosing accept or decline." %}</p> | ||
| <p>{% trans "If you accept, you’ll be automatically signed up or logged in and taken directly to" %} {% if two_factor_required %}{% trans "two factor authentication and then to" %} {% endif %} {% trans "the submission." %}</p> | ||
| <p>{% trans "We recommend updating your profile after accepting the invite. You’ll also have the option to update your name and email in 'My account' section." %}</p> |
There was a problem hiding this comment.
These two sentences can be merged it to one I believe.
| hx-target="#htmx-modal" | ||
| {% if object.co_applicant_invites.count >= invite_max_limit %}disabled title='{% trans "Max limit reached" %}'{% endif %} | ||
| role="button" | ||
| aria-label="{% trans "Invite CoApplicant" %}" |
There was a problem hiding this comment.
User facing text should say "co-applicant".
wes-otf
left a comment
There was a problem hiding this comment.
really nice work! all my changes were super minor things, the functionality seems great.
| <details {% if user.is_applicant %} open {% endif %}> | ||
| <summary class="flex gap-4 justify-between items-center"> | ||
| <p class="flex items-center text-lg font-bold"> | ||
| {% trans "Co-applicants" %} | ||
| {% heroicon_solid "chevron-down" size="16" class="w-4 h-4 ms-2" %} |
There was a problem hiding this comment.
| <details {% if user.is_applicant %} open {% endif %}> | |
| <summary class="flex gap-4 justify-between items-center"> | |
| <p class="flex items-center text-lg font-bold"> | |
| {% trans "Co-applicants" %} | |
| {% heroicon_solid "chevron-down" size="16" class="w-4 h-4 ms-2" %} | |
| <details {% if user.is_applicant or not co_applicants %} open {% endif %} class="group"> | |
| <summary class="flex gap-4 justify-between items-center list-none"> | |
| <p class="flex items-center text-lg font-bold"> | |
| {% trans "Co-applicants" %} | |
| {% heroicon_solid "chevron-down" size="16" class="rotate-90 w-4 h-4 ms-2 group-open:rotate-0" %} |
This might make things a bit more intuitive - don't hide no applicants and have the chevron indicate when things are hidden
There was a problem hiding this comment.
also might be nice to include the number of co-applicants next to the Co-applicants text just to get the idea at a glace
There was a problem hiding this comment.
Updated! It looks better. The number of co-applicants is also included there.
| </div> | ||
| {% else %} | ||
| <div> | ||
| {% trans "No co-applicant yet" %} |
There was a problem hiding this comment.
| {% trans "No co-applicant yet" %} | |
| {% trans "No co-applicants yet." %} |
To be consistent with the other blocks
| class="font-bold line-clamp-2" | ||
| href="{% url 'apply:submissions:edit_co_applicant' invite_pk=invite.id %}" | ||
| hx-get="{% url 'apply:submissions:edit_co_applicant' invite_pk=invite.id %}" | ||
| hx-target="#htmx-modal" | ||
| > | ||
| <div class="flex justify-between"> | ||
| {% if invite.status == "accepted" %} | ||
| {{ invite.co_applicant.user }} | ||
| {% else %} | ||
| {{ invite.invited_user_email }} | ||
| {% endif %} | ||
|
|
||
| {% heroicon_solid "pencil" class="inline align-middle me-1" width=16 height=16 stroke_width=2 aria_hidden=true %} |
There was a problem hiding this comment.
| class="font-bold line-clamp-2" | |
| href="{% url 'apply:submissions:edit_co_applicant' invite_pk=invite.id %}" | |
| hx-get="{% url 'apply:submissions:edit_co_applicant' invite_pk=invite.id %}" | |
| hx-target="#htmx-modal" | |
| > | |
| <div class="flex justify-between"> | |
| {% if invite.status == "accepted" %} | |
| {{ invite.co_applicant.user }} | |
| {% else %} | |
| {{ invite.invited_user_email }} | |
| {% endif %} | |
| {% heroicon_solid "pencil" class="inline align-middle me-1" width=16 height=16 stroke_width=2 aria_hidden=true %} | |
| class="font-bold line-clamp-2 group/coapplicant" | |
| href="{% url 'apply:submissions:edit_co_applicant' invite_pk=invite.id %}" | |
| hx-get="{% url 'apply:submissions:edit_co_applicant' invite_pk=invite.id %}" | |
| hx-target="#htmx-modal" | |
| > | |
| <div class="flex justify-between"> | |
| {% if invite.status == "accepted" %} | |
| {{ invite.co_applicant.user }} | |
| {% else %} | |
| {{ invite.invited_user_email }} | |
| {% endif %} | |
| {% heroicon_solid "pencil" class="hidden align-middle me-1 group-hover/coapplicant:inline" width=16 height=16 stroke_width=2 aria_hidden=true %} |
I think @theskumar mentioned this in the last dev call but might make sense to keep this similar to the todo list's functionality and only show the edit button on hover.
(edited to not conflict w groups in this comment)
| def handle_co_applicant_invite(self, source, related, **kwargs): | ||
| from hypha.apply.funds.utils import generate_invite_path | ||
|
|
||
| invited_user = User.objects.filter(email=related.invited_user_email).first() |
There was a problem hiding this comment.
if you're already querying for the existing user here it might be cool to pass their name to the template so they won't get something different in the salutation than their set name in Hypha. not mission critical though
There was a problem hiding this comment.
Updated. Using the invited user name if it exists, else the trimmed email name.
|
My last comment is for permissions I think it might make more sense to always allow commenting (both read only & editing) and maybe renaming read only to view? |
…rmission for coapplicant
… on accept, Updated permissions and dashboard for co-applicants, Update listing and modals UI
9f43d3e to
c47fd00
Compare
|
@frjo It is ready for testing.
@wes-otf As I will work on the project part permissions, we can decide about it and use the same pattern for both. |

Fixes #3919
Applicant UI, default open

Invite co-applicant, (on click invite button).

Update roles, after accept

Staff UI, default collapsed.

Co-applicant UI, invite landing page

Invalid invite page
Test Steps