From 513fcb458589efeef81451922fd54c363b056d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=99=E6=B0=B8=E5=BC=BA?= <11704063+s-yongqiang@user.noreply.gitee.com> Date: Fri, 14 Jun 2024 17:53:37 +0800 Subject: [PATCH 1/9] send emails to new device login user --- seahub/api2/utils.py | 13 +++++++++++ seahub/auth/views.py | 17 +++++++++++++- .../registration/new_device_login_email.html | 22 +++++++++++++++++++ .../registration/password_change_email.html | 20 +++++++++++++++++ 4 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 seahub/templates/registration/new_device_login_email.html create mode 100644 seahub/templates/registration/password_change_email.html diff --git a/seahub/api2/utils.py b/seahub/api2/utils.py index 6c5f35218ab..0b758337e33 100644 --- a/seahub/api2/utils.py +++ b/seahub/api2/utils.py @@ -34,6 +34,8 @@ from seahub.utils.mail import send_html_email_with_dj_template from django.utils.translation import gettext as _ from seahub.settings import SECRET_KEY +from seahub.utils import send_html_email +from seahub.utils import get_site_name logger = logging.getLogger(__name__) @@ -207,6 +209,17 @@ def get_token_v2(request, username, platform, device_id, device_name, raise serializers.ValidationError('invalid device id') else: raise serializers.ValidationError('invalid platform') + + try: + TokenV2.objects.get(user=username, device_id=device_id) + except TokenV2.DoesNotExist: + email_template_name='registration/new_device_login_email.html' + send_to = email2contact_email(username) + site_name = get_site_name() + c = {'email': send_to} + send_html_email(_("New Device Login on %s") % site_name, + email_template_name, c, None, + [send_to]) return TokenV2.objects.get_or_create_token( username, platform, device_id, device_name, diff --git a/seahub/auth/views.py b/seahub/auth/views.py index ef95a11ce7d..cbd71253013 100644 --- a/seahub/auth/views.py +++ b/seahub/auth/views.py @@ -50,6 +50,10 @@ from seahub.onlyoffice.settings import ONLYOFFICE_DESKTOP_EDITOR_HTTP_USER_AGENT +from seahub.utils import send_html_email +from django.utils.translation import gettext_lazy as _ +from seahub.base.templatetags.seahub_tags import email2contact_email + # Get an instance of a logger logger = logging.getLogger(__name__) @@ -107,7 +111,8 @@ def login(request, template_name='registration/login.html', return HttpResponseRedirect(reverse(redirect_if_logged_in)) ip = get_remote_ip(request) - + print('ip',ip) + print(request.headers.get('User-Agent',None)) if request.method == "POST": login = request.POST.get('login', '').strip() failed_attempt = get_login_failed_attempts(username=login, ip=ip) @@ -482,6 +487,16 @@ def password_change(request, template_name='registration/password_change_form.ht if form.is_valid(): form.save() + email_template_name = 'registration/password_change_email.html' + send_to = email2contact_email(request.user.username) + site_name = get_site_name() + c = { + 'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S') + } + send_html_email(_("Successfully Changed Password on %s") % site_name, + email_template_name, c, None, + [send_to]) + if request.session.get('force_passwd_change', False): del request.session['force_passwd_change'] UserOptions.objects.unset_force_passwd_change( diff --git a/seahub/templates/registration/new_device_login_email.html b/seahub/templates/registration/new_device_login_email.html new file mode 100644 index 00000000000..fa1e9a9e4e8 --- /dev/null +++ b/seahub/templates/registration/new_device_login_email.html @@ -0,0 +1,22 @@ +{% extends 'email_base.html' %} + +{% load i18n %} + +{% block email_con %} + +{% autoescape off %} + +
{% trans "Hi," %}
+ ++{% blocktrans with account=email %}You are attempting to log in to your account {{ account }} on {{ site_name }} using a new device{% endblocktrans %} +
+ + ++{% trans "If you have not attempted to login with a new device, please change your password as soon as possible." %} +
+ +{% endautoescape %} + +{% endblock %} diff --git a/seahub/templates/registration/password_change_email.html b/seahub/templates/registration/password_change_email.html new file mode 100644 index 00000000000..6c035893a72 --- /dev/null +++ b/seahub/templates/registration/password_change_email.html @@ -0,0 +1,20 @@ +{% extends 'email_base.html' %} + +{% load i18n %} + +{% block email_con %} + +{% autoescape off %} + +{% trans "Hi," %}
+ ++{% blocktrans with account=email %}You submitted a password change request on {{ time }}. {% endblocktrans %} +
++{% trans "You have successfully changed your password!" %} +
+ +{% endautoescape %} + +{% endblock %} From 96b59b7e3d9683b235ded8589249b7a5e1fd4528 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=99=E6=B0=B8=E5=BC=BA?= <11704063+s-yongqiang@user.noreply.gitee.com> Date: Thu, 8 Aug 2024 15:24:21 +0800 Subject: [PATCH 2/9] update --- seahub/api2/endpoints/user.py | 13 +++++++++++-- seahub/auth/views.py | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/seahub/api2/endpoints/user.py b/seahub/api2/endpoints/user.py index be913aee466..89bd39f373d 100644 --- a/seahub/api2/endpoints/user.py +++ b/seahub/api2/endpoints/user.py @@ -1,5 +1,6 @@ # Copyright (c) 2012-2016 Seafile Ltd. import logging +from datetime import datetime from rest_framework import status from rest_framework.authentication import SessionAuthentication @@ -16,7 +17,7 @@ from seahub.organizations.settings import ORG_AUTO_URL_PREFIX from seahub.organizations.views import gen_org_url_prefix from seahub.password_session import update_session_auth_hash -from seahub.utils import is_valid_email +from seahub.utils import is_valid_email, send_html_email, get_site_name from seahub.api2.authentication import TokenAuthentication from seahub.api2.throttling import UserRateThrottle from seahub.api2.utils import api_error @@ -245,7 +246,15 @@ def post(self, request): user.set_password(new_password) user.save() - + email_template_name = 'registration/password_change_email.html' + send_to = email2contact_email(request.user.username) + site_name = get_site_name() + c = { + 'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S') + } + send_html_email(_("Successfully Changed Password on %s") % site_name, + email_template_name, c, None, + [send_to]) if not request.session.is_empty(): # update session auth hash update_session_auth_hash(request, request.user) diff --git a/seahub/auth/views.py b/seahub/auth/views.py index cbd71253013..bfd9afeb1d5 100644 --- a/seahub/auth/views.py +++ b/seahub/auth/views.py @@ -486,7 +486,7 @@ def password_change(request, template_name='registration/password_change_form.ht form = password_change_form(user=request.user, data=request.POST) if form.is_valid(): form.save() - + print('进入') email_template_name = 'registration/password_change_email.html' send_to = email2contact_email(request.user.username) site_name = get_site_name() From b85dd6b829f5843712013e971425a19f0d323dee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=99=E6=B0=B8=E5=BC=BA?= <11704063+s-yongqiang@user.noreply.gitee.com> Date: Tue, 13 Aug 2024 17:11:47 +0800 Subject: [PATCH 3/9] update --- seahub/auth/views.py | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/seahub/auth/views.py b/seahub/auth/views.py index bfd9afeb1d5..b163bdd7332 100644 --- a/seahub/auth/views.py +++ b/seahub/auth/views.py @@ -43,6 +43,7 @@ from seahub.utils.user_permissions import get_user_role from seahub.utils.auth import get_login_bg_image_path from seahub.organizations.models import OrgSAMLConfig +from seahub.sysadmin_extra.models import UserLoginLog from constance import config @@ -77,7 +78,16 @@ def log_user_in(request, user, redirect_to): # Okay, security checks complete. Log the user in. auth_login(request, user) - + # if UserLoginLog.objects.filter(username=user.username).count() == 1: + # email_template_name = 'registration/password_change_email.html' + # send_to = email2contact_email(request.user.username) + # site_name = get_site_name() + # c = { + # 'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S') + # } + # send_html_email(_("Successfully Changed Password on %s") % site_name, + # email_template_name, c, None, + # [send_to]) return HttpResponseRedirect(redirect_to) def _handle_login_form_valid(request, user, redirect_to, remember_me): @@ -111,15 +121,12 @@ def login(request, template_name='registration/login.html', return HttpResponseRedirect(reverse(redirect_if_logged_in)) ip = get_remote_ip(request) - print('ip',ip) - print(request.headers.get('User-Agent',None)) if request.method == "POST": login = request.POST.get('login', '').strip() failed_attempt = get_login_failed_attempts(username=login, ip=ip) remember_me = True if request.POST.get('remember_me', '') == 'on' else False redirect_to = request.POST.get(redirect_field_name, '') or redirect_to - # check the form used_captcha_already = False if bool(config.FREEZE_USER_ON_LOGIN_FAILED) is True: @@ -130,7 +137,6 @@ def login(request, template_name='registration/login.html', used_captcha_already = True else: form = authentication_form(data=request.POST) - if form.is_valid(): return _handle_login_form_valid(request, form.get_user(), redirect_to, remember_me) @@ -486,16 +492,6 @@ def password_change(request, template_name='registration/password_change_form.ht form = password_change_form(user=request.user, data=request.POST) if form.is_valid(): form.save() - print('进入') - email_template_name = 'registration/password_change_email.html' - send_to = email2contact_email(request.user.username) - site_name = get_site_name() - c = { - 'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S') - } - send_html_email(_("Successfully Changed Password on %s") % site_name, - email_template_name, c, None, - [send_to]) if request.session.get('force_passwd_change', False): del request.session['force_passwd_change'] From 062f7e929d53b12867fa375c9392f4574d848403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=99=E6=B0=B8=E5=BC=BA?= <11704063+s-yongqiang@user.noreply.gitee.com> Date: Wed, 14 Aug 2024 13:59:27 +0800 Subject: [PATCH 4/9] Update notification content --- seahub/api2/endpoints/user.py | 11 ++++++--- seahub/api2/utils.py | 18 +++++++------- seahub/auth/views.py | 24 +++++++++++-------- .../registration/browse_login_email.html | 20 ++++++++++++++++ .../registration/new_device_login_email.html | 5 ++-- .../registration/password_change_email.html | 7 ++---- 6 files changed, 55 insertions(+), 30 deletions(-) create mode 100644 seahub/templates/registration/browse_login_email.html diff --git a/seahub/api2/endpoints/user.py b/seahub/api2/endpoints/user.py index 89bd39f373d..419302ee75a 100644 --- a/seahub/api2/endpoints/user.py +++ b/seahub/api2/endpoints/user.py @@ -250,11 +250,16 @@ def post(self, request): send_to = email2contact_email(request.user.username) site_name = get_site_name() c = { + 'email': send_to, 'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S') } - send_html_email(_("Successfully Changed Password on %s") % site_name, - email_template_name, c, None, - [send_to]) + try: + send_html_email(_("Successfully Changed Password on %s") % site_name, + email_template_name, c, None, + [send_to]) + except Exception as e: + logger.error('Failed to send notification to %s' % send_to) + if not request.session.is_empty(): # update session auth hash update_session_auth_hash(request, request.user) diff --git a/seahub/api2/utils.py b/seahub/api2/utils.py index 0b758337e33..8678477d15a 100644 --- a/seahub/api2/utils.py +++ b/seahub/api2/utils.py @@ -34,8 +34,7 @@ from seahub.utils.mail import send_html_email_with_dj_template from django.utils.translation import gettext as _ from seahub.settings import SECRET_KEY -from seahub.utils import send_html_email -from seahub.utils import get_site_name +from seahub.utils import send_html_email, get_site_name logger = logging.getLogger(__name__) @@ -209,17 +208,18 @@ def get_token_v2(request, username, platform, device_id, device_name, raise serializers.ValidationError('invalid device id') else: raise serializers.ValidationError('invalid platform') - - try: - TokenV2.objects.get(user=username, device_id=device_id) - except TokenV2.DoesNotExist: + + if not TokenV2.objects.filter(user=username, device_id=device_id).first(): email_template_name='registration/new_device_login_email.html' send_to = email2contact_email(username) site_name = get_site_name() c = {'email': send_to} - send_html_email(_("New Device Login on %s") % site_name, - email_template_name, c, None, - [send_to]) + try: + send_html_email(_("New Device Login on %s") % site_name, + email_template_name, c, None, + [send_to]) + except Exception as e: + logger.error('Failed to send notification to %s' % send_to) return TokenV2.objects.get_or_create_token( username, platform, device_id, device_name, diff --git a/seahub/auth/views.py b/seahub/auth/views.py index b163bdd7332..27084d44c25 100644 --- a/seahub/auth/views.py +++ b/seahub/auth/views.py @@ -78,16 +78,20 @@ def log_user_in(request, user, redirect_to): # Okay, security checks complete. Log the user in. auth_login(request, user) - # if UserLoginLog.objects.filter(username=user.username).count() == 1: - # email_template_name = 'registration/password_change_email.html' - # send_to = email2contact_email(request.user.username) - # site_name = get_site_name() - # c = { - # 'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S') - # } - # send_html_email(_("Successfully Changed Password on %s") % site_name, - # email_template_name, c, None, - # [send_to]) + if UserLoginLog.objects.filter(username=user.username, login_success=1).count() == 1: + email_template_name = 'registration/browse_login_email.html' + send_to = email2contact_email(request.user.username) + site_name = get_site_name() + c = { + 'email': send_to + } + try: + send_html_email(_("%s account login reminder") % site_name, + email_template_name, c, None, + [send_to]) + except Exception as e: + logger.error(e) + return HttpResponseRedirect(redirect_to) def _handle_login_form_valid(request, user, redirect_to, remember_me): diff --git a/seahub/templates/registration/browse_login_email.html b/seahub/templates/registration/browse_login_email.html new file mode 100644 index 00000000000..9b90f9f436c --- /dev/null +++ b/seahub/templates/registration/browse_login_email.html @@ -0,0 +1,20 @@ +{% extends 'email_base.html' %} + +{% load i18n %} + +{% block email_con %} + +{% autoescape off %} + +{% trans "Hi," %}
+ ++{% blocktrans with account=email %}You are currently logging into this site using a browser{% endblocktrans %} +
++{{ email }} +
+ +{% endautoescape %} + +{% endblock %} diff --git a/seahub/templates/registration/new_device_login_email.html b/seahub/templates/registration/new_device_login_email.html index fa1e9a9e4e8..343e5c1e473 100644 --- a/seahub/templates/registration/new_device_login_email.html +++ b/seahub/templates/registration/new_device_login_email.html @@ -9,12 +9,11 @@{% trans "Hi," %}
-{% blocktrans with account=email %}You are attempting to log in to your account {{ account }} on {{ site_name }} using a new device{% endblocktrans %} +{% blocktrans with account=email %}You are trying to log in to your account with a new device {{ account }}{% endblocktrans %}
--{% trans "If you have not attempted to login with a new device, please change your password as soon as possible." %} +{% trans "If you do not have this operation, please change your password as soon as possible." %}
{% endautoescape %} diff --git a/seahub/templates/registration/password_change_email.html b/seahub/templates/registration/password_change_email.html index 6c035893a72..00f17daa075 100644 --- a/seahub/templates/registration/password_change_email.html +++ b/seahub/templates/registration/password_change_email.html @@ -4,17 +4,14 @@ {% block email_con %} -{% autoescape off %} -{% trans "Hi," %}
-{% blocktrans with account=email %}You submitted a password change request on {{ time }}. {% endblocktrans %} +{% blocktrans with account=email %}Your password was changed. {% endblocktrans %}
-{% trans "You have successfully changed your password!" %} +{{ email }}
-{% endautoescape %} {% endblock %} From 9f662cb190632421be97064d721326055746bdd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=99=E6=B0=B8=E5=BC=BA?= <11704063+s-yongqiang@user.noreply.gitee.com> Date: Fri, 16 Aug 2024 09:48:19 +0800 Subject: [PATCH 5/9] add user config --- .../components/user-settings/email-notice.js | 64 +++++++++++++++++-- frontend/src/pages/dashboard/activity-item.js | 4 +- frontend/src/utils/user-api.js | 12 ++++ seahub/api2/endpoints/user.py | 30 +++++---- seahub/api2/utils.py | 5 +- seahub/api2/views.py | 23 +++++++ seahub/auth/__init__.py | 4 ++ seahub/auth/views.py | 5 +- seahub/options/models.py | 32 +++++++++- .../templates/profile/set_profile_react.html | 2 + seahub/profile/views.py | 5 ++ 11 files changed, 160 insertions(+), 26 deletions(-) diff --git a/frontend/src/components/user-settings/email-notice.js b/frontend/src/components/user-settings/email-notice.js index 286b603ed52..1d3d96a7bcd 100644 --- a/frontend/src/components/user-settings/email-notice.js +++ b/frontend/src/components/user-settings/email-notice.js @@ -1,12 +1,15 @@ import React from 'react'; import { gettext } from '../../utils/constants'; -import { seafileAPI } from '../../utils/seafile-api'; +import { userAPI } from '../../utils/user-api'; import { Utils } from '../../utils/utils'; import toaster from '../toast'; const { fileUpdatesEmailInterval, - collaborateEmailInterval + collaborateEmailInterval, + enableLoginEmail, + enablePasswordUpdateEmail, + } = window.app.pageOptions; class EmailNotice extends React.Component { @@ -28,9 +31,21 @@ class EmailNotice extends React.Component { { interval: 3600, text: gettext('Per hour') + ' (' + gettext('If notifications have not been read within one hour, they will be sent to your mailbox.') + ')' } ]; + this.passwordOption = [ + { enabled: 0, text: gettext('Don\'t send emails') }, + { enabled: 1, text: gettext('Send email after changing password') } + ]; + + this.loginOption = [ + { enabled: 0, text: gettext('Don\'t send emails') }, + { enabled: 1, text: gettext('Send an email when a new device or browser logs in for the first time') } + ]; + this.state = { fileUpdatesEmailInterval: fileUpdatesEmailInterval, - collaborateEmailInterval: collaborateEmailInterval + collaborateEmailInterval: collaborateEmailInterval, + enableLoginEmail: enableLoginEmail, + enablePasswordUpdateEmail: enablePasswordUpdateEmail }; } @@ -50,10 +65,26 @@ class EmailNotice extends React.Component { } }; + inputPasswordEmailEnabledChange = (e) => { + if (e.target.checked) { + this.setState({ + enablePasswordUpdateEmail: parseInt(e.target.value) + }); + } + }; + + inputLoginEmailEnabledChange = (e) => { + if (e.target.checked) { + this.setState({ + enableLoginEmail: parseInt(e.target.value) + }); + } + }; + formSubmit = (e) => { e.preventDefault(); - let { fileUpdatesEmailInterval, collaborateEmailInterval } = this.state; - seafileAPI.updateEmailNotificationInterval(fileUpdatesEmailInterval, collaborateEmailInterval).then((res) => { + let { fileUpdatesEmailInterval, collaborateEmailInterval, enablePasswordUpdateEmail, enableLoginEmail } = this.state; + userAPI.updateEmailNotificationInterval(fileUpdatesEmailInterval, collaborateEmailInterval, enablePasswordUpdateEmail, enableLoginEmail).then((res) => { toaster.success(gettext('Success')); }).catch((error) => { let errorMsg = Utils.getErrorMsg(error); @@ -62,7 +93,7 @@ class EmailNotice extends React.Component { }; render() { - const { fileUpdatesEmailInterval, collaborateEmailInterval } = this.state; + const { fileUpdatesEmailInterval, collaborateEmailInterval, enableLoginEmail, enablePasswordUpdateEmail } = this.state; return ({gettext('Send a mail as soon as a new device or browser has signed into the account (like google and many other services do).')}
+ {this.loginOption.map((item, index) => { + return ( +{gettext('Send a mail as soon as a new device or browser has signed into the account (like google and many other services do).')}
+{% trans "Hi," %}
- --{% blocktrans with account=email %}You are currently logging into this site using a browser{% endblocktrans %} -
--{{ email }} -
- -{% endautoescape %} - -{% endblock %} diff --git a/seahub/templates/registration/login_email.html b/seahub/templates/registration/login_email.html new file mode 100644 index 00000000000..b0dcbb6443e --- /dev/null +++ b/seahub/templates/registration/login_email.html @@ -0,0 +1,21 @@ +{% extends 'email_base.html' %} + +{% load i18n %} + +{% block email_con %} + +{% autoescape off %} + ++{% blocktrans with account=name %}Dear, {{ account }}{% endblocktrans %} +
++Greetings! +
++{% trans " We are thrilled to inform you that you have successfully joined Seafile - a cloud-based platform dedicated to file management and team collaboration. Here, you'll find seamless and secure digital workspaces for document sharing, version control, and teamwork." %} +
+ +{% endautoescape %} + +{% endblock %} diff --git a/seahub/templates/registration/new_device_login_email.html b/seahub/templates/registration/new_device_login_email.html deleted file mode 100644 index 343e5c1e473..00000000000 --- a/seahub/templates/registration/new_device_login_email.html +++ /dev/null @@ -1,21 +0,0 @@ -{% extends 'email_base.html' %} - -{% load i18n %} - -{% block email_con %} - -{% autoescape off %} - -{% trans "Hi," %}
- --{% blocktrans with account=email %}You are trying to log in to your account with a new device {{ account }}{% endblocktrans %} -
- --{% trans "If you do not have this operation, please change your password as soon as possible." %} -
- -{% endautoescape %} - -{% endblock %} From 36b52bc049afed1a16dd7c3b3040a7c286f4c87d Mon Sep 17 00:00:00 2001 From: r350178982 <32759763+r350178982@users.noreply.github.com> Date: Tue, 20 Aug 2024 15:31:12 +0800 Subject: [PATCH 8/9] update --- seahub/api2/endpoints/user.py | 10 ++++--- seahub/api2/utils.py | 27 ++++++++----------- seahub/auth/utils.py | 22 +++++++++++++-- seahub/auth/views.py | 20 ++++---------- .../templates/registration/login_email.html | 6 ++++- .../registration/password_change_email.html | 14 +++++++--- 6 files changed, 58 insertions(+), 41 deletions(-) diff --git a/seahub/api2/endpoints/user.py b/seahub/api2/endpoints/user.py index 8c5a13c893d..c9f7a37141d 100644 --- a/seahub/api2/endpoints/user.py +++ b/seahub/api2/endpoints/user.py @@ -16,7 +16,7 @@ from seahub.organizations.settings import ORG_AUTO_URL_PREFIX from seahub.organizations.views import gen_org_url_prefix from seahub.password_session import update_session_auth_hash -from seahub.utils import is_valid_email, send_html_email, get_site_name +from seahub.utils import is_valid_email, send_html_email, get_site_name, IS_EMAIL_CONFIGURED from seahub.api2.authentication import TokenAuthentication from seahub.api2.throttling import UserRateThrottle from seahub.api2.utils import api_error @@ -248,15 +248,17 @@ def post(self, request): user.set_password(new_password) user.save() enable_pwd_email = bool(UserOptions.objects.get_password_update_email_enable_status(user.username)) - if enable_pwd_email: + + if IS_EMAIL_CONFIGURED and enable_pwd_email: email_template_name = 'registration/password_change_email.html' send_to = email2contact_email(request.user.username) site_name = get_site_name() c = { - 'email': send_to + 'email': send_to, + 'name': email2nickname(user.username) } try: - send_html_email(_("Successfully Changed Password on %s") % site_name, + send_html_email(_("[%s]Your Password Has Been Successfully Updated") % site_name, email_template_name, c, None, [send_to]) except Exception as e: diff --git a/seahub/api2/utils.py b/seahub/api2/utils.py index 6edd77cd350..63223a4df6e 100644 --- a/seahub/api2/utils.py +++ b/seahub/api2/utils.py @@ -22,6 +22,7 @@ get_group, seafserv_threaded_rpc from pysearpc import SearpcError +from seahub.auth.utils import send_login_email from seahub.base.templatetags.seahub_tags import email2nickname, \ translate_seahub_time, file_icon_filter, email2contact_email from seahub.constants import REPO_TYPE_WIKI @@ -30,7 +31,7 @@ from seahub.api2.models import Token, TokenV2, DESKTOP_PLATFORMS from seahub.avatar.settings import AVATAR_DEFAULT_SIZE from seahub.avatar.templatetags.avatar_tags import api_avatar_url -from seahub.utils import get_user_repos +from seahub.utils import get_user_repos, IS_EMAIL_CONFIGURED from seahub.utils.mail import send_html_email_with_dj_template from django.utils.translation import gettext as _ from seahub.settings import SECRET_KEY @@ -190,6 +191,7 @@ def get_token_v1(username): return token _ANDROID_DEVICE_ID_PATTERN = re.compile('^[a-f0-9]{1,16}$') + def get_token_v2(request, username, platform, device_id, device_name, client_version, platform_version): @@ -210,23 +212,16 @@ def get_token_v2(request, username, platform, device_id, device_name, else: raise serializers.ValidationError('invalid platform') enable_new_device_email = bool(UserOptions.objects.get_login_email_enable_status(username)) - if not TokenV2.objects.filter(user=username, device_id=device_id).first() and enable_new_device_email: - email_template_name='registration/login_email.html' - send_to = email2contact_email(username) - site_name = get_site_name() - c = { - 'name': email2nickname(username) - } - try: - send_html_email(_("Welcome to %s") % site_name, - email_template_name, c, None, - [send_to]) - except Exception as e: - logger.error('Failed to send notification to %s' % send_to) - - return TokenV2.objects.get_or_create_token( + + has_device = TokenV2.objects.filter(user=username, device_id=device_id, platform=platform).first() + token = TokenV2.objects.get_or_create_token( username, platform, device_id, device_name, client_version, platform_version, get_client_ip(request)) + + if IS_EMAIL_CONFIGURED and enable_new_device_email and (not has_device): + send_login_email(username) + + return token def get_api_token(request, keys=None, key_prefix='shib_'): diff --git a/seahub/auth/utils.py b/seahub/auth/utils.py index 893e8ed4257..6bd101fb7f2 100644 --- a/seahub/auth/utils.py +++ b/seahub/auth/utils.py @@ -1,13 +1,15 @@ # Copyright (c) 2012-2016 Seafile Ltd. +import logging from django.core.cache import cache from django.conf import settings +from django.utils.translation import gettext as _ from seahub.profile.models import Profile -from seahub.utils import normalize_cache_key +from seahub.utils import normalize_cache_key, get_site_name, send_html_email from seahub.utils.ip import get_remote_ip LOGIN_ATTEMPT_PREFIX = 'UserLoginAttempt_' - +logger = logging.getLogger(__name__) def get_login_failed_attempts(username=None, ip=None): """Get login failed attempts base on username and ip. @@ -84,3 +86,19 @@ def get_virtual_id_by_email(email): return email else: return p.user + + +def send_login_email(username): + from seahub.base.templatetags.seahub_tags import email2contact_email, email2nickname + email_template_name = 'registration/login_email.html' + send_to = email2contact_email(username) + site_name = get_site_name() + c = { + 'name': email2nickname(username) + } + try: + send_html_email(_("Welcome to %s") % site_name, + email_template_name, c, None, + [send_to]) + except Exception as e: + logger.error('Failed to send notification to %s, %s' % (send_to, e)) diff --git a/seahub/auth/views.py b/seahub/auth/views.py index a892eecfdd5..ea6ab92e6eb 100644 --- a/seahub/auth/views.py +++ b/seahub/auth/views.py @@ -29,12 +29,12 @@ from seahub.auth.tokens import default_token_generator from seahub.auth.utils import ( get_login_failed_attempts, incr_login_failed_attempts, - clear_login_failed_attempts) + clear_login_failed_attempts, send_login_email) from seahub.base.accounts import User, UNUSABLE_PASSWORD from seahub.options.models import UserOptions from seahub.profile.models import Profile from seahub.two_factor.views.login import is_device_remembered -from seahub.utils import render_error, get_site_name, is_valid_email, get_service_url +from seahub.utils import render_error, get_site_name, is_valid_email, get_service_url, IS_EMAIL_CONFIGURED from seahub.utils.http import rate_limit from seahub.utils.ip import get_remote_ip from seahub.utils.file_size import get_quota_from_string @@ -79,19 +79,9 @@ def log_user_in(request, user, redirect_to): auth_login(request, user) enable_login_email = bool(UserOptions.objects.get_login_email_enable_status(user.username)) already_login_users = request.session.get(SESSION_USERS_LOGIN, []) - if user.username not in already_login_users and enable_login_email: - email_template_name = 'registration/login_email.html' - send_to = email2contact_email(request.user.username) - site_name = get_site_name() - c = { - 'name': email2nickname(user.username) - } - try: - send_html_email(_("Welcome to %s") % site_name, - email_template_name, c, None, - [send_to]) - except Exception as e: - logger.error(e) + + if IS_EMAIL_CONFIGURED and (user.username not in already_login_users) and enable_login_email: + send_login_email(user.username) return HttpResponseRedirect(redirect_to) diff --git a/seahub/templates/registration/login_email.html b/seahub/templates/registration/login_email.html index b0dcbb6443e..6117cda9890 100644 --- a/seahub/templates/registration/login_email.html +++ b/seahub/templates/registration/login_email.html @@ -10,10 +10,14 @@ {% blocktrans with account=name %}Dear, {{ account }}{% endblocktrans %}+{% blocktrans %} Greetings! +{% endblocktrans %}
-{% trans " We are thrilled to inform you that you have successfully joined Seafile - a cloud-based platform dedicated to file management and team collaboration. Here, you'll find seamless and secure digital workspaces for document sharing, version control, and teamwork." %} +{% blocktrans %} + We are thrilled to inform you that you have successfully joined {{ site_name }} - a cloud-based platform dedicated to file management and team collaboration. Here, you'll find seamless and secure digital workspaces for document sharing, version control, and teamwork. +{% endblocktrans %}
{% endautoescape %} diff --git a/seahub/templates/registration/password_change_email.html b/seahub/templates/registration/password_change_email.html index 00f17daa075..85986770902 100644 --- a/seahub/templates/registration/password_change_email.html +++ b/seahub/templates/registration/password_change_email.html @@ -4,14 +4,22 @@ {% block email_con %} -{% trans "Hi," %}
+{% autoescape off %}-{% blocktrans with account=email %}Your password was changed. {% endblocktrans %} +{% blocktrans with account=name %}Dear, {{ account }}{% endblocktrans %}
-{{ email }} +{% blocktrans %} +Greetings! +{% endblocktrans %} +
++{% blocktrans %} + We are pleased to inform you that your password for {{ site_name }} has been successfully updated. To ensure the security of your account, we recommend regularly changing your password and avoiding simple or personally identifiable combinations. +{% endblocktrans %}
+{% endautoescape %} {% endblock %} From 87dda2e31b849f2f8b98ef4646fee6006da2ee46 Mon Sep 17 00:00:00 2001 From: r350178982 <32759763+r350178982@users.noreply.github.com> Date: Tue, 20 Aug 2024 15:46:34 +0800 Subject: [PATCH 9/9] code-optimize --- frontend/src/components/user-settings/email-notice.js | 2 +- frontend/src/utils/user-api.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/user-settings/email-notice.js b/frontend/src/components/user-settings/email-notice.js index fd4972cb17d..7d08be191ed 100644 --- a/frontend/src/components/user-settings/email-notice.js +++ b/frontend/src/components/user-settings/email-notice.js @@ -84,7 +84,7 @@ class EmailNotice extends React.Component { formSubmit = (e) => { e.preventDefault(); let { fileUpdatesEmailInterval, collaborateEmailInterval, enablePasswordUpdateEmail, enableLoginEmail } = this.state; - userAPI.updateEmailNotificationInterval(fileUpdatesEmailInterval, collaborateEmailInterval, enablePasswordUpdateEmail, enableLoginEmail).then((res) => { + userAPI.updateEmailNotificationConfig(fileUpdatesEmailInterval, collaborateEmailInterval, enablePasswordUpdateEmail, enableLoginEmail).then((res) => { toaster.success(gettext('Success')); }).catch((error) => { let errorMsg = Utils.getErrorMsg(error); diff --git a/frontend/src/utils/user-api.js b/frontend/src/utils/user-api.js index 15207419ae2..a2477304acf 100644 --- a/frontend/src/utils/user-api.js +++ b/frontend/src/utils/user-api.js @@ -43,7 +43,7 @@ class UserAPI { return this.req.post(url, data); } - updateEmailNotificationInterval(fileUpdatesEmailInterval, collaborateEmailInterval, enablePasswordUpdateEmail, enableLoginEmail) { + updateEmailNotificationConfig(fileUpdatesEmailInterval, collaborateEmailInterval, enablePasswordUpdateEmail, enableLoginEmail) { let url = this.server + '/api2/account/info/'; let data = { 'file_updates_email_interval': fileUpdatesEmailInterval,