-
-
Notifications
You must be signed in to change notification settings - Fork 156
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
WIP started adding the ability to create an account from an organization
Signed-off-by: Trey <[email protected]>
- Loading branch information
Showing
11 changed files
with
254 additions
and
82 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
from django.contrib import messages | ||
from django.shortcuts import render | ||
from django.urls import reverse | ||
from django.utils.crypto import get_random_string | ||
|
||
from backend.decorators import web_require_scopes | ||
from backend.models import Organization, User, TeamMemberPermission | ||
from backend.service.permissions.scopes import get_permissions_from_request | ||
from backend.types.emails import SingleEmailInput | ||
from backend.types.requests import WebRequest | ||
from settings.helpers import send_email | ||
|
||
|
||
@web_require_scopes("team:invite", True, True) | ||
def create_user_view(request: WebRequest): | ||
team_id = request.POST.get("team_id", "") | ||
|
||
team: Organization | None = Organization.objects.filter(id=team_id).first() | ||
|
||
if not team: | ||
messages.error("This team does not exist") | ||
return render(request, "base/toast.html") | ||
|
||
if not team.is_owner(request.user): | ||
messages.error(request, "Only the team owner can create users") | ||
return render(request, "base/toast.html") | ||
|
||
first_name = request.POST.get("first_name", "") | ||
last_name = request.POST.get("last_name", "") | ||
email = request.POST.get("email", "") | ||
permissions: list = get_permissions_from_request(request) | ||
|
||
if not email: | ||
messages.error(request, "Please enter a valid user email") | ||
return render(request, "base/toast.html") | ||
|
||
if User.objects.filter(email=email).exists(): | ||
messages.error(request, "This user already exists, invite them instead!") | ||
return render(request, "base/toast.html") | ||
|
||
temporary_password = get_random_string(length=8) | ||
|
||
user: User = User.objects.create_user(email=email, first_name=first_name, last_name=last_name, username=email) | ||
user.set_password(temporary_password) | ||
user.awaiting_email_verification = False | ||
user.save() | ||
|
||
send_email( | ||
SingleEmailInput( | ||
destination=email, | ||
subject="MyFinances | You have been invited to join an organization", | ||
content=f""" | ||
Hi {user.first_name or "User"}, | ||
You have been invited by {request.user.email} to join the organization {team.name}. | ||
Your account email is: {email} | ||
Your temporary password is: {temporary_password} | ||
We suggest that you change your password as soon as you login, however no other user including the organization have | ||
access to this password. | ||
Upon login, you will be added to the \"{team.name}\" organization. However, if required, you may leave at any point. | ||
Login to your new account using this link: | ||
{request.build_absolute_uri(reverse("auth:login manual"))} | ||
""", | ||
) | ||
) | ||
|
||
team.members.add(user) | ||
|
||
TeamMemberPermission.objects.create(user=user, team=team, scopes=permissions) | ||
|
||
messages.success(request, "User was created successfully. They have been emailed instructions.") | ||
return render(request, "base/toast.html") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Generated by Django 5.1 on 2024-09-14 21:55 | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
("backend", "0059_alter_invoicerecurringprofile_managers_and_more"), | ||
] | ||
|
||
operations = [ | ||
migrations.AddField( | ||
model_name="user", | ||
name="require_change_password", | ||
field=models.BooleanField(default=False), | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
{% load strfilters %} | ||
<div class="collapse collapse-arrow border select-bordered mt-4"> | ||
<input type="checkbox" /> | ||
<div class="collapse-title text-xl font-medium">Permissions</div> | ||
<div class="collapse-content"> | ||
<ul class="block"> | ||
{% for group in permissions %} | ||
<li class="border-t-2 mt-2 p-2 flex items-center"> | ||
<div class="flex-auto"> | ||
<strong>{{ group.name | title | split:"_" | join:" " }}</strong> | ||
<div class="text text-sm">{{ group.description }}</div> | ||
</div> | ||
<select class="select select-bordered inline-block position-relative" | ||
name="permission_{{ group.name }}"> | ||
<option value="none">No Access</option> | ||
{% for item, readable in group.options.items %} | ||
<option value="{{ item }}" | ||
{% if group.name|add:":"|add:item in user_current_scopes %}selected{% endif %}> | ||
{{ readable }} | ||
</option> | ||
{% endfor %} | ||
</select> | ||
</li> | ||
{% endfor %} | ||
</ul> | ||
</div> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
{% component_block "modal" id="modal_invite_user" start_open="true" title="Create User Account" %} | ||
{% fill "content" %} | ||
<form class="py-4" | ||
id="modal_invite_user-form" | ||
hx-post="{% url 'api:teams:invite' %}" | ||
hx-swap="none"> | ||
{% csrf_token %} | ||
<div class="form-control w-full"> | ||
<label class="label justify-start"> | ||
Users' Email | ||
<span class="tooltip tooltip-right ml-2" data-tip="The email address of the user you are about to create"> | ||
<i class="fa fa-info-circle"></i> | ||
</span> | ||
<span class="required_star">*</span> | ||
</label> | ||
<input id="modal_input-email" | ||
name="email" | ||
type="email" | ||
class="input input-block input-bordered" | ||
required> | ||
</div> | ||
<div class="flex flex-row gap-4 w-full"> | ||
<div> | ||
<label class="label justify-start"> | ||
Users' First Name | ||
<span class="required_star">*</span> | ||
</label> | ||
<input id="modal_input-email" | ||
name="first_name" | ||
type="text" | ||
class="input input-block input-bordered" | ||
required> | ||
</div> | ||
<div> | ||
<label class="label justify-start"> | ||
Users' Last Name | ||
<span class="required_star">*</span> | ||
</label> | ||
<input id="modal_input-email" | ||
name="last_name" | ||
type="text" | ||
class="input input-block input-bordered" | ||
required> | ||
</div> | ||
</div> | ||
<input type="hidden" name="team_id" value="{{ team_id }}"> | ||
{% include "components/permissions/selector.html" %} | ||
<div class="modal-action"> | ||
<button type="submit" | ||
id="modal_invite_user-submit" | ||
class="btn btn-primary" | ||
x-on:invite_user_error.window="document.getElementById('modal_invite_user').close()"> | ||
Send Invite | ||
</button> | ||
<button type="button" | ||
_="on click call #modal_invite_user.close()" | ||
class="btn">Cancel | ||
</button> | ||
</div> | ||
</form> | ||
{% endfill %} | ||
{% endcomponent_block %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.