mirror of
https://github.com/haiwen/seahub.git
synced 2025-07-15 07:52:14 +00:00
[share link] email address verification: redesigned the 'verification form' UI & the 2 emails (#6399)
This commit is contained in:
parent
c64bb90669
commit
cd5a9b824c
@ -2065,3 +2065,11 @@ a.sf-popover-item {
|
|||||||
background: #6e7687;
|
background: #6e7687;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#email-audit-form .email-input {
|
||||||
|
width: 172px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#email-audit-form .get-code-btn {
|
||||||
|
width: 102px;
|
||||||
|
}
|
||||||
|
@ -32,6 +32,7 @@ from seahub.avatar.settings import AVATAR_DEFAULT_SIZE
|
|||||||
from seahub.avatar.templatetags.avatar_tags import api_avatar_url
|
from seahub.avatar.templatetags.avatar_tags import api_avatar_url
|
||||||
from seahub.utils import get_user_repos
|
from seahub.utils import get_user_repos
|
||||||
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 seahub.settings import SECRET_KEY
|
from seahub.settings import SECRET_KEY
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -285,7 +286,7 @@ def is_web_request(request):
|
|||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def is_wiki_repo(repo):
|
def is_wiki_repo(repo):
|
||||||
return repo.repo_type == REPO_TYPE_WIKI
|
return repo.repo_type == REPO_TYPE_WIKI
|
||||||
|
|
||||||
@ -306,9 +307,9 @@ def get_search_repos(username, org_id):
|
|||||||
repos.append((repo.id, repo.origin_repo_id, repo.origin_path, repo.name))
|
repos.append((repo.id, repo.origin_repo_id, repo.origin_path, repo.name))
|
||||||
|
|
||||||
return repos
|
return repos
|
||||||
|
|
||||||
def send_share_link_emails(emails, fs, shared_from):
|
def send_share_link_emails(emails, fs, shared_from):
|
||||||
subject = "Share links"
|
subject = _("A share link for you")
|
||||||
for email in emails:
|
for email in emails:
|
||||||
c = {'url': "%s?email=%s" % (fs.get_full_url(), email), 'shared_from': shared_from}
|
c = {'url': "%s?email=%s" % (fs.get_full_url(), email), 'shared_from': shared_from}
|
||||||
send_success = send_html_email_with_dj_template(
|
send_success = send_html_email_with_dj_template(
|
||||||
@ -321,7 +322,7 @@ def send_share_link_emails(emails, fs, shared_from):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
def is_valid_internal_jwt(auth):
|
def is_valid_internal_jwt(auth):
|
||||||
|
|
||||||
if not auth or auth[0].lower()!= 'token' or len(auth) != 2:
|
if not auth or auth[0].lower()!= 'token' or len(auth) != 2:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -337,5 +338,5 @@ def is_valid_internal_jwt(auth):
|
|||||||
is_internal = payload.get('is_internal')
|
is_internal = payload.get('is_internal')
|
||||||
if is_internal:
|
if is_internal:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
@ -12,27 +12,33 @@ from seahub.share.models import FileShare, UploadLinkShare
|
|||||||
from seahub.share.utils import SCOPE_SPECIFIC_EMAILS, SCOPE_ALL_USERS, SCOPE_SPECIFIC_USERS
|
from seahub.share.utils import SCOPE_SPECIFIC_EMAILS, SCOPE_ALL_USERS, SCOPE_SPECIFIC_USERS
|
||||||
from seahub.utils import render_error
|
from seahub.utils import render_error
|
||||||
from seahub.utils import normalize_cache_key, is_pro_version, redirect_to_login
|
from seahub.utils import normalize_cache_key, is_pro_version, redirect_to_login
|
||||||
|
from seahub.utils.auth import get_login_bg_image_path
|
||||||
from seahub.constants import REPO_SHARE_LINK_COUNT_LIMIT
|
from seahub.constants import REPO_SHARE_LINK_COUNT_LIMIT
|
||||||
|
|
||||||
|
|
||||||
def _share_link_auth_email_entry(request, fileshare, func, *args, **kwargs):
|
def _share_link_auth_email_entry(request, fileshare, func, *args, **kwargs):
|
||||||
if request.user.username == fileshare.username:
|
if request.user.username == fileshare.username:
|
||||||
return func(request, fileshare, *args, **kwargs)
|
return func(request, fileshare, *args, **kwargs)
|
||||||
|
|
||||||
session_key = "link_authed_email_%s" % fileshare.token
|
session_key = "link_authed_email_%s" % fileshare.token
|
||||||
if request.session.get(session_key) is not None:
|
if request.session.get(session_key) is not None:
|
||||||
return func(request, fileshare, *args, **kwargs)
|
return func(request, fileshare, *args, **kwargs)
|
||||||
|
|
||||||
|
login_bg_image_path = get_login_bg_image_path()
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
email = request.GET.get('email', '')
|
email = request.GET.get('email', '')
|
||||||
return render(request, 'share/share_link_email_audit.html', {'email': email, 'token': fileshare.token})
|
return render(request, 'share/share_link_email_audit.html', {
|
||||||
|
'email': email,
|
||||||
|
'token': fileshare.token,
|
||||||
|
'login_bg_image_path': login_bg_image_path,
|
||||||
|
})
|
||||||
|
|
||||||
elif request.method == 'POST':
|
elif request.method == 'POST':
|
||||||
code_post = request.POST.get('code', '')
|
code_post = request.POST.get('code', '')
|
||||||
email_post = request.POST.get('email', '')
|
email_post = request.POST.get('email', '')
|
||||||
cache_key = normalize_cache_key(email_post, 'share_link_email_auth_', token=fileshare.token)
|
cache_key = normalize_cache_key(email_post, 'share_link_email_auth_', token=fileshare.token)
|
||||||
code = cache.get(cache_key)
|
code = cache.get(cache_key)
|
||||||
|
|
||||||
authed_details = json.loads(fileshare.authed_details)
|
authed_details = json.loads(fileshare.authed_details)
|
||||||
if code == code_post and email_post in authed_details.get('authed_emails'):
|
if code == code_post and email_post in authed_details.get('authed_emails'):
|
||||||
request.session[session_key] = email_post
|
request.session[session_key] = email_post
|
||||||
@ -40,12 +46,13 @@ def _share_link_auth_email_entry(request, fileshare, func, *args, **kwargs):
|
|||||||
return func(request, fileshare, *args, **kwargs)
|
return func(request, fileshare, *args, **kwargs)
|
||||||
else:
|
else:
|
||||||
return render(request, 'share/share_link_email_audit.html', {
|
return render(request, 'share/share_link_email_audit.html', {
|
||||||
'err_msg': 'Invalid token, please try again.',
|
'login_bg_image_path': login_bg_image_path,
|
||||||
|
'err_msg': _('Invalid verification code, please try again.'),
|
||||||
'email': email_post,
|
'email': email_post,
|
||||||
'code': code,
|
'code': code,
|
||||||
'token': fileshare.token,
|
'token': fileshare.token,
|
||||||
'code_verify': False
|
'code_verify': False
|
||||||
|
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
assert False, 'TODO'
|
assert False, 'TODO'
|
||||||
@ -56,7 +63,7 @@ def share_link_audit(func):
|
|||||||
def _decorated(request, token, *args, **kwargs):
|
def _decorated(request, token, *args, **kwargs):
|
||||||
|
|
||||||
assert token is not None # Checked by URLconf
|
assert token is not None # Checked by URLconf
|
||||||
|
|
||||||
is_for_upload = False
|
is_for_upload = False
|
||||||
try:
|
try:
|
||||||
fileshare = FileShare.objects.get(token=token)
|
fileshare = FileShare.objects.get(token=token)
|
||||||
@ -69,22 +76,22 @@ def share_link_audit(func):
|
|||||||
is_for_upload = True
|
is_for_upload = True
|
||||||
except UploadLinkShare.DoesNotExist:
|
except UploadLinkShare.DoesNotExist:
|
||||||
fileshare = None
|
fileshare = None
|
||||||
|
|
||||||
if not fileshare:
|
if not fileshare:
|
||||||
return render_error(request, _('Link does not exist.'))
|
return render_error(request, _('Link does not exist.'))
|
||||||
|
|
||||||
if fileshare.is_expired():
|
if fileshare.is_expired():
|
||||||
return render_error(request, _('Link is expired.'))
|
return render_error(request, _('Link is expired.'))
|
||||||
|
|
||||||
if is_for_upload:
|
if is_for_upload:
|
||||||
return func(request, fileshare, *args, **kwargs)
|
return func(request, fileshare, *args, **kwargs)
|
||||||
|
|
||||||
if fileshare.user_scope in [SCOPE_ALL_USERS, SCOPE_SPECIFIC_USERS]:
|
if fileshare.user_scope in [SCOPE_ALL_USERS, SCOPE_SPECIFIC_USERS]:
|
||||||
return func(request, fileshare, *args, **kwargs)
|
return func(request, fileshare, *args, **kwargs)
|
||||||
|
|
||||||
if fileshare.user_scope == SCOPE_SPECIFIC_EMAILS:
|
if fileshare.user_scope == SCOPE_SPECIFIC_EMAILS:
|
||||||
return _share_link_auth_email_entry(request, fileshare, func, *args, **kwargs)
|
return _share_link_auth_email_entry(request, fileshare, func, *args, **kwargs)
|
||||||
|
|
||||||
return _decorated
|
return _decorated
|
||||||
|
|
||||||
def share_link_login_required(func):
|
def share_link_login_required(func):
|
||||||
|
@ -2,15 +2,16 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block email_con %}
|
{% block email_con %}
|
||||||
|
|
||||||
{% autoescape off %}
|
{% autoescape off %}
|
||||||
|
|
||||||
<p style="color:#121214;font-size:14px;">{% trans "Hi," %}</p>
|
<p style="color:#121214;font-size:14px;">{% trans "Hi," %}</p>
|
||||||
|
|
||||||
<p style="font-size:14px;color:#434144;">
|
<p style="font-size:14px;color:#434144;">
|
||||||
{% blocktrans %}Your code is {{code}}, this code will be valid for one hour.{% endblocktrans%}
|
{% blocktrans %}The verification code is {{code}}, and it will be valid in one hour.{% endblocktrans%}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{% endautoescape %}
|
{% endautoescape %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block thanks %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,80 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block main_panel %}
|
|
||||||
<div class="new-narrow-panel" role="main">
|
|
||||||
<h2 class="hd">{% trans "Email Verification" %}</h2>
|
|
||||||
<form action="" method="post" id="link-audit-form" class="con">{% csrf_token %}
|
|
||||||
<p class="tip">{% trans "Please provide your email address to continue." %}</p>
|
|
||||||
<label for="email">{% trans "Email" %}</label>
|
|
||||||
<input id="email" type="text" class="input email-input" name="email" value="{{email}}" />
|
|
||||||
<button type="button" id="get-code" class="get-code-btn">{% trans "Get code" %}</button><br />
|
|
||||||
|
|
||||||
<label for="code">{% trans "Verification code" %}</label><br />
|
|
||||||
<input id="code" type="text" class="input" name="code" value="{{code}}" />
|
|
||||||
|
|
||||||
{% if err_msg %}
|
|
||||||
<p class="error">{{ err_msg }}</p>
|
|
||||||
{% else %}
|
|
||||||
<p class="error hide"></p>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<input type="submit" value="{% trans "Submit" %}" />
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
{% block extra_script %}
|
|
||||||
<script type="text/javascript">
|
|
||||||
$('#get-code').on('click', function() {
|
|
||||||
var email = $('input[name="email"]').val().trim();
|
|
||||||
if (!email) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var $this = $(this);
|
|
||||||
var originalText = $this.text(); // Remember the original text content
|
|
||||||
var seconds = 60;
|
|
||||||
|
|
||||||
$this.prop('disabled', true).addClass('btn-disabled');
|
|
||||||
$this.text(originalText + '(' + seconds + 's)');
|
|
||||||
// do a set interval, using an interval of 1000 milliseconds
|
|
||||||
// and clear it after the number of seconds counts down to 0
|
|
||||||
var interval = setInterval(function() {
|
|
||||||
// decrement the seconds and update the text
|
|
||||||
seconds = seconds - 1;
|
|
||||||
$this.text(originalText + ' (' + seconds + 's)');
|
|
||||||
if (seconds === 0) { // once seconds is 0...
|
|
||||||
$this.prop('disabled', false).removeClass('btn-disabled')
|
|
||||||
.text(originalText); // reset to original text
|
|
||||||
clearInterval(interval); // clear interval
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: "{% url "ajax_get_link_audit_code" %}",
|
|
||||||
type: 'POST',
|
|
||||||
cache: false,
|
|
||||||
beforeSend: prepareCSRFToken,
|
|
||||||
data: {
|
|
||||||
token: "{{token}}",
|
|
||||||
email: email
|
|
||||||
},
|
|
||||||
success: function() {
|
|
||||||
feedback("{% trans "A verification code has been sent to the email." %}", 'success');
|
|
||||||
},
|
|
||||||
error: function(xhr) {
|
|
||||||
var error_msg = prepareAjaxErrorMsg(xhr);
|
|
||||||
$('.error', $this.closest('form')).html(error_msg).removeClass('hide');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#link-audit-form').on('submit', function() {
|
|
||||||
var email = $('[name="email"]').val().trim();
|
|
||||||
var code = $('[name="code"]').val().trim();
|
|
||||||
if (!email || !code) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
@ -2,18 +2,21 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block email_con %}
|
{% block email_con %}
|
||||||
|
|
||||||
{% autoescape off %}
|
{% autoescape off %}
|
||||||
|
|
||||||
<p style="color:#121214;font-size:14px;">{% trans "Hi," %}</p>
|
<p style="color:#121214;font-size:14px;">{% trans "Hi," %}</p>
|
||||||
|
|
||||||
<p style="font-size:14px;color:#434144;">
|
<p style="font-size:14px;color:#434144;">
|
||||||
{% blocktrans %}
|
{% blocktrans %}
|
||||||
{{ shared_from }} has shared a library with you.
|
{{ shared_from }} shared a file link with you.
|
||||||
Please click <a href={{ url }}>here</a> to verify your email.
|
{% endblocktrans%}
|
||||||
|
</p>
|
||||||
|
<p style="font-size:14px;color:#434144;">
|
||||||
|
{% blocktrans %}
|
||||||
|
You can click <a href={{ url }}>here</a> to verify your email address and visit it.
|
||||||
{% endblocktrans%}
|
{% endblocktrans%}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{% endautoescape %}
|
{% endautoescape %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block thanks %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,82 +1,112 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block sub_title %}{% trans "Email address verification" %} - {% endblock %}
|
||||||
|
{% block header_css_class %}hide{% endblock %}
|
||||||
|
{% block extra_base_style %}
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/seafile-ui.css" />
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extra_style %}
|
||||||
|
<style type="text/css">
|
||||||
|
html, body, #wrapper { height:100%; }
|
||||||
|
#wrapper {
|
||||||
|
background: url('{{ MEDIA_URL }}{{login_bg_image_path}}') center top no-repeat scroll;
|
||||||
|
background-size: cover;
|
||||||
|
padding-top:1px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block main_panel %}
|
{% block main_panel %}
|
||||||
<div class="new-narrow-panel" role="main">
|
<div class="login-panel-outer-container vh">
|
||||||
<h2 class="hd">{% trans "Email Verification" %}</h2>
|
<div class="login-panel" id="log-in-panel">
|
||||||
<form action="" method="post" id="link-audit-form" class="con">{% csrf_token %}
|
<h1 class="login-panel-hd">{% trans "Email address verification" %}</h1>
|
||||||
<p class="tip">{% trans "Please provide your email address to continue." %}</p>
|
<p class="text-center">{% trans "Please provide your email address to continue." %}</p>
|
||||||
<label for="email">{% trans "Email" %}</label>
|
<form action="" method="post" id="email-audit-form" class="con">{% csrf_token %}
|
||||||
<input id="email" type="text" class="input email-input" name="email" value="{{email}}" />
|
<div class="d-flex mt-2 mb-3">
|
||||||
<button type="button" id="get-code" class="get-code-btn">{% trans "Get code" %}</button><br />
|
<input type="text" class="input email-input mr-2" name="email" value="{{email}}" placeholder="{% trans "Enter your email address" %}" />
|
||||||
<label for="code">{% trans "Verification code" %}</label><br />
|
<button type="button" id="get-code" class="btn btn-primary btn-sm text-truncate get-code-btn flex-shrink-0" title="{% trans "Get code" %}">{% trans "Get code" %}</button>
|
||||||
<input id="code" type="text" class="input" name="code" value="{{code}}" />
|
</div>
|
||||||
|
<input id="code" type="text" class="input d-block" name="code" placeholder="{% trans "Paste the verification code here" %}" />
|
||||||
|
|
||||||
{% if err_msg %}
|
{% if err_msg %}
|
||||||
<p class="error">{{ err_msg }}</p>
|
<p class="error">{{ err_msg }}</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p class="error hide"></p>
|
<p class="error hide"></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<input type="submit" value="{% trans "Submit" %}" />
|
<button type="submit" class="submit btn btn-primary btn-block h-auto">{% trans "Submit" %}</button>
|
||||||
</form>
|
</form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra_script %}
|
{% block extra_script %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
$('.login-panel-outer-container').prepend($($('#logo').html()).attr({'height': 40}).addClass('login-panel-logo'));
|
||||||
|
var $el = $('.login-panel-outer-container');
|
||||||
|
var elHeight = $el.outerHeight();
|
||||||
|
var wdHeight = $(window).height();
|
||||||
|
if (wdHeight > elHeight) {
|
||||||
|
$el.css({'margin-top': (wdHeight - elHeight)/2});
|
||||||
|
}
|
||||||
|
$el.removeClass('vh');
|
||||||
|
|
||||||
$('#get-code').on('click', function() {
|
$('#get-code').on('click', function() {
|
||||||
var email = $('input[name="email"]').val().trim();
|
var email = $('input[name="email"]').val().trim();
|
||||||
if (!email) {
|
if (!email) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var $this = $(this);
|
var $this = $(this);
|
||||||
var originalText = $this.text(); // Remember the original text content
|
//var originalText = $this.text(); // Remember the original text content
|
||||||
var seconds = 60;
|
var originalText = "{% trans "Resend" %}";
|
||||||
|
var seconds = 60;
|
||||||
|
|
||||||
$this.prop('disabled', true).addClass('btn-disabled');
|
$this.prop('disabled', true);
|
||||||
|
$this.text(originalText + '(' + seconds + 's)');
|
||||||
|
// do a set interval, using an interval of 1000 milliseconds
|
||||||
|
// and clear it after the number of seconds counts down to 0
|
||||||
|
var interval = setInterval(function() {
|
||||||
|
// decrement the seconds and update the text
|
||||||
|
seconds = seconds - 1;
|
||||||
$this.text(originalText + '(' + seconds + 's)');
|
$this.text(originalText + '(' + seconds + 's)');
|
||||||
// do a set interval, using an interval of 1000 milliseconds
|
if (seconds === 0) { // once seconds is 0...
|
||||||
// and clear it after the number of seconds counts down to 0
|
$this.prop('disabled', false)
|
||||||
var interval = setInterval(function() {
|
.text(originalText); // reset to original text
|
||||||
// decrement the seconds and update the text
|
clearInterval(interval); // clear interval
|
||||||
seconds = seconds - 1;
|
}
|
||||||
$this.text(originalText + ' (' + seconds + 's)');
|
}, 1000);
|
||||||
if (seconds === 0) { // once seconds is 0...
|
|
||||||
$this.prop('disabled', false).removeClass('btn-disabled')
|
|
||||||
.text(originalText); // reset to original text
|
|
||||||
clearInterval(interval); // clear interval
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "{% url "ajax_get_link_email_audit_code" %}",
|
url: "{% url "ajax_get_link_email_audit_code" %}",
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
cache: false,
|
cache: false,
|
||||||
beforeSend: prepareCSRFToken,
|
beforeSend: prepareCSRFToken,
|
||||||
data: {
|
data: {
|
||||||
token: "{{token}}",
|
token: "{{token}}",
|
||||||
email: email
|
email: email
|
||||||
},
|
},
|
||||||
success: function() {
|
success: function() {
|
||||||
feedback("{% trans "A verification code has been sent to the email." %}", 'success');
|
feedback("{% trans "A verification code has been sent to the email address." %}", 'success');
|
||||||
},
|
},
|
||||||
error: function(xhr) {
|
error: function(xhr) {
|
||||||
var error_msg = prepareAjaxErrorMsg(xhr);
|
var error_msg = prepareAjaxErrorMsg(xhr);
|
||||||
$('.error', $this.closest('form')).html(error_msg).removeClass('hide');
|
$('.error', $this.closest('form')).html(error_msg).removeClass('hide');
|
||||||
$this.prop('disabled', false).removeClass('btn-disabled')
|
$this.prop('disabled', false)
|
||||||
.text(originalText); // reset to original text
|
.text(originalText); // reset to original text
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#link-audit-form').on('submit', function() {
|
$('#email-audit-form').on('submit', function() {
|
||||||
var email = $('[name="email"]').val().trim();
|
var email = $('[name="email"]').val().trim();
|
||||||
var code = $('[name="code"]').val().trim();
|
var code = $('[name="code"]').val().trim();
|
||||||
if (!email || !code) {
|
if (!email || !code) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -7,6 +7,5 @@ urlpatterns = [
|
|||||||
path('link/save/', save_shared_link, name='save_shared_link'),
|
path('link/save/', save_shared_link, name='save_shared_link'),
|
||||||
path('link/export-excel/', export_shared_link, name='export_shared_link'),
|
path('link/export-excel/', export_shared_link, name='export_shared_link'),
|
||||||
path('ajax/private-share-dir/', ajax_private_share_dir, name='ajax_private_share_dir'),
|
path('ajax/private-share-dir/', ajax_private_share_dir, name='ajax_private_share_dir'),
|
||||||
path('ajax/get-link-audit-code/', ajax_get_link_audit_code, name='ajax_get_link_audit_code'),
|
|
||||||
path('ajax/get-link-email-audit-code/', ajax_get_link_email_audit_code, name='ajax_get_link_email_audit_code'),
|
path('ajax/get-link-email-audit-code/', ajax_get_link_email_audit_code, name='ajax_get_link_email_audit_code'),
|
||||||
]
|
]
|
||||||
|
@ -344,56 +344,6 @@ def ajax_private_share_dir(request):
|
|||||||
data = json.dumps({"error": _("Please check the email(s) you entered")})
|
data = json.dumps({"error": _("Please check the email(s) you entered")})
|
||||||
return HttpResponse(data, status=400, content_type=content_type)
|
return HttpResponse(data, status=400, content_type=content_type)
|
||||||
|
|
||||||
|
|
||||||
def ajax_get_link_audit_code(request):
|
|
||||||
"""
|
|
||||||
Generate a token, and record that token with email in cache, expires in
|
|
||||||
one hour, send token to that email address.
|
|
||||||
|
|
||||||
User provide token and email at share link page, if the token and email
|
|
||||||
are valid, record that email in session.
|
|
||||||
"""
|
|
||||||
content_type = 'application/json; charset=utf-8'
|
|
||||||
|
|
||||||
token = request.POST.get('token')
|
|
||||||
email = request.POST.get('email')
|
|
||||||
if not is_valid_email(email):
|
|
||||||
return HttpResponse(json.dumps({
|
|
||||||
'error': _('Email address is not valid')
|
|
||||||
}), status=400, content_type=content_type)
|
|
||||||
|
|
||||||
dfs = FileShare.objects.get_valid_file_link_by_token(token)
|
|
||||||
ufs = UploadLinkShare.objects.get_valid_upload_link_by_token(token)
|
|
||||||
|
|
||||||
fs = dfs if dfs else ufs
|
|
||||||
if fs is None:
|
|
||||||
return HttpResponse(json.dumps({
|
|
||||||
'error': _('Share link is not found')
|
|
||||||
}), status=400, content_type=content_type)
|
|
||||||
|
|
||||||
cache_key = normalize_cache_key(email, 'share_link_audit_')
|
|
||||||
code = gen_token(max_length=6)
|
|
||||||
cache.set(cache_key, code, SHARE_LINK_AUDIT_CODE_TIMEOUT)
|
|
||||||
|
|
||||||
# send code to user via email
|
|
||||||
subject = _("Verification code for visiting share links")
|
|
||||||
c = {'code': code}
|
|
||||||
|
|
||||||
send_success = send_html_email_with_dj_template(email,
|
|
||||||
subject=subject,
|
|
||||||
dj_template='share/audit_code_email.html',
|
|
||||||
context=c)
|
|
||||||
|
|
||||||
if not send_success:
|
|
||||||
logger.error('Failed to send audit code via email to %s')
|
|
||||||
return HttpResponse(json.dumps({
|
|
||||||
"error": _("Failed to send a verification code, please try again later.")
|
|
||||||
}), status=500, content_type=content_type)
|
|
||||||
|
|
||||||
return HttpResponse(json.dumps({'success': True}), status=200,
|
|
||||||
content_type=content_type)
|
|
||||||
|
|
||||||
|
|
||||||
def ajax_get_link_email_audit_code(request):
|
def ajax_get_link_email_audit_code(request):
|
||||||
content_type = 'application/json; charset=utf-8'
|
content_type = 'application/json; charset=utf-8'
|
||||||
|
|
||||||
@ -422,7 +372,7 @@ def ajax_get_link_email_audit_code(request):
|
|||||||
cache.set(cache_key, code, 60 * 60)
|
cache.set(cache_key, code, 60 * 60)
|
||||||
|
|
||||||
# send code to user via email
|
# send code to user via email
|
||||||
subject = _("Verification code for visiting share links")
|
subject = _("The verification code")
|
||||||
c = {'code': code}
|
c = {'code': code}
|
||||||
|
|
||||||
send_success = send_html_email_with_dj_template(email,
|
send_success = send_html_email_with_dj_template(email,
|
||||||
|
@ -5,11 +5,13 @@
|
|||||||
<div style="padding:30px 55px 40px;min-height:300px;border-top:1px solid #efefef;background:transparent url('{{ url_base }}{{media_url}}img/email_bg.jpg') scroll repeat-x center top;">
|
<div style="padding:30px 55px 40px;min-height:300px;border-top:1px solid #efefef;background:transparent url('{{ url_base }}{{media_url}}img/email_bg.jpg') scroll repeat-x center top;">
|
||||||
{% block email_con %}{% endblock %}
|
{% block email_con %}{% endblock %}
|
||||||
|
|
||||||
<p style="font-size:14px;color:#434144;margin:30px 0;">
|
{% block thanks %}
|
||||||
|
<p style="font-size:14px;color:#434144;margin-top:30px;">
|
||||||
{% trans "Thanks for using our site!" %}
|
{% trans "Thanks for using our site!" %}
|
||||||
</p>
|
</p>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
<p style="font-size:14px;color:#434144;">
|
<p style="font-size:14px;color:#434144;margin-top:30px;">
|
||||||
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
|
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,9 +2,7 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block sub_title %}{% trans "Log In" %} - {% endblock %}
|
{% block sub_title %}{% trans "Log In" %} - {% endblock %}
|
||||||
|
|
||||||
{% block header_css_class %}hide{% endblock %}
|
{% block header_css_class %}hide{% endblock %}
|
||||||
|
|
||||||
{% block extra_base_style %}
|
{% block extra_base_style %}
|
||||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/seafile-ui.css" />
|
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/seafile-ui.css" />
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
Loading…
Reference in New Issue
Block a user