forked from Github-Mirrors/canaille
User emails and phone numbers are now multiple
This commit is contained in:
parent
8617fc0f2b
commit
b7e1590510
8 changed files with 209 additions and 109 deletions
|
@ -11,6 +11,7 @@ Added
|
|||
|
||||
- Configuration entries can be loaded from files if the entry key has a *_FILE* suffix
|
||||
and the entry value is the path to the file. :issue:`134` :pr:`134`
|
||||
- Field list support. :issue:`115` :pr:`136`
|
||||
|
||||
Removed
|
||||
*******
|
||||
|
|
|
@ -42,6 +42,7 @@ from .forms import MINIMUM_PASSWORD_LENGTH
|
|||
from .forms import PasswordForm
|
||||
from .forms import PasswordResetForm
|
||||
from .forms import profile_form
|
||||
from .forms import PROFILE_FORM_FIELDS
|
||||
from .mails import send_invitation_mail
|
||||
from .mails import send_password_initialization_mail
|
||||
from .mails import send_password_reset_mail
|
||||
|
@ -307,7 +308,7 @@ def registration(data, hash):
|
|||
|
||||
data = {
|
||||
"user_name": invitation.user_name,
|
||||
"emails": invitation.email,
|
||||
"emails": [invitation.email],
|
||||
"groups": invitation.groups,
|
||||
}
|
||||
|
||||
|
@ -336,25 +337,29 @@ def registration(data, hash):
|
|||
form["password1"].flags.required = True
|
||||
form["password2"].flags.required = True
|
||||
|
||||
if request.form:
|
||||
if not form.validate():
|
||||
flash(_("User account creation failed."), "error")
|
||||
if not request.form or form.form_control():
|
||||
return render_template(
|
||||
"profile_add.html",
|
||||
form=form,
|
||||
menuitem="users",
|
||||
edited_user=None,
|
||||
self_deletion=False,
|
||||
)
|
||||
|
||||
else:
|
||||
user = profile_create(current_app, form)
|
||||
user.login()
|
||||
flash(_("Your account has been created successfully."), "success")
|
||||
return redirect(
|
||||
url_for("account.profile_edition", username=user.user_name[0])
|
||||
)
|
||||
if not form.validate():
|
||||
flash(_("User account creation failed."), "error")
|
||||
return render_template(
|
||||
"profile_add.html",
|
||||
form=form,
|
||||
menuitem="users",
|
||||
edited_user=None,
|
||||
self_deletion=False,
|
||||
)
|
||||
|
||||
return render_template(
|
||||
"profile_add.html",
|
||||
form=form,
|
||||
menuitem="users",
|
||||
edited_user=None,
|
||||
self_deletion=False,
|
||||
)
|
||||
user = profile_create(current_app, form)
|
||||
user.login()
|
||||
flash(_("Your account has been created successfully."), "success")
|
||||
return redirect(url_for("account.profile_edition", username=user.user_name[0]))
|
||||
|
||||
|
||||
@bp.route("/profile", methods=("GET", "POST"))
|
||||
|
@ -367,23 +372,27 @@ def profile_creation(user):
|
|||
if field.render_kw and "readonly" in field.render_kw:
|
||||
del field.render_kw["readonly"]
|
||||
|
||||
if request.form:
|
||||
if not form.validate():
|
||||
flash(_("User account creation failed."), "error")
|
||||
if not request.form or form.form_control():
|
||||
return render_template(
|
||||
"profile_add.html",
|
||||
form=form,
|
||||
menuitem="users",
|
||||
edited_user=None,
|
||||
self_deletion=False,
|
||||
)
|
||||
|
||||
else:
|
||||
user = profile_create(current_app, form)
|
||||
return redirect(
|
||||
url_for("account.profile_edition", username=user.user_name[0])
|
||||
)
|
||||
if not form.validate():
|
||||
flash(_("User account creation failed."), "error")
|
||||
return render_template(
|
||||
"profile_add.html",
|
||||
form=form,
|
||||
menuitem="users",
|
||||
edited_user=None,
|
||||
self_deletion=False,
|
||||
)
|
||||
|
||||
return render_template(
|
||||
"profile_add.html",
|
||||
form=form,
|
||||
menuitem="users",
|
||||
edited_user=None,
|
||||
self_deletion=False,
|
||||
)
|
||||
user = profile_create(current_app, form)
|
||||
return redirect(url_for("account.profile_edition", username=user.user_name[0]))
|
||||
|
||||
|
||||
def profile_create(current_app, form):
|
||||
|
@ -455,11 +464,13 @@ def profile_edition(user, username):
|
|||
"organization",
|
||||
}
|
||||
data = {
|
||||
k: getattr(user, k)[0]
|
||||
if getattr(user, k) and isinstance(getattr(user, k), list)
|
||||
else getattr(user, k) or ""
|
||||
for k in fields
|
||||
if hasattr(user, k) and k in available_fields
|
||||
field: getattr(user, field)[0]
|
||||
if getattr(user, field)
|
||||
and isinstance(getattr(user, field), list)
|
||||
and not PROFILE_FORM_FIELDS[field].field_class == wtforms.FieldList
|
||||
else getattr(user, field) or ""
|
||||
for field in fields
|
||||
if hasattr(user, field) and field in available_fields
|
||||
}
|
||||
|
||||
form = profile_form(
|
||||
|
@ -467,40 +478,45 @@ def profile_edition(user, username):
|
|||
)
|
||||
form.process(CombinedMultiDict((request.files, request.form)) or None, data=data)
|
||||
|
||||
if request.form:
|
||||
if not form.validate():
|
||||
flash(_("Profile edition failed."), "error")
|
||||
if not request.form or form.form_control():
|
||||
return render_template(
|
||||
"profile_edit.html",
|
||||
form=form,
|
||||
menuitem=menuitem,
|
||||
edited_user=user,
|
||||
)
|
||||
|
||||
else:
|
||||
for attribute in form:
|
||||
if attribute.name in user.attributes and attribute.name in editor.write:
|
||||
if isinstance(attribute.data, FileStorage):
|
||||
data = attribute.data.stream.read()
|
||||
else:
|
||||
data = attribute.data
|
||||
if not form.validate():
|
||||
flash(_("Profile edition failed."), "error")
|
||||
return render_template(
|
||||
"profile_edit.html",
|
||||
form=form,
|
||||
menuitem=menuitem,
|
||||
edited_user=user,
|
||||
)
|
||||
|
||||
setattr(user, attribute.name, data)
|
||||
for attribute in form:
|
||||
if attribute.name in user.attributes and attribute.name in editor.write:
|
||||
if isinstance(attribute.data, FileStorage):
|
||||
data = attribute.data.stream.read()
|
||||
else:
|
||||
data = attribute.data
|
||||
|
||||
if "photo" in form and form["photo_delete"].data:
|
||||
del user.photo
|
||||
setattr(user, attribute.name, data)
|
||||
|
||||
if "preferred_language" in request.form:
|
||||
# Refresh the babel cache in case the lang is updated
|
||||
refresh()
|
||||
if "photo" in form and form["photo_delete"].data:
|
||||
del user.photo
|
||||
|
||||
if form["preferred_language"].data == "auto":
|
||||
user.preferred_language = None
|
||||
if "preferred_language" in request.form:
|
||||
# Refresh the babel cache in case the lang is updated
|
||||
refresh()
|
||||
|
||||
user.save()
|
||||
flash(_("Profile updated successfully."), "success")
|
||||
return redirect(url_for("account.profile_edition", username=username))
|
||||
if form["preferred_language"].data == "auto":
|
||||
user.preferred_language = None
|
||||
|
||||
return render_template(
|
||||
"profile_edit.html",
|
||||
form=form,
|
||||
menuitem=menuitem,
|
||||
edited_user=user,
|
||||
)
|
||||
user.save()
|
||||
flash(_("Profile updated successfully."), "success")
|
||||
return redirect(url_for("account.profile_edition", username=username))
|
||||
|
||||
|
||||
@bp.route("/profile/<username>/settings", methods=("GET", "POST"))
|
||||
|
|
|
@ -4,6 +4,7 @@ from canaille.app.forms import DateTimeUTCField
|
|||
from canaille.app.forms import HTMXBaseForm
|
||||
from canaille.app.forms import HTMXForm
|
||||
from canaille.app.forms import is_uri
|
||||
from canaille.app.forms import unique_values
|
||||
from canaille.app.i18n import native_language_name_from_code
|
||||
from flask import current_app
|
||||
from flask import g
|
||||
|
@ -155,24 +156,32 @@ PROFILE_FORM_FIELDS = dict(
|
|||
"autocorrect": "off",
|
||||
},
|
||||
),
|
||||
emails=wtforms.EmailField(
|
||||
_("Email address"),
|
||||
validators=[
|
||||
wtforms.validators.DataRequired(),
|
||||
wtforms.validators.Email(),
|
||||
unique_email,
|
||||
],
|
||||
description=_(
|
||||
"This email will be used as a recovery address to reset the password if needed"
|
||||
emails=wtforms.FieldList(
|
||||
wtforms.EmailField(
|
||||
_("Email address"),
|
||||
validators=[
|
||||
wtforms.validators.DataRequired(),
|
||||
wtforms.validators.Email(),
|
||||
unique_email,
|
||||
],
|
||||
description=_(
|
||||
"This email will be used as a recovery address to reset the password if needed"
|
||||
),
|
||||
render_kw={
|
||||
"placeholder": _("jane@doe.com"),
|
||||
"spellcheck": "false",
|
||||
"autocorrect": "off",
|
||||
},
|
||||
),
|
||||
render_kw={
|
||||
"placeholder": _("jane@doe.com"),
|
||||
"spellcheck": "false",
|
||||
"autocorrect": "off",
|
||||
},
|
||||
min_entries=1,
|
||||
validators=[unique_values],
|
||||
),
|
||||
phone_numbers=wtforms.TelField(
|
||||
_("Phone number"), render_kw={"placeholder": _("555-000-555")}
|
||||
phone_numbers=wtforms.FieldList(
|
||||
wtforms.TelField(
|
||||
_("Phone number"), render_kw={"placeholder": _("555-000-555")}
|
||||
),
|
||||
min_entries=1,
|
||||
validators=[unique_values],
|
||||
),
|
||||
formatted_address=wtforms.StringField(
|
||||
_("Address"),
|
||||
|
|
|
@ -50,7 +50,7 @@ def test_form_translations(testclient, logged_user):
|
|||
logged_user.save()
|
||||
|
||||
res = testclient.get("/profile/user", status=200)
|
||||
res.form["emails"] = "invalid"
|
||||
res.form["emails-0"] = "invalid"
|
||||
res = res.form.submit(name="action", value="edit")
|
||||
|
||||
res.mustcontain(no="Invalid email address.")
|
||||
|
|
|
@ -26,7 +26,7 @@ def test_invitation(testclient, logged_admin, foo_group, smtpd):
|
|||
|
||||
assert res.form["user_name"].value == "someone"
|
||||
assert res.form["user_name"].attrs["readonly"]
|
||||
assert res.form["emails"].value == "someone@domain.tld"
|
||||
assert res.form["emails-0"].value == "someone@domain.tld"
|
||||
assert res.form["groups"].value == [foo_group.id]
|
||||
|
||||
res.form["password1"] = "whatever"
|
||||
|
@ -75,7 +75,7 @@ def test_invitation_editable_user_name(testclient, logged_admin, foo_group, smtp
|
|||
|
||||
assert res.form["user_name"].value == "jackyjack"
|
||||
assert "readonly" not in res.form["user_name"].attrs
|
||||
assert res.form["emails"].value == "jackyjack@domain.tld"
|
||||
assert res.form["emails-0"].value == "jackyjack@domain.tld"
|
||||
assert res.form["groups"].value == [foo_group.id]
|
||||
|
||||
res.form["user_name"] = "djorje"
|
||||
|
@ -120,7 +120,7 @@ def test_generate_link(testclient, logged_admin, foo_group, smtpd):
|
|||
res = testclient.get(url, status=200)
|
||||
|
||||
assert res.form["user_name"].value == "sometwo"
|
||||
assert res.form["emails"].value == "sometwo@domain.tld"
|
||||
assert res.form["emails-0"].value == "sometwo@domain.tld"
|
||||
assert res.form["groups"].value == [foo_group.id]
|
||||
|
||||
res.form["password1"] = "whatever"
|
||||
|
@ -169,6 +169,24 @@ def test_registration(testclient, foo_group):
|
|||
testclient.get(f"/register/{b64}/{hash}", status=200)
|
||||
|
||||
|
||||
def test_registration_formcontrol(testclient):
|
||||
invitation = Invitation(
|
||||
datetime.datetime.now(datetime.timezone.utc).isoformat(),
|
||||
"someoneelse",
|
||||
False,
|
||||
"someone@mydomain.tld",
|
||||
[],
|
||||
)
|
||||
b64 = invitation.b64()
|
||||
hash = invitation.profile_hash()
|
||||
|
||||
res = testclient.get(f"/register/{b64}/{hash}", status=200)
|
||||
assert "emails-1" not in res.form.fields
|
||||
|
||||
res = res.form.submit(status=200, name="fieldlist_add", value="emails-0")
|
||||
assert "emails-1" in res.form.fields
|
||||
|
||||
|
||||
def test_registration_invalid_hash(testclient, foo_group):
|
||||
now = datetime.datetime.now(datetime.timezone.utc).isoformat()
|
||||
invitation = Invitation(
|
||||
|
|
|
@ -14,8 +14,8 @@ def test_user_creation_edition_and_deletion(
|
|||
res.form["user_name"] = "george"
|
||||
res.form["given_name"] = "George"
|
||||
res.form["family_name"] = "Abitbol"
|
||||
res.form["emails"] = "george@abitbol.com"
|
||||
res.form["phone_numbers"] = "555-666-888"
|
||||
res.form["emails-0"] = "george@abitbol.com"
|
||||
res.form["phone_numbers-0"] = "555-666-888"
|
||||
res.form["groups"] = [foo_group.id]
|
||||
res.form["password1"] = "totoyolo"
|
||||
res.form["password2"] = "totoyolo"
|
||||
|
@ -70,11 +70,11 @@ def test_profile_creation_dynamic_validation(testclient, logged_admin, user):
|
|||
"/profile",
|
||||
{
|
||||
"csrf_token": res.form["csrf_token"].value,
|
||||
"emails": "john@doe.com",
|
||||
"emails-0": "john@doe.com",
|
||||
},
|
||||
headers={
|
||||
"HX-Request": "true",
|
||||
"HX-Trigger-Name": "emails",
|
||||
"HX-Trigger-Name": "emails-0",
|
||||
},
|
||||
)
|
||||
res.mustcontain("The email 'john@doe.com' is already used")
|
||||
|
@ -84,7 +84,7 @@ def test_user_creation_without_password(testclient, logged_moderator):
|
|||
res = testclient.get("/profile", status=200)
|
||||
res.form["user_name"] = "george"
|
||||
res.form["family_name"] = "Abitbol"
|
||||
res.form["emails"] = "george@abitbol.com"
|
||||
res.form["emails-0"] = "george@abitbol.com"
|
||||
|
||||
res = res.form.submit(name="action", value="edit", status=302)
|
||||
assert ("success", "User account creation succeed.") in res.flashes
|
||||
|
@ -115,7 +115,7 @@ def test_username_already_taken(
|
|||
res = testclient.get("/profile", status=200)
|
||||
res.form["user_name"] = "user"
|
||||
res.form["family_name"] = "foo"
|
||||
res.form["emails"] = "any@thing.com"
|
||||
res.form["emails-0"] = "any@thing.com"
|
||||
res = res.form.submit(name="action", value="edit")
|
||||
assert ("error", "User account creation failed.") in res.flashes
|
||||
res.mustcontain("The login 'user' already exists")
|
||||
|
@ -125,7 +125,7 @@ def test_email_already_taken(testclient, logged_moderator, user, foo_group, bar_
|
|||
res = testclient.get("/profile", status=200)
|
||||
res.form["user_name"] = "user2"
|
||||
res.form["family_name"] = "foo"
|
||||
res.form["emails"] = "john@doe.com"
|
||||
res.form["emails-0"] = "john@doe.com"
|
||||
res = res.form.submit(name="action", value="edit")
|
||||
assert ("error", "User account creation failed.") in res.flashes
|
||||
res.mustcontain("The email 'john@doe.com' is already used")
|
||||
|
@ -136,7 +136,7 @@ def test_cn_setting_with_given_name_and_surname(testclient, logged_moderator):
|
|||
res.form["user_name"] = "george"
|
||||
res.form["given_name"] = "George"
|
||||
res.form["family_name"] = "Abitbol"
|
||||
res.form["emails"] = "george@abitbol.com"
|
||||
res.form["emails-0"] = "george@abitbol.com"
|
||||
|
||||
res = res.form.submit(name="action", value="edit", status=302).follow(status=200)
|
||||
|
||||
|
@ -149,10 +149,38 @@ def test_cn_setting_with_surname_only(testclient, logged_moderator):
|
|||
res = testclient.get("/profile", status=200)
|
||||
res.form["user_name"] = "george"
|
||||
res.form["family_name"] = "Abitbol"
|
||||
res.form["emails"] = "george@abitbol.com"
|
||||
res.form["emails-0"] = "george@abitbol.com"
|
||||
|
||||
res = res.form.submit(name="action", value="edit", status=302).follow(status=200)
|
||||
|
||||
george = models.User.get_from_login("george")
|
||||
assert george.formatted_name[0] == "Abitbol"
|
||||
george.delete()
|
||||
|
||||
|
||||
def test_formcontrol(testclient, logged_admin):
|
||||
res = testclient.get("/profile")
|
||||
assert "emails-1" not in res.form.fields
|
||||
|
||||
res = res.form.submit(status=200, name="fieldlist_add", value="emails-0")
|
||||
assert "emails-1" in res.form.fields
|
||||
|
||||
|
||||
def test_formcontrol_htmx(testclient, logged_admin):
|
||||
res = testclient.get("/profile")
|
||||
data = {
|
||||
field: res.form[field].value
|
||||
for field in res.form.fields
|
||||
if len(res.form.fields.get(field)) == 1
|
||||
}
|
||||
data["fieldlist_add"] = "emails-0"
|
||||
response = testclient.post(
|
||||
"/profile",
|
||||
data,
|
||||
headers={
|
||||
"HX-Request": "true",
|
||||
"HX-Trigger-Name": "listfield_add",
|
||||
},
|
||||
)
|
||||
assert "emails-0" in response.text
|
||||
assert "emails-1" in response.text
|
||||
|
|
|
@ -104,8 +104,8 @@ def test_edition(
|
|||
res.form["given_name"] = "given_name"
|
||||
res.form["family_name"] = "family_name"
|
||||
res.form["display_name"] = "display_name"
|
||||
res.form["emails"] = "email@mydomain.tld"
|
||||
res.form["phone_numbers"] = "555-666-777"
|
||||
res.form["emails-0"] = "email@mydomain.tld"
|
||||
res.form["phone_numbers-0"] = "555-666-777"
|
||||
res.form["formatted_address"] = "formatted_address"
|
||||
res.form["street"] = "street"
|
||||
res.form["postal_code"] = "postal_code"
|
||||
|
@ -158,7 +158,7 @@ def test_edition_remove_fields(
|
|||
):
|
||||
res = testclient.get("/profile/user", status=200)
|
||||
res.form["display_name"] = ""
|
||||
res.form["phone_numbers"] = ""
|
||||
res.form["phone_numbers-0"] = ""
|
||||
|
||||
res = res.form.submit(name="action", value="edit")
|
||||
assert res.flashes == [("success", "Profile updated successfully.")], res.text
|
||||
|
@ -183,11 +183,11 @@ def test_profile_edition_dynamic_validation(testclient, logged_admin, user):
|
|||
"/profile/admin",
|
||||
{
|
||||
"csrf_token": res.form["csrf_token"].value,
|
||||
"emails": "john@doe.com",
|
||||
"emails-0": "john@doe.com",
|
||||
},
|
||||
headers={
|
||||
"HX-Request": "true",
|
||||
"HX-Trigger-Name": "emails",
|
||||
"HX-Trigger-Name": "emails-0",
|
||||
},
|
||||
)
|
||||
res.mustcontain("The email 'john@doe.com' is already used")
|
||||
|
@ -205,13 +205,13 @@ def test_field_permissions_none(testclient, logged_user):
|
|||
}
|
||||
|
||||
res = testclient.get("/profile/user", status=200)
|
||||
assert "phone_numbers" not in res.form.fields
|
||||
assert "phone_numbers-0" not in res.form.fields
|
||||
|
||||
testclient.post(
|
||||
"/profile/user",
|
||||
{
|
||||
"action": "edit",
|
||||
"phone_numbers": "000-000-000",
|
||||
"phone_numbers-0": "000-000-000",
|
||||
"csrf_token": res.form["csrf_token"].value,
|
||||
},
|
||||
)
|
||||
|
@ -230,13 +230,13 @@ def test_field_permissions_read(testclient, logged_user):
|
|||
"PERMISSIONS": ["edit_self"],
|
||||
}
|
||||
res = testclient.get("/profile/user", status=200)
|
||||
assert "phone_numbers" in res.form.fields
|
||||
assert "phone_numbers-0" in res.form.fields
|
||||
|
||||
testclient.post(
|
||||
"/profile/user",
|
||||
{
|
||||
"action": "edit",
|
||||
"phone_numbers": "000-000-000",
|
||||
"phone_numbers-0": "000-000-000",
|
||||
"csrf_token": res.form["csrf_token"].value,
|
||||
},
|
||||
)
|
||||
|
@ -255,13 +255,13 @@ def test_field_permissions_write(testclient, logged_user):
|
|||
"PERMISSIONS": ["edit_self"],
|
||||
}
|
||||
res = testclient.get("/profile/user", status=200)
|
||||
assert "phone_numbers" in res.form.fields
|
||||
assert "phone_numbers-0" in res.form.fields
|
||||
|
||||
testclient.post(
|
||||
"/profile/user",
|
||||
{
|
||||
"action": "edit",
|
||||
"phone_numbers": "000-000-000",
|
||||
"phone_numbers-0": "000-000-000",
|
||||
"csrf_token": res.form["csrf_token"].value,
|
||||
},
|
||||
)
|
||||
|
@ -292,7 +292,7 @@ def test_admin_bad_request(testclient, logged_moderator):
|
|||
def test_bad_email(testclient, logged_user):
|
||||
res = testclient.get("/profile/user", status=200)
|
||||
|
||||
res.form["emails"] = "john@doe.com"
|
||||
res.form["emails-0"] = "john@doe.com"
|
||||
|
||||
res = res.form.submit(name="action", value="edit").follow()
|
||||
|
||||
|
@ -300,7 +300,7 @@ def test_bad_email(testclient, logged_user):
|
|||
|
||||
res = testclient.get("/profile/user", status=200)
|
||||
|
||||
res.form["emails"] = "yolo"
|
||||
res.form["emails-0"] = "yolo"
|
||||
|
||||
res = res.form.submit(name="action", value="edit", status=200)
|
||||
|
||||
|
@ -320,3 +320,31 @@ def test_surname_is_mandatory(testclient, logged_user):
|
|||
logged_user.reload()
|
||||
|
||||
assert ["Doe"] == logged_user.family_name
|
||||
|
||||
|
||||
def test_formcontrol(testclient, logged_user):
|
||||
res = testclient.get("/profile/user")
|
||||
assert "emails-1" not in res.form.fields
|
||||
|
||||
res = res.form.submit(status=200, name="fieldlist_add", value="emails-0")
|
||||
assert "emails-1" in res.form.fields
|
||||
|
||||
|
||||
def test_formcontrol_htmx(testclient, logged_user):
|
||||
res = testclient.get("/profile/user")
|
||||
data = {
|
||||
field: res.form[field].value
|
||||
for field in res.form.fields
|
||||
if len(res.form.fields.get(field)) == 1
|
||||
}
|
||||
data["fieldlist_add"] = "emails-0"
|
||||
response = testclient.post(
|
||||
"/profile/user",
|
||||
data,
|
||||
headers={
|
||||
"HX-Request": "true",
|
||||
"HX-Trigger-Name": "listfield_add",
|
||||
},
|
||||
)
|
||||
assert "emails-0" in response.text
|
||||
assert "emails-1" in response.text
|
||||
|
|
|
@ -108,7 +108,7 @@ def test_photo_on_profile_creation(testclient, jpeg_photo, logged_admin):
|
|||
res.form["photo"] = Upload("logo.jpg", jpeg_photo)
|
||||
res.form["user_name"] = "foobar"
|
||||
res.form["family_name"] = "Abitbol"
|
||||
res.form["emails"] = "george@abitbol.com"
|
||||
res.form["emails-0"] = "george@abitbol.com"
|
||||
res = res.form.submit(name="action", value="edit", status=302).follow(status=200)
|
||||
|
||||
user = models.User.get_from_login("foobar")
|
||||
|
@ -126,7 +126,7 @@ def test_photo_deleted_on_profile_creation(testclient, jpeg_photo, logged_admin)
|
|||
res.form["photo_delete"] = True
|
||||
res.form["user_name"] = "foobar"
|
||||
res.form["family_name"] = "Abitbol"
|
||||
res.form["emails"] = "george@abitbol.com"
|
||||
res.form["emails-0"] = "george@abitbol.com"
|
||||
res = res.form.submit(name="action", value="edit", status=302).follow(status=200)
|
||||
|
||||
user = models.User.get_from_login("foobar")
|
||||
|
|
Loading…
Reference in a new issue