diff options
| author | Jonas Kohl | 2024-09-19 13:37:59 +0200 | 
|---|---|---|
| committer | Jonas Kohl | 2024-09-19 13:37:59 +0200 | 
| commit | 06510101ad051c5b7bbacd6411eeb2b5c53cc3a3 (patch) | |
| tree | 0678aea9b166c2e73f14c91f9246ac0b82298098 /src | |
| parent | ea64d16f7cdb86be610d5c90c46d0185d0e839e1 (diff) | |
Email editing
Diffstat (limited to 'src')
| -rw-r--r-- | src/application/messages/de.msg | 68 | ||||
| -rw-r--r-- | src/application/mystic/forum/orm/User.php | 2 | ||||
| -rw-r--r-- | src/application/views/form_login.php | 2 | ||||
| -rw-r--r-- | src/application/views/view_user.php | 10 | ||||
| -rw-r--r-- | src/index.php | 175 | 
5 files changed, 234 insertions, 23 deletions
| diff --git a/src/application/messages/de.msg b/src/application/messages/de.msg index cac30e7..c2d8416 100644 --- a/src/application/messages/de.msg +++ b/src/application/messages/de.msg @@ -146,6 +146,9 @@ metadata({  : "Display name:"  = "Anzeigename:" +: "Password:" += "Passwort:" +  : "Choose password:"  = "Passwort festlegen:" @@ -355,7 +358,7 @@ metadata({  = "Passwort wiederholen:"  : "The password reset link is either invalid or it expired" -= "Der Link zum Password Zurücksetzen ist entweder ungültig oder abgelaufen" += "Der Link zum Zurücksetzen des Passwortes ist entweder ungültig oder abgelaufen"  : "Password reset successfully!"  = "Passwort erfolgreich zurückgesetzt!" @@ -368,7 +371,7 @@ metadata({  : "Hello, %user_display_name%!\n"    "\n" -  "a password reset has been requested successfully! Please click the link below to set a new password:\n" +  "A password reset has been requested successfully! Please click the link below to set a new password:\n"    "%reset_link%\n"    "\n"    "If this wasn't you, you can safely ignore this email. The link will only be valid for one hour.\n" @@ -377,7 +380,7 @@ metadata({    "%forum_copyright%"  = "Hallo, %user_display_name%!\n"    "\n" -  "das Zurücksetzen Ihres Passwortes wurde erfolgreich angefragt. Bitte klicken Sie auf den untenstehenden Link, um Ihr Passwort zurückzusetzen:\n" +  "Das Zurücksetzen Ihres Passwortes wurde erfolgreich angefragt. Bitte klicken Sie auf den untenstehenden Link, um Ihr Passwort zurückzusetzen:\n"    "%reset_link%\n"    "\n"    "Falls Sie dies nicht waren, können Sie diese E-Mail ignorieren. Der Link ist nur für eine Stunde gültig.\n" @@ -393,3 +396,62 @@ metadata({  : "I know my password and I want to %link%log in%/link%!"  = "Ich kenne mein Passwort und möchte mich %link%anmelden%/link%!" + +: "Hello, %user_display_name%!\n" +  "\n" +  "We are sending this email to let you know your passwort has been reset successfully!\n" +  "\n" +  "Kind regards,\n" +  "%forum_copyright%" += "Hallo, %user_display_name%!\n" +  "\n" +  "Wir senden Ihnen diese E-Mail, um Ihnen mitzuteilen, dass Ihr Passwort erfolgreich geändert wurde!\n" +  "\n" +  "Mit freundlichen Grüßen,\n" +  "%forum_copyright%" + +: "Please activate your account" += "Bitte aktivieren Sie Ihr Nutzerkonto" + +: "Email address changed" += "E-Mail-Adresse geändert" + +: "Hello, %user_display_name%!\n" +  "\n" +  "Your email address has been successfully changed from %old_email% to %new_email%!\n" +  "\n" +  "Kind regards,\n" +  "%forum_copyright%" += "Hallo, %user_display_name%!\n" +  "\n" +  "Ihre E-Mail-Adresse wurde erfolgreich von %old_email% zu %new_email% geändert!\n" +  "\n" +  "Mit freundlichen Grüßen,\n" +  "%forum_copyright%" + +: "Your email address has been changed successfully!\nPlease click %link%here%/link% to return to your profile!" += "Ihre E-Mail-Adresse wurde erfolgreich geändert!\nBitte klicken Sie %link%hier%/link%, um zu Ihrem Profil zurückzukehren!" + +: "Please verify your email first!" += "Bitte bestätigen Sie zuerst Ihre E-Mail-Adresse!" + +: "Please verify your email address" += "Bitte bestätigen Sie Ihre E-Mail-Adresse!" + +: "Hello, %user_display_name%!\n" +  "\n" +  "Please verify your new email address by clicking the link below:\n" +  "%verify_link%\n" +  "\n" +  "Kind regards,\n" +  "%forum_copyright%" += "Hallo, %user_display_name%!\n" +  "\n" +  "Bitte bestätigen Sie Ihre E-Mail-Adresse, indem Sie auf folgenden Link klicken:\n" +  "%verify_link%\n" +  "\n" +  "Mit freundlichen Grüßen,\n" +  "%forum_copyright%" + +: "Failed to send verification email" += "Konnte Bestätigungsmail nicht versenden" diff --git a/src/application/mystic/forum/orm/User.php b/src/application/mystic/forum/orm/User.php index 1bf02f1..868f385 100644 --- a/src/application/mystic/forum/orm/User.php +++ b/src/application/mystic/forum/orm/User.php @@ -17,6 +17,8 @@ class User extends Entity {      #[Unique] public string $name;      public string $displayName;      #[Unique] public string $email; +    #[Unique] public ?string $pendingEmail; +    public ?\DateTimeImmutable $pendingEmailCreated;      public \DateTimeImmutable $created;      public string $passwordHash;      public int $permissionMask; diff --git a/src/application/views/form_login.php b/src/application/views/form_login.php index acef1ff..87ee516 100644 --- a/src/application/views/form_login.php +++ b/src/application/views/form_login.php @@ -35,7 +35,7 @@ if (($_formError = RequestUtils::getAndClearFormError("login")) !== null) {  <div class="form-group">      <button class="btn btn-primary" type="submit"><?= __("Log in") ?></button> -    <a href="?_action=pwreset"><?= __("I forgot my password") ?></a> +    <a class="btn btn-link" href="?_action=pwreset"><?= __("I forgot my password") ?></a>  </div>  <div class="form-group"> diff --git a/src/application/views/view_user.php b/src/application/views/view_user.php index aba0f2f..d3ebe04 100644 --- a/src/application/views/view_user.php +++ b/src/application/views/view_user.php @@ -20,6 +20,8 @@ else  $dateJoined = DateTime::createFromImmutable($user->created);  $dateJoined->setTime(0, 0, 0, 0); + +$emailPending = $isOwnProfile && $user->pendingEmail !== null;  ?>  <div class="clearfix page-header margin-top-0"> @@ -93,7 +95,7 @@ if (($_formError = RequestUtils::getAndClearFormError("update_profile")) !== nul      <div class="form-group">          <label for="i_name"><?= __("Username:") ?></label>          <?php if ($lastNameChangeTooRecent): ?> -            <input required class="form-control" type="text" id="i_name" value="<?= htmlentities($user->name) ?>" disabled> +            <input class="form-control" type="text" id="i_name" value="<?= htmlentities($user->name) ?>" disabled>              <small class="text-danger"><strong><?= __("You can only change your username every 30 days!") ?></strong></small>          <?php else: ?>              <input required class="form-control" type="text" name="name" id="i_name" value="<?= htmlentities($user->name) ?>"> @@ -101,7 +103,11 @@ if (($_formError = RequestUtils::getAndClearFormError("update_profile")) !== nul      </div>      <div class="form-group">          <label for="i_email"><?= __("Email address:") ?></label> -        <input required class="form-control" type="email" id="i_email" value="<?= htmlentities($user->email) ?>" disabled> +        <?php if ($emailPending): ?> +            <input class="form-control" type="email" id="i_email" value="<?= htmlentities($user->email) ?>" disabled> +        <?php else: ?> +            <input required class="form-control" type="email" id="i_email" name="email" value="<?= htmlentities($user->email) ?>"> +        <?php endif; ?>      </div>      <div class="form-group">          <label><?= __("Profile picture:") ?></label> diff --git a/src/index.php b/src/index.php index 62874e6..d651400 100644 --- a/src/index.php +++ b/src/index.php @@ -441,10 +441,9 @@ if ($_action === "auth") {      $sig = $_GET["sig"] ?? throw new Exception("Missing signature");      $user = new User(); -    $user->activated = false;      $user->activationToken = $token; -    if (!$db->fetchWhere($user, [ "activated", "activation_token" ])) { +    if (!$db->fetchWhere($user, "activation_token")) {          http_response_code(400);          msg_error(__("Invalid token"));          exit; @@ -458,22 +457,101 @@ if ($_action === "auth") {          exit;      } -    $user->activated = true; -    $user->activationToken = ""; +    $isActivation = !$user->activated; +    if ($isActivation) { +        $user->activated = true; +        $user->activationToken = ""; -    if (!$db->update($user)) { -        http_response_code(400); -        msg_error(__("Failed to update user")); -        exit; -    } +        if (!$db->update($user)) { +            http_response_code(400); +            msg_error(__("Failed to update user")); +            exit; +        } -    msg_info("?!HTML::" . __( -        "Your account has been activated!\nPlease click %link%here%/link% to log in!", -        [ -            "link" => '<a href="?_action=auth">', -            "/link" => '</a>', -        ] -    )); +        msg_info("?!HTML::" . __( +            "Your account has been activated!\nPlease click %link%here%/link% to log in!", +            [ +                "link" => '<a href="?_action=auth">', +                "/link" => '</a>', +            ] +        )); +    } else { +        $oldEmail = $user->email; +        $newEmail = $user->pendingEmail; + +        $user->activationToken = ""; +        $user->email = $user->pendingEmail; +        $user->pendingEmail = null; +        $user->pendingEmailCreated = null; + +        if (!$db->update($user)) { +            http_response_code(400); +            msg_error(__("Failed to update user")); +            exit; +        } + +        $transport = Transport::fromDsn(env("MAILER_DSN")); + +        try { +            $transport->send( +                (new Email()) +                    ->from(env("MAILER_FROM")) +                    ->to(new Address($oldEmail, $user->displayName)) +                    ->text(__( +                        "Hello, %user_display_name%!\n" . +                        "\n" . +                        "Your email address has been successfully changed from %old_email% to %new_email%!\n" . +                        "\n" . +                        "Kind regards,\n" . +                        "%forum_copyright%", +                        params: [ +                            "forum_title" => (env("MYSTIC_FORUM_TITLE") ?? "Forum"), +                            "user_display_name" => $user->displayName, +                            "old_email" => $oldEmail, +                            "new_email" => $newEmail, +                            "forum_copyright" => (env("MYSTIC_FORUM_COPYRIGHT") ?? env("MYSTIC_FORUM_TITLE") ?? "Forum") +                        ] +                    )) +                    ->subject(__("Email address changed")) +            ); +        } catch (TransportException $_) { +            // fail silently +        } + +        try { +            $transport->send( +                (new Email()) +                    ->from(env("MAILER_FROM")) +                    ->to(new Address($newEmail, $user->displayName)) +                    ->text(__( +                        "Hello, %user_display_name%!\n" . +                        "\n" . +                        "Your email address has been successfully changed from %old_email% to %new_email%!\n" . +                        "\n" . +                        "Kind regards,\n" . +                        "%forum_copyright%", +                        params: [ +                            "forum_title" => (env("MYSTIC_FORUM_TITLE") ?? "Forum"), +                            "user_display_name" => $user->displayName, +                            "old_email" => $oldEmail, +                            "new_email" => $newEmail, +                            "forum_copyright" => (env("MYSTIC_FORUM_COPYRIGHT") ?? env("MYSTIC_FORUM_TITLE") ?? "Forum") +                        ] +                    )) +                    ->subject(__("Email address changed")) +            ); +        } catch (TransportException $_) { +            // fail silently +        } + +        msg_info("?!HTML::" . __( +            "Your email address has been changed successfully!\nPlease click %link%here%/link% to return to your profile!", +            [ +                "link" => '<a href="?_action=viewuser&user=' . htmlentities(urlencode($user->id)) . '">', +                "/link" => '</a>', +            ] +        )); +    }  } elseif ($_action === "logout") {      RequestUtils::unsetAuthorizedUser();      header("Location: " . ($_GET["next"] ?? ".")); @@ -766,6 +844,7 @@ if ($_action === "auth") {              $pfpAction = RequestUtils::getRequiredField("pfp_action", $formId);              $userName = $_POST["name"] ?? $user->name; +            $email = $_POST["email"] ?? $user->email;              $user->displayName = $displayName; @@ -784,6 +863,48 @@ if ($_action === "auth") {                  }              } +            if ($email !== $user->email) { +                if ($user->pendingEmailCreated !== null) { +                    RequestUtils::triggerFormError(__("Please verify your email first!"), $formId); +                } else { +                    $queryUser = new User(); +                    $queryUser->email = $email; +                    $queryUser->pendingEmail = $email; +                    if ($db->fetchWhere($queryUser, "email") || $db->fetchWhere($queryUser, "pending_email")) { +                        RequestUtils::triggerFormError(__("This email address is already in use!"), $formId); +                    } +                    $user->pendingEmail = $email; +                    $user->pendingEmailCreated = new DateTimeImmutable(); +                    $user->activationToken = $db->generateId(12); + +                    try { +                        Transport::fromDsn(env("MAILER_DSN"))->send( +                            (new Email()) +                                ->from(env("MAILER_FROM")) +                                ->to(new Address($email, $displayName)) +                                ->text(__( +                                    "Hello, %user_display_name%!\n" . +                                    "\n" . +                                    "Please verify your new email address by clicking the link below:\n" . +                                    "%verify_link%\n" . +                                    "\n" . +                                    "Kind regards,\n" . +                                    "%forum_copyright%", +                                    params: [ +                                        "forum_title" => (env("MYSTIC_FORUM_TITLE") ?? "Forum"), +                                        "user_display_name" => $displayName, +                                        "verify_link" => env("PUBLIC_URL") . "?_action=verifyemail&token=" . urlencode($user->activationToken) . "&sig=" . urlencode(base64_encode(hash("sha256", env("SECRET") . $user->activationToken . $user->id, true))), +                                        "forum_copyright" => (env("MYSTIC_FORUM_COPYRIGHT") ?? env("MYSTIC_FORUM_TITLE") ?? "Forum") +                                    ] +                                )) +                                ->subject(__("Please verify your email address")) +                        ); +                    } catch (TransportException $_) { +                        RequestUtils::triggerFormError(__("Failed to send verification email"), $formId); +                    } +                } +            } +              switch ($pfpAction) {                  case "keep":                      // Do nothing @@ -1386,6 +1507,26 @@ if ($_action === "auth") {                  RequestUtils::triggerFormError(__("Failed to update password"), $formId);              } +            Transport::fromDsn(env("MAILER_DSN"))->send( +                (new Email()) +                    ->from(env("MAILER_FROM")) +                    ->to(new Address($resetUser->email, $resetUser->displayName)) +                    ->text(__( +                        "Hello, %user_display_name%!\n" . +                        "\n" . +                        "We are sending this email to let you know your passwort has been reset successfully!\n" . +                        "\n" . +                        "Kind regards,\n" . +                        "%forum_copyright%", +                        params: [ +                            "forum_title" => (env("MYSTIC_FORUM_TITLE") ?? "Forum"), +                            "user_display_name" => $resetUser->displayName, +                            "forum_copyright" => (env("MYSTIC_FORUM_COPYRIGHT") ?? env("MYSTIC_FORUM_TITLE") ?? "Forum") +                        ] +                    )) +                    ->subject(__("Password reset successfully!")) +            ); +              msg_info(__("Password reset successfully!"), true);          } else {              $formId = "pwreset"; @@ -1403,7 +1544,7 @@ if ($_action === "auth") {                              ->text(__(                                  "Hello, %user_display_name%!\n" .                                  "\n" . -                                "a password reset has been requested successfully! Please click the link below to set a new password:\n" . +                                "A password reset has been requested successfully! Please click the link below to set a new password:\n" .                                  "%reset_link%\n" .                                  "\n" .                                  "If this wasn't you, you can safely ignore this email. The link will only be valid for one hour.\n" . |