사용자 이메일 변경

관리자가 사용자의 이메일 주소를 변경하는 과정에 대해 조금 혼란스럽습니다.

아무래도 이해가 안 되는 부분이 몇 있고, 버그도 하나 있습니다. (그래서 #support가 아니라 #contribute:bug에 이 글을 올립니다)

관리자가 해당 사용자의 설정 페이지에서 사용자의 이메일을 변경할 때:

  • 사용자에게 이메일이 변경됨을 확인하는 이메일이 발송되지 않습니다. 대신 새 이메일 주소로 계정의 비밀번호를 설정할 수 있도록 비밀번호 재설정 이메일이 발송됩니다.
  • 사용자에게 이메일이 변경되었음을 알리는 이메일이 기존 이메일 주소로 발송됩니다.

#1 비밀번호 재설정 이메일이 발송되는 이유("계정의 비밀번호를 설정할 수 있도록"이라는 설명)를 이해하지 못하겠습니다. 비밀번호를 변경할 필요가 없는 것 아닌가요? 그리고 사용자 경험 측면에서도 혼란스럽습니다. 사용자는 비밀번호 재설정 이메일을 기대하지 않으며, 관련 안내 문구도 없이 단순히 "[포럼 이름]에서 누군가가 비밀번호 재설정을 요청했습니다"라고만 표시됩니다.

#2 그 비밀번호 재설정 이메일이 새 이메일 주소가 아니라 기존 주소로 발송됩니다.

46번째 줄의 update_user_email에서 사용자 이메일은 업데이트되지만, @user 객체가 다시 로드되지 않아 여전히 기존 이메일 주소를 포함하고 있습니다.

#3 관리자가 해당 작업을 수행하는 사용자이고, 대상 사용자가 스태프가 아닌 경우, 위의 명세에 따라 확인 이메일이 발송되지 않습니다. 그럼에도 불구하고 이메일 주소를 변경한 후 관리자는 다음과 같은 성공 메시지를 받습니다: “해당 주소로 이메일을 보냈습니다. 확인 지시 사항을 따르세요”

#4 왜 사용자가 새 이메일 주소를 확인하지 않아도 되나요? 풀 리퀘스트는 이 토픽을 참조하고 있지만, 많은 게시물이 누락된 것 같습니다. 하지만 토픽에는 여전히 "일반 사용자의 경우, 새 이메일 주소만 검증해야 합니다"라는 내용이 언급되어 있습니다. 수정: 아, #6 / #7을 참고하세요.

#5 관리자가 사용자의 이메일을 변경하는 이 과정은 일반적으로 기존 이메일 주소를 더 이상 접근할 수 없을 때 사용된다고 가정합니다. 그럼에도 왜 기존 주소로 알림이 발송되나요?

#6 이 사용자가 로그인하려고 하면 팝업이 나타납니다.

아직 로그인할 수 없습니다. 이전에 기존 이메일 주소로 활성화 이메일을 보냈습니다. 계정을 활성화하려면 해당 이메일의 지시 사항을 따르세요.

  • 그런 이메일은 발송된 적이 없습니다.
  • 기존 이메일 주소가 언급되고 있습니다.

재전송 버튼을 누르면 다음과 같이 표시됩니다.

새 이메일 주소로 활성화 이메일을 다시 보냈습니다. 도착하는 데 몇 분 정도 걸릴 수 있으니 스팸 폴더를 꼭 확인하세요.

#7 그 활성화 이메일은 실제로 새 이메일 주소로 도착하며 제목은 "새 계정 확인"입니다( "새 이메일 주소 확인"이 아닙니다).

이렇게 처리되는 것이 옳지 않나요:

새 이메일 주소로 "[관리자 이름]에 의해 이메일 주소가 변경되었습니다. 다음 링크를 클릭하여 확인하세요 [링크]."라고 명시된 이메일 한 통만 발송되어야 합니다.

수정: #8 이메일 주소는 사용자의 공개 프로필(/u/username)에서 관리자가 변경할 수 있지만, 해당 사용자의 관리자 페이지(/admin/users/id/username)에서는 변경할 수 없습니다. 이는 직관적이지 않습니다.

10개의 좋아요

@tshenry, 이 문제를 재현할 수 있을까요? 여기서 회귀가 발생한 건가요?

2개의 좋아요

현재 제가 확인하고 있는 흐름을 정리해 보겠습니다. (대부분, 혹은 전부 @RGJ가 정리한 내용과 일치합니다.)

  1. 관리자가 스태프가 아닌 사용자의 설정으로 이동하여 이메일 주소를 변경합니다:

    제출하면 관리자는 다음과 같은 메시지를 확인합니다:

    해당 주소로 이메일을 보냈습니다. 확인 지침을 따라 주세요.

  2. 위 메시지는 정확하지 않아 보입니다. 구 이메일 주소로 두 통의 이메일이 발송되기 때문입니다:

    [Demo] 이메일 주소가 변경되었습니다

    이것은 자동화된 메시지입니다.
    Demo의 이메일 주소가 변경되었음을 알려 드립니다. 실수로 변경된 경우
    사이트 관리자에게 문의해 주세요.

    이메일 주소가 다음으로 변경되었습니다:

    new@email.com

    [Demo] 비밀번호 재설정

    누군가가 Demo에서 비밀번호 재설정을 요청했습니다.

    본인이 요청하지 않은 경우, 이 이메일을 무시하셔도 됩니다.

    새 비밀번호를 설정하려면 다음 링크를 클릭하세요:
    https://example.discourse.site/u/password-reset/74d53d7d2cf20dsbc360614844c653s2

  3. 이 지점에서 세 가지 시나리오를 테스트했습니다. 각 항목은 개별 시나리오를 나타냅니다:

    • 사용자가 구 이메일에 접근할 수 있고 비밀번호 재설정 링크를 따르는 경우. 비밀번호를 업데이트하면 로그인됩니다. 이후 사용자는 사용자 이름 또는 구 이메일 주소로 로그인할 수 있습니다. 이 시점에서 새 이메일 주소가 적용된 것으로 보이지 않습니다.

    • 사용자가 사용자 이름 또는 새 이메일 주소로 로그인하려고 시도하면 다음과 같은 메시지가 표시됩니다:

      옵션 1: '재전송’을 누르면 다음 메시지가 표시됩니다. (이번에는 새 이메일 주소가 언급됩니다.)

      실제로 이메일이 새 이메일 주소로 발송됩니다:

      [Demo] 새 계정 확인

      Demo에 오신 것을 환영합니다!

      새 계정을 확인하고 활성화하려면 다음 링크를 클릭하세요:
      https://example.discourse.site/u/activate-account/74d53d7d2cf20dsbc360614844c653s2

      위 링크를 클릭할 수 없다면, 웹 브라우저의 주소창에 복사해서 붙여넣어 보세요.

      링크를 따라가면 새 계정 활성화 페이지 중 일부가 표시됩니다. 결국 사용자는 성공적으로 로그인합니다. 이 시점부터 사용자는 사용자 이름 또는 구 이메일 주소로 로그인할 수 있습니다. 이 시점에서 새 이메일 주소가 적용된 것으로 보이지 않습니다.

      옵션 2: ‘이메일 주소 변경’ 버튼을 누르면 다음과 같은 화면이 표시됩니다. 텍스트 필드에 새 이메일 주소가 입력되어 있으면 ‘이메일 주소 업데이트’ 버튼이 비활성화 상태이며, 이는 새 이메일이 이미 활성화되어 있음을 암시합니다(하지만 실제로는 그렇지 않은 것으로 보입니다).

    • 사용자가 비밀번호 재설정을 시작하는 경우. 이메일은 새 이메일 주소로 발송되며, 사용자는 링크를 통해 로그인할 수 있습니다. 다른 시나리오와 마찬가지로, 사용자는 사용자 이름 또는 구 이메일 주소로 로그인할 수 있습니다. 이 시점에서 새 이메일 주소가 적용된 것으로 보이지 않습니다.

따라서 분명히 재현 가능한 문제들이 있습니다. 명확하게 서술하기가 까다로운 부분이지만, 원 게시글과 이 개요를 통해 이해가 되길 바랍니다. 분명히 수정이 필요한 부분이 있는 것으로 보입니다.

@martin 과거에 코어의 이 부분을 다뤄 보셨다고 알고 있습니다. 시간이 나실 때 의견을 주실 수 있을까요?

9개의 좋아요

이것이 왜 회귀되었을까요? :thinking:

수정: 회귀가 발생한 것을 확인했습니다. 일반 사용자의 이메일을 수정할 때, 확인 메일 등이 기존(OLD) 이메일로 발송됩니다. 과거에는 이렇게 동작하지 않았는데…

4개의 좋아요

인용된 풀 리퀘스트 설명을 읽다가 그 불편한 익숙함을 느끼고, 범인이 바로 나였다는 사실을 깨달았을 때의 그 기분…

상세한 안내를 해 주셔서 감사합니다, @tshenry, @RGJ. 이번 주에 수정할 일 중 가장 우선순위로 처리하겠습니다.

4개의 좋아요

자, 이제 이 문제를 이해했습니다. 그리고 과거에 삭제된 댓글의 이력을 살펴보았더니, @sam이 작성한 아래 내용을 다시 떠올리게 되었습니다:

관리자 이메일 재설정 케이스는 매우 다르며, 사실상 이메일과 비밀번호를 함께 재설정하는 것입니다. 왜냐하면 사용자가 계정에 접근할 수 있다면 셀프 서비스로 모든 작업을 수행할 수 있기 때문입니다.

즉, 이메일을 변경하는 주체가 관리자이므로 비밀번호 재설정 이메일을 보내야 한다는 것입니다. 사용자가 기존 이메일에 접근할 수 있다면 그냥… 로그인해서 직접 할 수 있을 테니까요. 하지만 비밀번호 재설정 이메일은 동시에 확인 역할도 합니다. 재설정 과정을 완료하지 않으면(현재는 기존 이메일로 전송되므로 완료할 수 없습니다) 새 이메일은 "확인"되지 않으며, 이것이 바로 해당 모달이 표시되는 이유입니다:

비밀번호 재설정 이메일이 기존 주소로 전송되는 문제는 쉽게 수정할 수 있으며, 이렇게 하면 최소한 재설정 과정을 진행할 수 있는 상태로 만들 수 있습니다:

또한, 현재 비밀번호 재설정 이메일이 기존 이메일로 전송되며, 이것이 확인되면 잘못된 주소가 확인되고 사용자의 이메일이 다시 기존 이메일로 설정됩니다.

이메일을 변경하는 관리자를 위한 메시지 문구를 수정하여, 사용자가 새 이메일의 링크를 클릭하고 비밀번호를 변경해야 변경 사항이 완전히 적용된다는 점(그리고 잘못된 이메일 문제도 함께 수정)을 명확히 하겠습니다.

4개의 좋아요

잠깐요. 이게 무슨 말인지 이해가 되지 않습니다.

사용자가 이전 이메일에 접근할 수 있는 것과 사용자가 Discourse 계정에 대해 비밀번호 재설정을 필요로 하는 것 사이에는 차이가 있습니다. 전자는 후자를 절대 함축하지 않으며, 이는 완전히 다른 상황입니다.

관리자에 의한 이메일 변경의 상당수는 사용자가 방법을 모를 때나, 관리자가 email_editable = false 제한을 일시적으로 해제해야 할 때 발생합니다.

비밀번호 재설정이 이메일 확인을 겸한다는 점이 매우 혼란스럽습니다. 개인적으로는 비밀번호 재설정 메일에 응답조차 하지 않았을 것입니다. 제가 요청한 것이 아니었기 때문이죠. 또한 그것이 필수적인 확인 단계라는 사실도 인지하지 못했을 것입니다(그리고 저는 그것이 필요 없다고 생각하며, 일반적인 확인 메일만으로도 충분하다고 봅니다?).

4개의 좋아요

관련이 있을 수 있습니다:

오늘 포럼 사용자 중 한 명이 비밀번호를 재설정하려고 시도했을 때(오늘 아침 기준으로 최신 버전의 Discourse를 사용 중), 이메일은 수신했지만 이메일 링크를 클릭했을 때 오류가 발생했습니다:

여러 브라우저에서 동일한 오류가 발생하며, 애드블로커를 사용하지 않고 있습니다.

해당 사용자의 계정 설정 페이지에서 “비밀번호 재설정 이메일 보내기” 버튼을 클릭하면 거기서도 오류 메시지가 표시됩니다:

버튼 옆에 "(오류)"라고 표시되기 직전에 "(이메일 전송 중)"이라고 잠시 깜빡입니다. 하지만 이메일이 전송되지 않은 것으로 보입니다. 오늘 다른 포럼 이메일은 정상적으로 전송되는 것을 확인할 수 있습니다.

이 기능은 이전에는 정상적으로 작동했습니다… 지난주 어딘가에서 문제가 생긴 것 같습니다.

관리자로 로그인한 상태에서 웹 브라우저에서 Discourse 오류 로그를 확인해 보세요. 더 자세한 내용이 포함된 오류 보고서가 표시되어야 합니다.

에러 항목은 다음과 같습니다:

398 Job exception: The specified copy source is larger than the maximum allowable size for a copy source: 5368709120

aws-sdk-core-3.99.1/lib/seahorse/client/plugins/raise_response_errors.rb:15:in `call'

aws-sdk-s3-1.66.0/lib/aws-sdk-s3/plugins/sse_cpk.rb:22:in `call'

aws-sdk-s3-1.66.0/lib/aws-sdk-s3/plugins/dualstack.rb:26:in `call'

aws-sdk-s3-1.66.0/lib/aws-sdk-s3/plugins/accelerate.rb:35:in `call'

aws-sdk-core-3.99.1/lib/aws-sdk-core/plugins/jsonvalue_converter.rb:20:in `call'

aws-sdk-core-3.99.1/lib/aws-sdk-core/plugins/idempotency_token.rb:17:in `call'

aws-sdk-core-3.99.1/lib/aws-sdk-core/plugins/param_converter.rb:24:in `call'

aws-sdk-core-3.99.1/lib/aws-sdk-core/plugins/response_paging.rb:10:in `call'

aws-sdk-core-3.99.1/lib/seahorse/client/plugins/response_target.rb:23:in `call'

aws-sdk-core-3.99.1/lib/seahorse/client/request.rb:70:in `send_request'

aws-sdk-s3-1.66.0/lib/aws-sdk-s3/client.rb:1108:in `copy_object'

/var/www/discourse/lib/backup_restore/s3_backup_store.rb:61:in `block in vacate_legacy_prefix'

/var/www/discourse/lib/backup_restore/s3_backup_store.rb:60:in `each'

/var/www/discourse/lib/backup_restore/s3_backup_store.rb:60:in `vacate_legacy_prefix'

/var/www/discourse/app/jobs/onceoff/vacate_legacy_prefix_backups.rb:7:in `execute_onceoff'

/var/www/discourse/app/jobs/onceoff/onceoff.rb:25:in `execute'

/var/www/discourse/app/jobs/base.rb:232:in `block (2 levels) in perform'

rails_multisite-2.5.0/lib/rails_multisite/connection_management.rb:76:in `with_connection'

/var/www/discourse/app/jobs/base.rb:221:in `block in perform'

/var/www/discourse/app/jobs/base.rb:217:in `each'

/var/www/discourse/app/jobs/base.rb:217:in `perform'

sidekiq-6.1.2/lib/sidekiq/processor.rb:196:in `execute_job'

sidekiq-6.1.2/lib/sidekiq/processor.rb:164:in `block (2 levels) in process'

sidekiq-6.1.2/lib/sidekiq/middleware/chain.rb:138:in `block in invoke'

/var/www/discourse/lib/sidekiq/pausable.rb:138:in `call'

sidekiq-6.1.2/lib/sidekiq/middleware/chain.rb:140:in `block in invoke'

sidekiq-6.1.2/lib/sidekiq/middleware/chain.rb:143:in `invoke'

sidekiq-6.1.2/lib/sidekiq/processor.rb:163:in `block in process'

sidekiq-6.1.2/lib/sidekiq/processor.rb:136:in `block (6 levels) in dispatch'

sidekiq-6.1.2/lib/sidekiq/job_retry.rb:111:in `local'

sidekiq-6.1.2/lib/sidekiq/processor.rb:135:in `block (5 levels) in dispatch'

sidekiq-6.1.2/lib/sidekiq.rb:38:in `block in <module:Sidekiq>'

sidekiq-6.1.2/lib/sidekiq/processor.rb:131:in `block (4 levels) in dispatch'

sidekiq-6.1.2/lib/sidekiq/processor.rb:257:in `stats'

sidekiq-6.1.2/lib/sidekiq/processor.rb:126:in `block (3 levels) in dispatch'

sidekiq-6.1.2/lib/sidekiq/job_logger.rb:13:in `call'

sidekiq-6.1.2/lib/sidekiq/processor.rb:125:in `block (2 levels) in dispatch'

sidekiq-6.1.2/lib/sidekiq/job_retry.rb:78:in `global'

sidekiq-6.1.2/lib/sidekiq/processor.rb:124:in `block in dispatch'

sidekiq-6.1.2/lib/sidekiq/logger.rb:10:in `with'

sidekiq-6.1.2/lib/sidekiq/job_logger.rb:33:in `prepare'

sidekiq-6.1.2/lib/sidekiq/processor.rb:123:in `dispatch'

sidekiq-6.1.2/lib/sidekiq/processor.rb:162:in `process'

sidekiq-6.1.2/lib/sidekiq/processor.rb:78:in `process_one'

sidekiq-6.1.2/lib/sidekiq/processor.rb:68:in `run'

sidekiq-6.1.2/lib/sidekiq/util.rb:15:in `watchdog'

sidekiq-6.1.2/lib/sidekiq/util.rb:24:in `block in safe_thread'
1개의 좋아요

아니요, 그것은 전혀 관련이 없습니다.
로그를 지운 다음 이 오류를 발생시키고, 다시 로그를 확인해 보세요.

그런데 오류가 발생해도 로그가 여전히 비어 있습니다.

말씀하신 뜻을 이해합니다. 저 역시 어제 비밀번호 재설정이 확인 과정으로 쓰인 것에 당황했습니다. 사용자의 이메일을 변경할 때 관리자가 선택할 수 있는 부가적인 옵션으로, "사용자의 비밀번호도 함께 재설정합니다"라는 체크박스를 추가하는 것이 좋을 것 같습니다. 현재 프로세스가 완전히 깨져 있으므로, 제가 만든 수정 PR을 있는 그대로 병합하겠습니다.

@sam 님이 원래 비밀번호 재설정 플로우의 배경이 된 이유를 말씀하신 분이므로, 새로운 프로세스/플로우에 대해 의견을 내주시길 바랍니다:

  1. 관리자가 사용자의 이메일을 변경합니다. 동시에 비밀번호를 재설정할 수 있는 옵션이 있습니다.
  2. 사용자는 새 주소로 이메일 변경을 확인해 달라는 메일을 받습니다.
    • 동의(Yes)하면 이메일을 변경합니다. 그리고 이메일이 변경되었음을 알리는 메일을 이전 주소로 보냅니다.
    • 거절(No)하면 아무것도 하지 않습니다.
  3. 1번에서 관리자가 재설정을 원한다고 지정했다면, 사용자가 이메일 변경을 확인하는 즉시 새 주소로 비밀번호 재설정 메일이 전송됩니다.

이 방식이 훨씬 명확할 것 같고, 비밀번호 재설정은 이메일 변경 확인과 무관해집니다.

2개의 좋아요

네, 이 두 가지가 왜 관련이 있다고 보는지 이해가 안 됩니다.

1개의 좋아요

사람들이 반길 만한 1개의 새 병합 커밋을 확인했습니다 :smiley:

3개의 좋아요

감사합니다. 이 PR은 ‘완전히 깨진’ 상태의 문제를 수정하기 위해 병합될 예정입니다. 다른 PR이 뒤따를 것입니다!

이전 토픽에서 Sam과 논의한 결과 이렇게 처리되었습니다. 혼란을 해소하고 무관한 것들 사이의 연결을 제거하기 위해 새로운 프로세스로 진행하겠습니다.

4개의 좋아요

아래 내용을 수행하는 PR을 방금 병합했습니다:

  • 관리자 이메일 변경 사용자 플로우를 수정하여, 사용자가 변경 사항을 확인하기 위해 이메일을 받도록 했습니다.
  • 이제 이메일 변경 요청을 누가 했는지 기록합니다.
  • 요청자가 관리자이고 해당 사용자가 아니라면, 사용자에게 보내는 이메일에 이 사항을 명시합니다.
  • 또한 변경 확인 이메일 경로를匿名用户에게도 공개하여, 계정에 접근할 수 없는 상태에서도 사용자가 클릭할 수 있도록 했습니다. 로그인된 사용자가 있는 경우, 확인 정보가 현재 사용자와 일치하는지 확인합니다.

이로써 해당 프로세스가 훨씬 더 합리적으로 개선되었기를 바랍니다!

4개의 좋아요