mirror of
https://github.com/haiwen/seahub.git
synced 2025-08-11 20:01:40 +00:00
add user config
This commit is contained in:
parent
c7ed70f1c6
commit
36d293efdd
@ -1,12 +1,15 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { gettext } from '../../utils/constants';
|
import { gettext } from '../../utils/constants';
|
||||||
import { seafileAPI } from '../../utils/seafile-api';
|
import { userAPI } from '../../utils/user-api';
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
import toaster from '../toast';
|
import toaster from '../toast';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
fileUpdatesEmailInterval,
|
fileUpdatesEmailInterval,
|
||||||
collaborateEmailInterval
|
collaborateEmailInterval,
|
||||||
|
enableLoginEmail,
|
||||||
|
enablePasswordUpdateEmail,
|
||||||
|
|
||||||
} = window.app.pageOptions;
|
} = window.app.pageOptions;
|
||||||
|
|
||||||
class EmailNotice extends React.Component {
|
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.') + ')' }
|
{ 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 = {
|
this.state = {
|
||||||
fileUpdatesEmailInterval: fileUpdatesEmailInterval,
|
fileUpdatesEmailInterval: fileUpdatesEmailInterval,
|
||||||
collaborateEmailInterval: collaborateEmailInterval
|
collaborateEmailInterval: collaborateEmailInterval,
|
||||||
|
enableLoginEmail: enableLoginEmail,
|
||||||
|
enablePasswordUpdateEmail: enablePasswordUpdateEmail
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,11 +65,27 @@ 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) => {
|
formSubmit = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
let { fileUpdatesEmailInterval, collaborateEmailInterval } = this.state;
|
let { fileUpdatesEmailInterval, collaborateEmailInterval, enablePasswordUpdateEmail, enableLoginEmail } = this.state;
|
||||||
seafileAPI.updateEmailNotificationInterval(fileUpdatesEmailInterval, collaborateEmailInterval).then((res) => {
|
userAPI.updateEmailNotificationInterval(fileUpdatesEmailInterval, collaborateEmailInterval, enablePasswordUpdateEmail, enableLoginEmail).then((res) => {
|
||||||
toaster.success(gettext('Email notification updated'));
|
toaster.success(gettext('Success'));
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
let errorMsg = Utils.getErrorMsg(error);
|
let errorMsg = Utils.getErrorMsg(error);
|
||||||
toaster.danger(errorMsg);
|
toaster.danger(errorMsg);
|
||||||
@ -62,7 +93,7 @@ class EmailNotice extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { fileUpdatesEmailInterval, collaborateEmailInterval } = this.state;
|
const { fileUpdatesEmailInterval, collaborateEmailInterval, enableLoginEmail, enablePasswordUpdateEmail } = this.state;
|
||||||
return (
|
return (
|
||||||
<div className="setting-item" id="email-notice">
|
<div className="setting-item" id="email-notice">
|
||||||
<h3 className="setting-item-heading">{gettext('Email Notification')}</h3>
|
<h3 className="setting-item-heading">{gettext('Email Notification')}</h3>
|
||||||
@ -88,6 +119,27 @@ class EmailNotice extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
|
<h4 className="mt-3 h6">{gettext('Notifications of change password')}</h4>
|
||||||
|
{this.passwordOption.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<div className="d-flex align-items-start" key={`password-${index}`}>
|
||||||
|
<input type="radio" name="pwd-interval" value={item.enabled} className="mt-1" id={`password-interval-option-${index + 1}`} checked={enablePasswordUpdateEmail == item.enabled} onChange={this.inputPasswordEmailEnabledChange} />
|
||||||
|
<label className="m-0 ml-2" htmlFor={`password-interval-option-${index + 1}`}>{item.text}</label>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
<h4 className="mt-3 h6">{gettext('Notifications of login')}</h4>
|
||||||
|
<p className="mb-1">{gettext('Send a mail as soon as a new device or browser has signed into the account (like google and many other services do).')}</p>
|
||||||
|
{this.loginOption.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<div className="d-flex" key={`login-updates-${index}`}>
|
||||||
|
<input type="radio" name="login-interval" value={item.enabled} id={`login-updates-interval-option-${index + 1}`} checked={enableLoginEmail == item.enabled} onChange={this.inputLoginEmailEnabledChange} />
|
||||||
|
<label className="m-0 ml-2" htmlFor={`login-updates-interval-option-${index + 1}`}>{item.text}</label>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
<button type="submit" className="btn btn-outline-primary mt-4">{gettext('Submit')}</button>
|
<button type="submit" className="btn btn-outline-primary mt-4">{gettext('Submit')}</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -81,6 +81,17 @@ class UserAPI {
|
|||||||
return this.req.get(url);
|
return this.req.get(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateEmailNotificationInterval(fileUpdatesEmailInterval, collaborateEmailInterval, enablePasswordUpdateEmail, enableLoginEmail) {
|
||||||
|
let url = this.server + '/api2/account/info/';
|
||||||
|
let data = {
|
||||||
|
'file_updates_email_interval': fileUpdatesEmailInterval,
|
||||||
|
'collaborate_email_interval': collaborateEmailInterval,
|
||||||
|
'enable_password_update_email': enablePasswordUpdateEmail,
|
||||||
|
'enable_login_email': enableLoginEmail
|
||||||
|
};
|
||||||
|
return this.req.put(url, data);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let userAPI = new UserAPI();
|
let userAPI = new UserAPI();
|
||||||
|
@ -26,6 +26,8 @@ from seahub.base.templatetags.seahub_tags import email2nickname, \
|
|||||||
from seahub.profile.models import Profile, DetailedProfile
|
from seahub.profile.models import Profile, DetailedProfile
|
||||||
from seahub.settings import ENABLE_UPDATE_USER_INFO, ENABLE_USER_SET_CONTACT_EMAIL, ENABLE_CONVERT_TO_TEAM_ACCOUNT, \
|
from seahub.settings import ENABLE_UPDATE_USER_INFO, ENABLE_USER_SET_CONTACT_EMAIL, ENABLE_CONVERT_TO_TEAM_ACCOUNT, \
|
||||||
ENABLE_USER_SET_NAME
|
ENABLE_USER_SET_NAME
|
||||||
|
from seahub.options.models import UserOptions
|
||||||
|
|
||||||
|
|
||||||
import seaserv
|
import seaserv
|
||||||
from seaserv import ccnet_api, seafile_api
|
from seaserv import ccnet_api, seafile_api
|
||||||
@ -251,6 +253,8 @@ class ResetPasswordView(APIView):
|
|||||||
|
|
||||||
user.set_password(new_password)
|
user.set_password(new_password)
|
||||||
user.save()
|
user.save()
|
||||||
|
enable_pwd_email = bool(UserOptions.objects.get_password_update_email_enable_status(user.username))
|
||||||
|
if enable_pwd_email:
|
||||||
email_template_name = 'registration/password_change_email.html'
|
email_template_name = 'registration/password_change_email.html'
|
||||||
send_to = email2contact_email(request.user.username)
|
send_to = email2contact_email(request.user.username)
|
||||||
site_name = get_site_name()
|
site_name = get_site_name()
|
||||||
|
@ -34,6 +34,8 @@ from seahub.utils import get_user_repos, send_html_email, get_site_name
|
|||||||
from seahub.utils.mail import send_html_email_with_dj_template
|
from seahub.utils.mail import send_html_email_with_dj_template
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
import seahub.settings as settings
|
import seahub.settings as settings
|
||||||
|
from seahub.options.models import UserOptions
|
||||||
|
|
||||||
|
|
||||||
JWT_PRIVATE_KEY = getattr(settings, 'JWT_PRIVATE_KEY', '')
|
JWT_PRIVATE_KEY = getattr(settings, 'JWT_PRIVATE_KEY', '')
|
||||||
|
|
||||||
@ -210,8 +212,8 @@ def get_token_v2(request, username, platform, device_id, device_name,
|
|||||||
raise serializers.ValidationError('invalid device id')
|
raise serializers.ValidationError('invalid device id')
|
||||||
else:
|
else:
|
||||||
raise serializers.ValidationError('invalid platform')
|
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():
|
if not TokenV2.objects.filter(user=username, device_id=device_id).first() and enable_new_device_email:
|
||||||
email_template_name='registration/new_device_login_email.html'
|
email_template_name='registration/new_device_login_email.html'
|
||||||
send_to = email2contact_email(username)
|
send_to = email2contact_email(username)
|
||||||
site_name = get_site_name()
|
site_name = get_site_name()
|
||||||
|
@ -383,6 +383,21 @@ class AccountInfo(APIView):
|
|||||||
return api_error(status.HTTP_400_BAD_REQUEST,
|
return api_error(status.HTTP_400_BAD_REQUEST,
|
||||||
'collaborate_email_interval invalid')
|
'collaborate_email_interval invalid')
|
||||||
|
|
||||||
|
enable_login_email = request.data.get("enable_login_email", None)
|
||||||
|
if enable_login_email is not None:
|
||||||
|
try:
|
||||||
|
enable_login_email = int(enable_login_email)
|
||||||
|
except ValueError:
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST,
|
||||||
|
'enable_login_email invalid')
|
||||||
|
|
||||||
|
enable_password_update_email = request.data.get("enable_password_update_email", None)
|
||||||
|
if enable_password_update_email is not None:
|
||||||
|
try:
|
||||||
|
enable_password_update_email = int(enable_password_update_email)
|
||||||
|
except ValueError:
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST,
|
||||||
|
'enable_password_update_email invalid')
|
||||||
# update user info
|
# update user info
|
||||||
|
|
||||||
if name is not None:
|
if name is not None:
|
||||||
@ -403,6 +418,14 @@ class AccountInfo(APIView):
|
|||||||
UserOptions.objects.set_collaborate_email_interval(
|
UserOptions.objects.set_collaborate_email_interval(
|
||||||
username, collaborate_email_interval)
|
username, collaborate_email_interval)
|
||||||
|
|
||||||
|
if enable_password_update_email is not None:
|
||||||
|
UserOptions.objects.set_password_update_email_enable_status(
|
||||||
|
username, enable_password_update_email)
|
||||||
|
|
||||||
|
if enable_login_email is not None:
|
||||||
|
UserOptions.objects.set_login_email_enable_status(
|
||||||
|
username, enable_login_email)
|
||||||
|
|
||||||
return Response(self._get_account_info(request))
|
return Response(self._get_account_info(request))
|
||||||
|
|
||||||
|
|
||||||
|
@ -119,7 +119,11 @@ def logout(request):
|
|||||||
session data.
|
session data.
|
||||||
Also remove all passwords used to decrypt repos.
|
Also remove all passwords used to decrypt repos.
|
||||||
"""
|
"""
|
||||||
|
already_logged_list = request.session.get('_already_logged', [])
|
||||||
request.session.flush()
|
request.session.flush()
|
||||||
|
if request.user.username not in already_logged_list:
|
||||||
|
already_logged_list.append(request.user.username)
|
||||||
|
request.session['_already_logged'] = already_logged_list
|
||||||
if hasattr(request, 'user'):
|
if hasattr(request, 'user'):
|
||||||
from seahub.base.accounts import User
|
from seahub.base.accounts import User
|
||||||
if isinstance(request.user, User):
|
if isinstance(request.user, User):
|
||||||
|
@ -43,7 +43,6 @@ from seahub.utils.two_factor_auth import two_factor_auth_enabled, handle_two_fac
|
|||||||
from seahub.utils.user_permissions import get_user_role
|
from seahub.utils.user_permissions import get_user_role
|
||||||
from seahub.utils.auth import get_login_bg_image_path
|
from seahub.utils.auth import get_login_bg_image_path
|
||||||
from seahub.organizations.models import OrgSAMLConfig
|
from seahub.organizations.models import OrgSAMLConfig
|
||||||
from seahub.sysadmin_extra.models import UserLoginLog
|
|
||||||
|
|
||||||
from constance import config
|
from constance import config
|
||||||
|
|
||||||
@ -78,7 +77,9 @@ def log_user_in(request, user, redirect_to):
|
|||||||
|
|
||||||
# Okay, security checks complete. Log the user in.
|
# Okay, security checks complete. Log the user in.
|
||||||
auth_login(request, user)
|
auth_login(request, user)
|
||||||
if UserLoginLog.objects.filter(username=user.username, login_success=1).count() == 1:
|
enable_login_email = bool(UserOptions.objects.get_login_email_enable_status(user.username))
|
||||||
|
already_logs = request.session.get('_already_logged', [])
|
||||||
|
if user.username not in already_logs and enable_login_email:
|
||||||
email_template_name = 'registration/browse_login_email.html'
|
email_template_name = 'registration/browse_login_email.html'
|
||||||
send_to = email2contact_email(request.user.username)
|
send_to = email2contact_email(request.user.username)
|
||||||
site_name = get_site_name()
|
site_name = get_site_name()
|
||||||
|
@ -38,9 +38,11 @@ KEY_FILE_UPDATES_EMAIL_INTERVAL = "file_updates_email_interval"
|
|||||||
KEY_FILE_UPDATES_LAST_EMAILED_TIME = "file_updates_last_emailed_time"
|
KEY_FILE_UPDATES_LAST_EMAILED_TIME = "file_updates_last_emailed_time"
|
||||||
KEY_COLLABORATE_EMAIL_INTERVAL = 'collaborate_email_interval'
|
KEY_COLLABORATE_EMAIL_INTERVAL = 'collaborate_email_interval'
|
||||||
KEY_COLLABORATE_LAST_EMAILED_TIME = 'collaborate_last_emailed_time'
|
KEY_COLLABORATE_LAST_EMAILED_TIME = 'collaborate_last_emailed_time'
|
||||||
|
KEY_LOGIN_EMAIL_INTERVAL = 'enable_login_email'
|
||||||
|
KEY_PASSWD_UPDATE_EMAIL_INTERVAL = 'enable_password_update_email'
|
||||||
|
|
||||||
DEFAULT_COLLABORATE_EMAIL_INTERVAL = 3600
|
DEFAULT_COLLABORATE_EMAIL_INTERVAL = 3600
|
||||||
|
DEFAULT_PWD_UPDATE_EMAIL_ENABLED = 1
|
||||||
|
|
||||||
class CryptoOptionNotSetError(Exception):
|
class CryptoOptionNotSetError(Exception):
|
||||||
pass
|
pass
|
||||||
@ -346,6 +348,34 @@ class UserOptionsManager(models.Manager):
|
|||||||
def unset_collaborate_last_emailed_time(self, username):
|
def unset_collaborate_last_emailed_time(self, username):
|
||||||
return self.unset_user_option(username, KEY_COLLABORATE_LAST_EMAILED_TIME)
|
return self.unset_user_option(username, KEY_COLLABORATE_LAST_EMAILED_TIME)
|
||||||
|
|
||||||
|
def get_login_email_enable_status(self, username):
|
||||||
|
val = self.get_user_option(username, KEY_LOGIN_EMAIL_INTERVAL)
|
||||||
|
if not val:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
return int(val)
|
||||||
|
except ValueError:
|
||||||
|
logger.error('Failed to convert string %s to int' % val)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def set_login_email_enable_status(self, username, enable):
|
||||||
|
return self.set_user_option(username, KEY_LOGIN_EMAIL_INTERVAL,
|
||||||
|
str(enable))
|
||||||
|
|
||||||
|
def get_password_update_email_enable_status(self, username):
|
||||||
|
val = self.get_user_option(username, KEY_PASSWD_UPDATE_EMAIL_INTERVAL)
|
||||||
|
if not val:
|
||||||
|
return DEFAULT_PWD_UPDATE_EMAIL_ENABLED
|
||||||
|
try:
|
||||||
|
return int(val)
|
||||||
|
except ValueError:
|
||||||
|
logger.error('Failed to convert string %s to int' % val)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def set_password_update_email_enable_status(self, username, enable):
|
||||||
|
return self.set_user_option(username, KEY_PASSWD_UPDATE_EMAIL_INTERVAL,
|
||||||
|
str(enable))
|
||||||
|
|
||||||
|
|
||||||
class UserOptions(models.Model):
|
class UserOptions(models.Model):
|
||||||
email = LowerCaseCharField(max_length=255, db_index=True)
|
email = LowerCaseCharField(max_length=255, db_index=True)
|
||||||
|
@ -58,6 +58,8 @@ window.app.pageOptions = {
|
|||||||
|
|
||||||
fileUpdatesEmailInterval: {{ file_updates_email_interval }},
|
fileUpdatesEmailInterval: {{ file_updates_email_interval }},
|
||||||
collaborateEmailInterval: {{ collaborate_email_interval }},
|
collaborateEmailInterval: {{ collaborate_email_interval }},
|
||||||
|
enablePasswordUpdateEmail: {{ enable_password_update_email }},
|
||||||
|
enableLoginEmail: {{ enable_login_email }},
|
||||||
|
|
||||||
twoFactorAuthEnabled: {% if two_factor_auth_enabled %} true {% else %} false {% endif %},
|
twoFactorAuthEnabled: {% if two_factor_auth_enabled %} true {% else %} false {% endif %},
|
||||||
{% if two_factor_auth_enabled %}
|
{% if two_factor_auth_enabled %}
|
||||||
|
@ -90,6 +90,9 @@ def edit_profile(request):
|
|||||||
file_updates_email_interval = file_updates_email_interval if file_updates_email_interval is not None else 0
|
file_updates_email_interval = file_updates_email_interval if file_updates_email_interval is not None else 0
|
||||||
collaborate_email_interval = UserOptions.objects.get_collaborate_email_interval(username)
|
collaborate_email_interval = UserOptions.objects.get_collaborate_email_interval(username)
|
||||||
collaborate_email_interval = collaborate_email_interval if collaborate_email_interval is not None else DEFAULT_COLLABORATE_EMAIL_INTERVAL
|
collaborate_email_interval = collaborate_email_interval if collaborate_email_interval is not None else DEFAULT_COLLABORATE_EMAIL_INTERVAL
|
||||||
|
enable_login_email = UserOptions.objects.get_login_email_enable_status(username)
|
||||||
|
enable_login_email = enable_login_email if enable_login_email is not None else 0
|
||||||
|
enable_password_update_email = UserOptions.objects.get_password_update_email_enable_status(username)
|
||||||
|
|
||||||
if work_weixin_oauth_check():
|
if work_weixin_oauth_check():
|
||||||
enable_wechat_work = True
|
enable_wechat_work = True
|
||||||
@ -168,6 +171,8 @@ def edit_profile(request):
|
|||||||
'ENABLE_UPDATE_USER_INFO': ENABLE_UPDATE_USER_INFO,
|
'ENABLE_UPDATE_USER_INFO': ENABLE_UPDATE_USER_INFO,
|
||||||
'file_updates_email_interval': file_updates_email_interval,
|
'file_updates_email_interval': file_updates_email_interval,
|
||||||
'collaborate_email_interval': collaborate_email_interval,
|
'collaborate_email_interval': collaborate_email_interval,
|
||||||
|
'enable_password_update_email': enable_password_update_email,
|
||||||
|
'enable_login_email': enable_login_email,
|
||||||
'social_next_page': reverse('edit_profile'),
|
'social_next_page': reverse('edit_profile'),
|
||||||
'enable_wechat_work': enable_wechat_work,
|
'enable_wechat_work': enable_wechat_work,
|
||||||
'social_connected': social_connected,
|
'social_connected': social_connected,
|
||||||
|
Loading…
Reference in New Issue
Block a user