mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-19 18:29:23 +00:00
[passwd strength] add STRONG password check(default not enabled) when user sign-up or change-password
This commit is contained in:
@@ -7,10 +7,13 @@ from seahub.base.accounts import User
|
|||||||
from seahub.auth import authenticate
|
from seahub.auth import authenticate
|
||||||
from seahub.auth.tokens import default_token_generator
|
from seahub.auth.tokens import default_token_generator
|
||||||
from seahub.utils import IS_EMAIL_CONFIGURED, send_html_email, \
|
from seahub.utils import IS_EMAIL_CONFIGURED, send_html_email, \
|
||||||
is_valid_username, is_ldap_user
|
is_valid_username, is_ldap_user, is_user_password_strong
|
||||||
|
|
||||||
from captcha.fields import CaptchaField
|
from captcha.fields import CaptchaField
|
||||||
|
|
||||||
|
from seahub.settings import USER_STRONG_PASSWORD_REQUIRED, \
|
||||||
|
USER_PASSWORD_STRENGTH_LEVEL, USER_PASSWORD_MIN_LENGTH
|
||||||
|
|
||||||
class AuthenticationForm(forms.Form):
|
class AuthenticationForm(forms.Form):
|
||||||
"""
|
"""
|
||||||
Base class for authenticating users. Extend this to get a form that accepts
|
Base class for authenticating users. Extend this to get a form that accepts
|
||||||
@@ -64,7 +67,7 @@ class AuthenticationForm(forms.Form):
|
|||||||
|
|
||||||
class CaptchaAuthenticationForm(AuthenticationForm):
|
class CaptchaAuthenticationForm(AuthenticationForm):
|
||||||
captcha = CaptchaField()
|
captcha = CaptchaField()
|
||||||
|
|
||||||
class PasswordResetForm(forms.Form):
|
class PasswordResetForm(forms.Form):
|
||||||
email = forms.EmailField(label=_("E-mail"), max_length=255)
|
email = forms.EmailField(label=_("E-mail"), max_length=255)
|
||||||
|
|
||||||
@@ -74,7 +77,7 @@ class PasswordResetForm(forms.Form):
|
|||||||
"""
|
"""
|
||||||
if not IS_EMAIL_CONFIGURED:
|
if not IS_EMAIL_CONFIGURED:
|
||||||
raise forms.ValidationError(_(u'Failed to send email, email service is not properly configured, please contact administrator.'))
|
raise forms.ValidationError(_(u'Failed to send email, email service is not properly configured, please contact administrator.'))
|
||||||
|
|
||||||
email = self.cleaned_data["email"].lower().strip()
|
email = self.cleaned_data["email"].lower().strip()
|
||||||
|
|
||||||
# TODO: add filter method to UserManager
|
# TODO: add filter method to UserManager
|
||||||
@@ -121,9 +124,21 @@ class SetPasswordForm(forms.Form):
|
|||||||
|
|
||||||
def __init__(self, user, *args, **kwargs):
|
def __init__(self, user, *args, **kwargs):
|
||||||
self.user = user
|
self.user = user
|
||||||
|
|
||||||
super(SetPasswordForm, self).__init__(*args, **kwargs)
|
super(SetPasswordForm, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def clean_new_password1(self):
|
||||||
|
if 'new_password1' in self.cleaned_data:
|
||||||
|
pwd = self.cleaned_data['new_password1']
|
||||||
|
|
||||||
|
if USER_STRONG_PASSWORD_REQUIRED is True:
|
||||||
|
if is_user_password_strong(pwd) is True:
|
||||||
|
return pwd
|
||||||
|
else:
|
||||||
|
raise forms.ValidationError(_("%s characters or more, include %s types or more of these: letters(case sensitive), numbers, and symbols") % (USER_PASSWORD_MIN_LENGTH, USER_PASSWORD_STRENGTH_LEVEL))
|
||||||
|
else:
|
||||||
|
return pwd
|
||||||
|
|
||||||
def clean_new_password2(self):
|
def clean_new_password2(self):
|
||||||
password1 = self.cleaned_data.get('new_password1')
|
password1 = self.cleaned_data.get('new_password1')
|
||||||
password2 = self.cleaned_data.get('new_password2')
|
password2 = self.cleaned_data.get('new_password2')
|
||||||
|
@@ -25,6 +25,8 @@ from seahub.auth.tokens import default_token_generator
|
|||||||
from seahub.base.accounts import User
|
from seahub.base.accounts import User
|
||||||
from seahub.utils import is_ldap_user
|
from seahub.utils import is_ldap_user
|
||||||
from seahub.utils.ip import get_remote_ip
|
from seahub.utils.ip import get_remote_ip
|
||||||
|
from seahub.settings import USER_PASSWORD_MIN_LENGTH, \
|
||||||
|
USER_STRONG_PASSWORD_REQUIRED, USER_PASSWORD_STRENGTH_LEVEL
|
||||||
|
|
||||||
# Get an instance of a logger
|
# Get an instance of a logger
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -35,9 +37,9 @@ def log_user_in(request, user, redirect_to):
|
|||||||
# Light security check -- make sure redirect_to isn't garbage.
|
# Light security check -- make sure redirect_to isn't garbage.
|
||||||
if not redirect_to or ' ' in redirect_to:
|
if not redirect_to or ' ' in redirect_to:
|
||||||
redirect_to = settings.LOGIN_REDIRECT_URL
|
redirect_to = settings.LOGIN_REDIRECT_URL
|
||||||
|
|
||||||
# Heavier security check -- redirects to http://example.com should
|
# Heavier security check -- redirects to http://example.com should
|
||||||
# not be allowed, but things like /view/?param=http://example.com
|
# not be allowed, but things like /view/?param=http://example.com
|
||||||
# should be allowed. This regex checks if there is a '//' *before* a
|
# should be allowed. This regex checks if there is a '//' *before* a
|
||||||
# question mark.
|
# question mark.
|
||||||
elif '//' in redirect_to and re.match(r'[^\?]*//', redirect_to):
|
elif '//' in redirect_to and re.match(r'[^\?]*//', redirect_to):
|
||||||
@@ -103,7 +105,7 @@ def _incr_login_faied_attempts(username=None, ip=None):
|
|||||||
|
|
||||||
def _clear_login_failed_attempts(request):
|
def _clear_login_failed_attempts(request):
|
||||||
"""Clear login failed attempts records.
|
"""Clear login failed attempts records.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
- `request`:
|
- `request`:
|
||||||
"""
|
"""
|
||||||
@@ -167,9 +169,9 @@ def login(request, template_name='registration/login.html',
|
|||||||
form = CaptchaAuthenticationForm(request)
|
form = CaptchaAuthenticationForm(request)
|
||||||
else:
|
else:
|
||||||
form = authentication_form(request)
|
form = authentication_form(request)
|
||||||
|
|
||||||
request.session.set_test_cookie()
|
request.session.set_test_cookie()
|
||||||
|
|
||||||
if Site._meta.installed:
|
if Site._meta.installed:
|
||||||
current_site = Site.objects.get_current()
|
current_site = Site.objects.get_current()
|
||||||
else:
|
else:
|
||||||
@@ -213,7 +215,7 @@ def login_simple_check(request):
|
|||||||
user = User.objects.get(email=username)
|
user = User.objects.get(email=username)
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
raise Http404
|
raise Http404
|
||||||
|
|
||||||
for backend in get_backends():
|
for backend in get_backends():
|
||||||
user.backend = "%s.%s" % (backend.__module__, backend.__class__.__name__)
|
user.backend = "%s.%s" % (backend.__module__, backend.__class__.__name__)
|
||||||
|
|
||||||
@@ -223,7 +225,7 @@ def login_simple_check(request):
|
|||||||
else:
|
else:
|
||||||
raise Http404
|
raise Http404
|
||||||
|
|
||||||
|
|
||||||
def logout(request, next_page=None, template_name='registration/logged_out.html', redirect_field_name=REDIRECT_FIELD_NAME):
|
def logout(request, next_page=None, template_name='registration/logged_out.html', redirect_field_name=REDIRECT_FIELD_NAME):
|
||||||
"Logs out the user and displays 'You are logged out' message."
|
"Logs out the user and displays 'You are logged out' message."
|
||||||
from seahub.auth import logout
|
from seahub.auth import logout
|
||||||
@@ -255,7 +257,7 @@ def redirect_to_login(next, login_url=None, redirect_field_name=REDIRECT_FIELD_N
|
|||||||
# 4 views for password reset:
|
# 4 views for password reset:
|
||||||
# - password_reset sends the mail
|
# - password_reset sends the mail
|
||||||
# - password_reset_done shows a success message for the above
|
# - password_reset_done shows a success message for the above
|
||||||
# - password_reset_confirm checks the link the user clicked and
|
# - password_reset_confirm checks the link the user clicked and
|
||||||
# prompts for a new password
|
# prompts for a new password
|
||||||
# - password_reset_complete shows a success message for the above
|
# - password_reset_complete shows a success message for the above
|
||||||
|
|
||||||
@@ -352,8 +354,12 @@ def password_change(request, template_name='registration/password_change_form.ht
|
|||||||
return HttpResponseRedirect(post_change_redirect)
|
return HttpResponseRedirect(post_change_redirect)
|
||||||
else:
|
else:
|
||||||
form = password_change_form(user=request.user)
|
form = password_change_form(user=request.user)
|
||||||
|
|
||||||
return render_to_response(template_name, {
|
return render_to_response(template_name, {
|
||||||
'form': form,
|
'form': form,
|
||||||
|
'min_len': USER_PASSWORD_MIN_LENGTH,
|
||||||
|
'strong_pwd_required': USER_STRONG_PASSWORD_REQUIRED,
|
||||||
|
'level': USER_PASSWORD_STRENGTH_LEVEL,
|
||||||
}, context_instance=RequestContext(request))
|
}, context_instance=RequestContext(request))
|
||||||
|
|
||||||
def password_change_done(request, template_name='registration/password_change_done.html'):
|
def password_change_done(request, template_name='registration/password_change_done.html'):
|
||||||
|
@@ -13,12 +13,14 @@ from registration import signals
|
|||||||
from seaserv import ccnet_threaded_rpc, unset_repo_passwd, is_passwd_set
|
from seaserv import ccnet_threaded_rpc, unset_repo_passwd, is_passwd_set
|
||||||
|
|
||||||
from seahub.profile.models import Profile, DetailedProfile
|
from seahub.profile.models import Profile, DetailedProfile
|
||||||
from seahub.utils import is_valid_username
|
from seahub.utils import is_valid_username, is_user_password_strong
|
||||||
try:
|
try:
|
||||||
from seahub.settings import CLOUD_MODE
|
from seahub.settings import CLOUD_MODE
|
||||||
except ImportError:
|
except ImportError:
|
||||||
CLOUD_MODE = False
|
CLOUD_MODE = False
|
||||||
|
|
||||||
|
from seahub.settings import USER_STRONG_PASSWORD_REQUIRED, \
|
||||||
|
USER_PASSWORD_MIN_LENGTH, USER_PASSWORD_STRENGTH_LEVEL
|
||||||
|
|
||||||
UNUSABLE_PASSWORD = '!' # This will never be a valid hash
|
UNUSABLE_PASSWORD = '!' # This will never be a valid hash
|
||||||
|
|
||||||
@@ -463,40 +465,14 @@ class RegistrationForm(forms.Form):
|
|||||||
def clean_password1(self):
|
def clean_password1(self):
|
||||||
if 'password1' in self.cleaned_data:
|
if 'password1' in self.cleaned_data:
|
||||||
pwd = self.cleaned_data['password1']
|
pwd = self.cleaned_data['password1']
|
||||||
if len(pwd) < 6:
|
|
||||||
raise forms.ValidationError(
|
if USER_STRONG_PASSWORD_REQUIRED is True:
|
||||||
_("Passwords must have at least 6 characters."))
|
if is_user_password_strong(pwd) is True:
|
||||||
|
return pwd
|
||||||
|
else:
|
||||||
|
raise forms.ValidationError(_("%s characters or more, include %s types or more of these: letters(case sensitive), numbers, and symbols") % (USER_PASSWORD_MIN_LENGTH, USER_PASSWORD_STRENGTH_LEVEL))
|
||||||
else:
|
else:
|
||||||
num = 0
|
return pwd
|
||||||
for letter in pwd:
|
|
||||||
# get ascii dec
|
|
||||||
# bitwise OR
|
|
||||||
num |= self.get_char_mode(ord(letter))
|
|
||||||
level = self.caculate_bitwise(num)
|
|
||||||
if level == 1:
|
|
||||||
raise forms.ValidationError(_("Passwords must contain at least 2 types: uppercase letters, lowercase letters, numbers, and symbols"))
|
|
||||||
|
|
||||||
return self.cleaned_data['password1']
|
|
||||||
|
|
||||||
def get_char_mode(self, n):
|
|
||||||
if (n >= 48 and n <= 57): #nums
|
|
||||||
return 1;
|
|
||||||
if (n >= 65 and n <= 90): #uppers
|
|
||||||
return 2;
|
|
||||||
if (n >= 97 and n <= 122): #lowers
|
|
||||||
return 4;
|
|
||||||
else:
|
|
||||||
return 8;
|
|
||||||
|
|
||||||
def caculate_bitwise(self, num):
|
|
||||||
level = 0
|
|
||||||
for i in range(4):
|
|
||||||
# bitwise AND
|
|
||||||
if (num&1):
|
|
||||||
level += 1
|
|
||||||
# Right logical shift
|
|
||||||
num = num >> 1
|
|
||||||
return level
|
|
||||||
|
|
||||||
def clean_password2(self):
|
def clean_password2(self):
|
||||||
"""
|
"""
|
||||||
|
@@ -104,10 +104,10 @@ MIDDLEWARE_CLASSES = (
|
|||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
'django.middleware.locale.LocaleMiddleware',
|
'django.middleware.locale.LocaleMiddleware',
|
||||||
'django.middleware.common.CommonMiddleware',
|
'django.middleware.common.CommonMiddleware',
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
'seahub.auth.middleware.AuthenticationMiddleware',
|
'seahub.auth.middleware.AuthenticationMiddleware',
|
||||||
'seahub.base.middleware.BaseMiddleware',
|
'seahub.base.middleware.BaseMiddleware',
|
||||||
'seahub.base.middleware.InfobarMiddleware',
|
'seahub.base.middleware.InfobarMiddleware',
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ LOCALE_PATHS = (
|
|||||||
TEMPLATE_CONTEXT_PROCESSORS = (
|
TEMPLATE_CONTEXT_PROCESSORS = (
|
||||||
'django.contrib.auth.context_processors.auth',
|
'django.contrib.auth.context_processors.auth',
|
||||||
'django.core.context_processors.debug',
|
'django.core.context_processors.debug',
|
||||||
'django.core.context_processors.i18n',
|
'django.core.context_processors.i18n',
|
||||||
'django.core.context_processors.media',
|
'django.core.context_processors.media',
|
||||||
'djblets.util.context_processors.siteRoot',
|
'djblets.util.context_processors.siteRoot',
|
||||||
'django.core.context_processors.request',
|
'django.core.context_processors.request',
|
||||||
@@ -207,6 +207,18 @@ SHOW_REPO_DOWNLOAD_BUTTON = False
|
|||||||
# mininum length for password of encrypted library
|
# mininum length for password of encrypted library
|
||||||
REPO_PASSWORD_MIN_LENGTH = 8
|
REPO_PASSWORD_MIN_LENGTH = 8
|
||||||
|
|
||||||
|
# mininum length for user's password
|
||||||
|
USER_PASSWORD_MIN_LENGTH = 6
|
||||||
|
|
||||||
|
# LEVEL based on four types of input:
|
||||||
|
# num, upper letter, lower letter, other symbols
|
||||||
|
# '3' means password must have at least 3 types of the above.
|
||||||
|
USER_PASSWORD_STRENGTH_LEVEL = 3
|
||||||
|
|
||||||
|
# default False, only check USER_PASSWORD_MIN_LENGTH
|
||||||
|
# when True, check password strength level, STRONG(or above) is allowed
|
||||||
|
USER_STRONG_PASSWORD_REQUIRED = False
|
||||||
|
|
||||||
# Using server side crypto by default, otherwise, let user choose crypto method.
|
# Using server side crypto by default, otherwise, let user choose crypto method.
|
||||||
FORCE_SERVER_CRYPTO = True
|
FORCE_SERVER_CRYPTO = True
|
||||||
|
|
||||||
@@ -219,7 +231,7 @@ OFFICE_PREVIEW_MAX_SIZE = 2 * 1024 * 1024
|
|||||||
USE_PDFJS = True
|
USE_PDFJS = True
|
||||||
FILE_ENCODING_LIST = ['auto', 'utf-8', 'gbk', 'ISO-8859-1', 'ISO-8859-5']
|
FILE_ENCODING_LIST = ['auto', 'utf-8', 'gbk', 'ISO-8859-1', 'ISO-8859-5']
|
||||||
FILE_ENCODING_TRY_LIST = ['utf-8', 'gbk']
|
FILE_ENCODING_TRY_LIST = ['utf-8', 'gbk']
|
||||||
HIGHLIGHT_KEYWORD = False # If True, highlight the keywords in the file when the visit is via clicking a link in 'search result' page.
|
HIGHLIGHT_KEYWORD = False # If True, highlight the keywords in the file when the visit is via clicking a link in 'search result' page.
|
||||||
|
|
||||||
# Common settings(file extension, storage) for avatar and group avatar.
|
# Common settings(file extension, storage) for avatar and group avatar.
|
||||||
AVATAR_FILE_STORAGE = '' # Replace with 'seahub.base.database_storage.DatabaseStorage' if save avatar files to database
|
AVATAR_FILE_STORAGE = '' # Replace with 'seahub.base.database_storage.DatabaseStorage' if save avatar files to database
|
||||||
@@ -346,7 +358,7 @@ LOGGING = {
|
|||||||
'filename': os.path.join(LOG_DIR, 'seahub.log'),
|
'filename': os.path.join(LOG_DIR, 'seahub.log'),
|
||||||
'maxBytes': 1024*1024*10, # 10 MB
|
'maxBytes': 1024*1024*10, # 10 MB
|
||||||
'formatter':'standard',
|
'formatter':'standard',
|
||||||
},
|
},
|
||||||
'request_handler': {
|
'request_handler': {
|
||||||
'level':'WARN',
|
'level':'WARN',
|
||||||
'class':'logging.handlers.RotatingFileHandler',
|
'class':'logging.handlers.RotatingFileHandler',
|
||||||
@@ -452,7 +464,7 @@ def load_local_settings(module):
|
|||||||
elif re.search('^[A-Z]', attr):
|
elif re.search('^[A-Z]', attr):
|
||||||
globals()[attr] = getattr(module, attr)
|
globals()[attr] = getattr(module, attr)
|
||||||
|
|
||||||
|
|
||||||
# Load seahub_extra_settings.py
|
# Load seahub_extra_settings.py
|
||||||
try:
|
try:
|
||||||
from seahub_extra import seahub_extra_settings
|
from seahub_extra import seahub_extra_settings
|
||||||
@@ -478,7 +490,7 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
# In server release, sqlite3 db file is <topdir>/seahub.db
|
# In server release, sqlite3 db file is <topdir>/seahub.db
|
||||||
DATABASES['default']['NAME'] = os.path.join(install_topdir, 'seahub.db')
|
DATABASES['default']['NAME'] = os.path.join(install_topdir, 'seahub.db')
|
||||||
if 'win32' not in sys.platform:
|
if 'win32' not in sys.platform:
|
||||||
# In server release, gunicorn is used to deploy seahub
|
# In server release, gunicorn is used to deploy seahub
|
||||||
|
@@ -7,9 +7,13 @@
|
|||||||
<h2 class="hd">{% trans "Password Modification" %}</h2>
|
<h2 class="hd">{% trans "Password Modification" %}</h2>
|
||||||
<form action="" method="post" class="con">{% csrf_token %}
|
<form action="" method="post" class="con">{% csrf_token %}
|
||||||
<label for="id_old_password">{% trans "Current Password: " %}</label>
|
<label for="id_old_password">{% trans "Current Password: " %}</label>
|
||||||
{{ form.old_password }} {{ form.old_password.errors }}
|
{{ form.old_password }} {{ form.old_password.errors }}
|
||||||
<label for="id_new_password1">{% trans "New Password: " %}</label>
|
<label for="id_new_password1">{% trans "New Password: " %}</label>
|
||||||
{{ form.new_password1 }} {{ form.new_password1.errors }}
|
{% if strong_pwd_required %}
|
||||||
|
<span class="icon-question-sign" title="{% blocktrans %}{{min_len}} characters or more, include {{level}} types or more of these: letters(case sensitive), numbers, and symbols"{% endblocktrans%}></span>
|
||||||
|
{% endif %}
|
||||||
|
{{ form.new_password1 }} {{ form.new_password1.errors }}
|
||||||
|
<div id="pwd_strength"></div>
|
||||||
<label for="id_new_password2">{% trans "Confirm Password: " %}</label>
|
<label for="id_new_password2">{% trans "Confirm Password: " %}</label>
|
||||||
{{ form.new_password2 }} {{ form.new_password2.errors }}
|
{{ form.new_password2 }} {{ form.new_password2.errors }}
|
||||||
|
|
||||||
@@ -22,6 +26,47 @@
|
|||||||
|
|
||||||
{% block extra_script %}
|
{% block extra_script %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$('[type="password"]').addClass('input');
|
$('[type="password"]').addClass('input');
|
||||||
|
|
||||||
|
{% include "snippets/password_strength_js.html" %}
|
||||||
|
|
||||||
|
$("#id_new_password1").keyup(function() {
|
||||||
|
var pwd = $(this).val(),
|
||||||
|
level = getStrengthLevel(pwd);
|
||||||
|
|
||||||
|
if (pwd.length > 0) {
|
||||||
|
showStrength(level);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
$('form').submit(function(){
|
||||||
|
var old_pwd = $.trim($('input[name="old_password"]').val()),
|
||||||
|
pwd1 = $.trim($('input[name="new_password1"]').val()),
|
||||||
|
pwd2 = $.trim($('input[name="new_password2"]').val()),
|
||||||
|
level = getStrengthLevel(pwd1);
|
||||||
|
|
||||||
|
if (!old_pwd) {
|
||||||
|
$('.error').removeClass('hide').html("{% trans "Current password cannot be blank" %}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!pwd1) {
|
||||||
|
$('.error').removeClass('hide').html("{% trans "Password cannot be blank" %}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!pwd2) {
|
||||||
|
$('.error').removeClass('hide').html("{% trans "Please enter the password again" %}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (pwd1 != pwd2) {
|
||||||
|
$('.error').removeClass('hide').html("{% trans "Passwords don't match" %}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
{% if strong_pwd_required %}
|
||||||
|
if (level < {{level}}) {
|
||||||
|
$('.error').removeClass('hide').html("{% blocktrans %}{{min_len}} characters or more, include {{level}} types or more of these: letters(case sensitive), numbers, and symbols{% endblocktrans %}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
{% endif %}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@@ -16,7 +16,10 @@
|
|||||||
|
|
||||||
<label for="id_email">{% trans "Email" %}</label>
|
<label for="id_email">{% trans "Email" %}</label>
|
||||||
{{ form.email }} {{ form.email.errors }}
|
{{ form.email }} {{ form.email.errors }}
|
||||||
<label for="id_password1">{% trans "Password" %}</label> <span class="icon-question-sign" title="{% trans "6 characters or more, include 2 types or more of these: letters(case sensitive), numbers, and symbols" %}"></span>
|
<label for="id_password1">{% trans "Password" %}</label>
|
||||||
|
{% if strong_pwd_required %}
|
||||||
|
<span class="icon-question-sign" title="{% blocktrans %}{{min_len}} characters or more, include {{level}} types or more of these: letters(case sensitive), numbers, and symbols"{% endblocktrans%}></span>
|
||||||
|
{% endif %}
|
||||||
{{ form.password1 }} {{ form.password1.errors }}
|
{{ form.password1 }} {{ form.password1.errors }}
|
||||||
<div id="pwd_strength"></div>
|
<div id="pwd_strength"></div>
|
||||||
<label for="id_password2">{% trans "Confirm Password" %}</label>
|
<label for="id_password2">{% trans "Confirm Password" %}</label>
|
||||||
@@ -40,73 +43,17 @@
|
|||||||
|
|
||||||
{% block extra_script %}
|
{% block extra_script %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
{% include "snippets/password_strength_js.html" %}
|
||||||
|
|
||||||
$("#id_password1").keyup(function() {
|
$("#id_password1").keyup(function() {
|
||||||
var level = getStrengthLevel($(this).val());
|
var pwd = $(this).val(),
|
||||||
showStrength(level);
|
level = getStrengthLevel(pwd);
|
||||||
});
|
|
||||||
|
|
||||||
function getStrengthLevel(pwd) {
|
if (pwd.length > 0) {
|
||||||
var num = 0,
|
showStrength(level);
|
||||||
min_passwd_len = 6;
|
|
||||||
|
|
||||||
if (pwd.length < min_passwd_len) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
for (var i = 0; i < pwd.length; i++) {
|
|
||||||
// return the unicode
|
|
||||||
// bitwise OR
|
|
||||||
num |= getCharMode(pwd.charCodeAt(i));
|
|
||||||
};
|
|
||||||
return calculateBitwise(num);
|
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
|
|
||||||
function getCharMode(n) {
|
|
||||||
if (n >= 48 && n <= 57) // nums
|
|
||||||
return 1;
|
|
||||||
if (n >= 65 && n <= 90) // uppers
|
|
||||||
return 2;
|
|
||||||
if (n >= 97 && n <= 122) // lowers
|
|
||||||
return 4;
|
|
||||||
else
|
|
||||||
return 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
function calculateBitwise(num) {
|
|
||||||
var level = 0;
|
|
||||||
for (var i = 0; i < 4; i++){
|
|
||||||
// bitwise AND
|
|
||||||
if (num&1) level++;
|
|
||||||
// Right logical shift
|
|
||||||
num>>>=1;
|
|
||||||
}
|
|
||||||
return level;
|
|
||||||
}
|
|
||||||
|
|
||||||
function showStrength(level) {
|
|
||||||
var strength_ct = $("#pwd_strength");
|
|
||||||
var strength = [
|
|
||||||
"{% trans "too weak" %}",
|
|
||||||
"{% trans "weak" %}",
|
|
||||||
"{% trans "medium" %}",
|
|
||||||
"{% trans "strong" %}"
|
|
||||||
];
|
|
||||||
switch (level) {
|
|
||||||
case 0:
|
|
||||||
strength_ct.html(strength[0]).css("color", '#F00000');
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
strength_ct.html('<span style="background:#db4747;">' + strength[1] + '</span><span>' + strength[2] + '</span><span>' + strength[3] + '</span>');
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
strength_ct.html('<span>' + strength[1] + '</span><span style="background:#fdd64d;">' + strength[2] + '</span><span>' + strength[3] + '</span>');
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
strength_ct.html('<span>' + strength[1] + '</span><span>' + strength[2] + '</span><span style="background:#4aa323;">' + strength[3] + '</span>');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$('form').submit(function(){
|
$('form').submit(function(){
|
||||||
var email = $.trim($('input[name="email"]').val()),
|
var email = $.trim($('input[name="email"]').val()),
|
||||||
@@ -130,14 +77,12 @@ $('form').submit(function(){
|
|||||||
$('.error').removeClass('hide').html("{% trans "Passwords don't match" %}");
|
$('.error').removeClass('hide').html("{% trans "Passwords don't match" %}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (pwd1.length < 6) {
|
{% if strong_pwd_required %}
|
||||||
$('.error').removeClass('hide').html("{% trans "Passwords must have at least 6 characters" %}");
|
if (level < {{level}}) {
|
||||||
return false;
|
$('.error').removeClass('hide').html("{% blocktrans %}{{min_len}} characters or more, include {{level}} types or more of these: letters(case sensitive), numbers, and symbols{% endblocktrans %}");
|
||||||
}
|
return false;
|
||||||
if (level <= 2) {
|
}
|
||||||
$('.error').removeClass('hide').html("{% trans "Passwords contain at least 2 types: uppercase letters, lowercase letters, numbers, and symbols" %}");
|
{% endif %}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
62
seahub/templates/snippets/password_strength_js.html
Normal file
62
seahub/templates/snippets/password_strength_js.html
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
function getStrengthLevel(pwd) {
|
||||||
|
var num = 0;
|
||||||
|
|
||||||
|
if (pwd.length < {{min_len}}) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
for (var i = 0; i < pwd.length; i++) {
|
||||||
|
// return the unicode
|
||||||
|
// bitwise OR
|
||||||
|
num |= getCharMode(pwd.charCodeAt(i));
|
||||||
|
};
|
||||||
|
return calculateBitwise(num);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCharMode(n) {
|
||||||
|
if (n >= 48 && n <= 57) // nums
|
||||||
|
return 1;
|
||||||
|
if (n >= 65 && n <= 90) // uppers
|
||||||
|
return 2;
|
||||||
|
if (n >= 97 && n <= 122) // lowers
|
||||||
|
return 4;
|
||||||
|
else
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateBitwise(num) {
|
||||||
|
var level = 0;
|
||||||
|
for (var i = 0; i < 4; i++){
|
||||||
|
// bitwise AND
|
||||||
|
if (num&1) level++;
|
||||||
|
// Right logical shift
|
||||||
|
num>>>=1;
|
||||||
|
}
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showStrength(level) {
|
||||||
|
var strength_ct = $("#pwd_strength");
|
||||||
|
var strength = [
|
||||||
|
"{% trans "too weak" %}",
|
||||||
|
"{% trans "weak" %}",
|
||||||
|
"{% trans "medium" %}",
|
||||||
|
"{% trans "strong" %}"
|
||||||
|
];
|
||||||
|
switch (level) {
|
||||||
|
case 0:
|
||||||
|
strength_ct.html(strength[0]).css("color", '#F00000');
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
strength_ct.html('<span style="background:#db4747;">' + strength[1] + '</span><span>' + strength[2] + '</span><span>' + strength[3] + '</span>');
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
strength_ct.html('<span>' + strength[1] + '</span><span style="background:#fdd64d;">' + strength[2] + '</span><span>' + strength[3] + '</span>');
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
strength_ct.html('<span>' + strength[1] + '</span><span>' + strength[2] + '</span><span style="background:#4aa323;">' + strength[3] + '</span>');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
@@ -15,7 +15,7 @@ $(function() {
|
|||||||
$('#encrypt-switch').click(function () {
|
$('#encrypt-switch').click(function () {
|
||||||
var form = $('#repo-create-form'),
|
var form = $('#repo-create-form'),
|
||||||
pwd_input = $('input[type="password"]', form);
|
pwd_input = $('input[type="password"]', form);
|
||||||
|
|
||||||
if ($(this).attr('checked')) {
|
if ($(this).attr('checked')) {
|
||||||
pwd_input.attr('disabled', false).removeClass('input-disabled');
|
pwd_input.attr('disabled', false).removeClass('input-disabled');
|
||||||
} else {
|
} else {
|
||||||
@@ -23,7 +23,7 @@ $('#encrypt-switch').click(function () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
$('#repo-create-form').submit(function() {
|
$('#repo-create-form').submit(function() {
|
||||||
var form = $(this),
|
var form = $(this),
|
||||||
form_id = form.attr('id'),
|
form_id = form.attr('id'),
|
||||||
name = $('[name="repo_name"]', form).val(),
|
name = $('[name="repo_name"]', form).val(),
|
||||||
desc = $('[name="repo_desc"]', form).val(),
|
desc = $('[name="repo_desc"]', form).val(),
|
||||||
|
@@ -29,7 +29,8 @@ from seaserv import seafserv_rpc, seafserv_threaded_rpc, get_repo, get_commits,\
|
|||||||
list_personal_repos_by_owner, get_group_repos, \
|
list_personal_repos_by_owner, get_group_repos, \
|
||||||
list_inner_pub_repos, CCNET_CONF_PATH, SERVICE_URL
|
list_inner_pub_repos, CCNET_CONF_PATH, SERVICE_URL
|
||||||
import seahub.settings
|
import seahub.settings
|
||||||
from seahub.settings import SITE_NAME, MEDIA_URL, LOGO_PATH
|
from seahub.settings import SITE_NAME, MEDIA_URL, LOGO_PATH, \
|
||||||
|
USER_PASSWORD_STRENGTH_LEVEL, USER_PASSWORD_MIN_LENGTH
|
||||||
try:
|
try:
|
||||||
from seahub.settings import EVENTS_CONFIG_FILE
|
from seahub.settings import EVENTS_CONFIG_FILE
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@@ -78,7 +79,7 @@ PREVIEW_FILEEXT = {
|
|||||||
def gen_fileext_type_map():
|
def gen_fileext_type_map():
|
||||||
"""
|
"""
|
||||||
Generate previewed file extension and file type relation map.
|
Generate previewed file extension and file type relation map.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
d = {}
|
d = {}
|
||||||
for filetype in PREVIEW_FILEEXT.keys():
|
for filetype in PREVIEW_FILEEXT.keys():
|
||||||
@@ -156,7 +157,7 @@ def gen_token(max_length=5):
|
|||||||
Generate a random token.
|
Generate a random token.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return uuid.uuid4().hex[:max_length]
|
return uuid.uuid4().hex[:max_length]
|
||||||
|
|
||||||
def normalize_cache_key(value, prefix=None):
|
def normalize_cache_key(value, prefix=None):
|
||||||
@@ -165,7 +166,7 @@ def normalize_cache_key(value, prefix=None):
|
|||||||
"""
|
"""
|
||||||
key = value if prefix is None else prefix + value
|
key = value if prefix is None else prefix + value
|
||||||
return urlquote(key)
|
return urlquote(key)
|
||||||
|
|
||||||
def get_repo_last_modify(repo):
|
def get_repo_last_modify(repo):
|
||||||
""" Get last modification time for a repo.
|
""" Get last modification time for a repo.
|
||||||
|
|
||||||
@@ -332,7 +333,7 @@ def get_file_revision_id_size(repo_id, commit_id, path):
|
|||||||
|
|
||||||
def new_merge_with_no_conflict(commit):
|
def new_merge_with_no_conflict(commit):
|
||||||
"""Check whether a commit is a new merge, and no conflict.
|
"""Check whether a commit is a new merge, and no conflict.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
- `commit`:
|
- `commit`:
|
||||||
"""
|
"""
|
||||||
@@ -358,7 +359,7 @@ def get_commit_before_new_merge(commit):
|
|||||||
commit = p1 if p1.ctime > p2.ctime else p2
|
commit = p1 if p1.ctime > p2.ctime else p2
|
||||||
|
|
||||||
assert new_merge_with_no_conflict(commit) is False
|
assert new_merge_with_no_conflict(commit) is False
|
||||||
|
|
||||||
return commit
|
return commit
|
||||||
|
|
||||||
def gen_inner_file_get_url(token, filename):
|
def gen_inner_file_get_url(token, filename):
|
||||||
@@ -386,7 +387,7 @@ def get_max_upload_file_size():
|
|||||||
Returns ``None`` if this value is not set.
|
Returns ``None`` if this value is not set.
|
||||||
"""
|
"""
|
||||||
return seaserv.MAX_UPLOAD_FILE_SIZE
|
return seaserv.MAX_UPLOAD_FILE_SIZE
|
||||||
|
|
||||||
def gen_block_get_url(token, blkid):
|
def gen_block_get_url(token, blkid):
|
||||||
"""
|
"""
|
||||||
Generate fileserver block url.
|
Generate fileserver block url.
|
||||||
@@ -425,7 +426,7 @@ def string2list(string):
|
|||||||
continue
|
continue
|
||||||
s.add(e)
|
s.add(e)
|
||||||
return [ x for x in s ]
|
return [ x for x in s ]
|
||||||
|
|
||||||
# def get_cur_ctx(request):
|
# def get_cur_ctx(request):
|
||||||
# ctx_dict = request.session.get('current_context', {
|
# ctx_dict = request.session.get('current_context', {
|
||||||
# 'base_template': 'myhome_base.html',
|
# 'base_template': 'myhome_base.html',
|
||||||
@@ -439,12 +440,12 @@ def string2list(string):
|
|||||||
def is_org_context(request):
|
def is_org_context(request):
|
||||||
"""An organization context is a virtual private Seafile instance on cloud
|
"""An organization context is a virtual private Seafile instance on cloud
|
||||||
service.
|
service.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
- `request`:
|
- `request`:
|
||||||
"""
|
"""
|
||||||
return request.cloud_mode and request.user.org is not None
|
return request.cloud_mode and request.user.org is not None
|
||||||
|
|
||||||
# def check_and_get_org_by_repo(repo_id, user):
|
# def check_and_get_org_by_repo(repo_id, user):
|
||||||
# """
|
# """
|
||||||
# Check whether repo is org repo, get org info if it is, and set
|
# Check whether repo is org repo, get org info if it is, and set
|
||||||
@@ -460,7 +461,7 @@ def is_org_context(request):
|
|||||||
# else:
|
# else:
|
||||||
# org = None
|
# org = None
|
||||||
# base_template = 'myhome_base.html'
|
# base_template = 'myhome_base.html'
|
||||||
|
|
||||||
# return org, base_template
|
# return org, base_template
|
||||||
|
|
||||||
def check_and_get_org_by_group(group_id, user):
|
def check_and_get_org_by_group(group_id, user):
|
||||||
@@ -478,9 +479,9 @@ def check_and_get_org_by_group(group_id, user):
|
|||||||
else:
|
else:
|
||||||
org = None
|
org = None
|
||||||
base_template = 'myhome_base.html'
|
base_template = 'myhome_base.html'
|
||||||
|
|
||||||
return org, base_template
|
return org, base_template
|
||||||
|
|
||||||
# events related
|
# events related
|
||||||
if EVENTS_CONFIG_FILE:
|
if EVENTS_CONFIG_FILE:
|
||||||
import seafevents
|
import seafevents
|
||||||
@@ -510,7 +511,7 @@ if EVENTS_CONFIG_FILE:
|
|||||||
events = _get_events_inner(ev_session, username, next_start, count)
|
events = _get_events_inner(ev_session, username, next_start, count)
|
||||||
if not events:
|
if not events:
|
||||||
break
|
break
|
||||||
|
|
||||||
for e1 in events:
|
for e1 in events:
|
||||||
duplicate = False
|
duplicate = False
|
||||||
for e2 in valid_events:
|
for e2 in valid_events:
|
||||||
@@ -519,13 +520,13 @@ if EVENTS_CONFIG_FILE:
|
|||||||
new_merge = False
|
new_merge = False
|
||||||
if hasattr(e1, 'commit') and new_merge_with_no_conflict(e1.commit):
|
if hasattr(e1, 'commit') and new_merge_with_no_conflict(e1.commit):
|
||||||
new_merge = True
|
new_merge = True
|
||||||
|
|
||||||
if not duplicate and not new_merge:
|
if not duplicate and not new_merge:
|
||||||
valid_events.append(e1)
|
valid_events.append(e1)
|
||||||
total_used = total_used + 1
|
total_used = total_used + 1
|
||||||
if len(valid_events) == count:
|
if len(valid_events) == count:
|
||||||
break
|
break
|
||||||
|
|
||||||
if len(valid_events) == count:
|
if len(valid_events) == count:
|
||||||
break
|
break
|
||||||
next_start = next_start + len(events)
|
next_start = next_start + len(events)
|
||||||
@@ -569,14 +570,14 @@ if EVENTS_CONFIG_FILE:
|
|||||||
break
|
break
|
||||||
|
|
||||||
if len(valid_events) == limit:
|
if len(valid_events) == limit:
|
||||||
break
|
break
|
||||||
next_start = next_start + len(valid_events)
|
next_start = next_start + len(valid_events)
|
||||||
|
|
||||||
return valid_events
|
return valid_events
|
||||||
|
|
||||||
def get_user_events(username, start, count):
|
def get_user_events(username, start, count):
|
||||||
"""Return user events list and a new start.
|
"""Return user events list and a new start.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
``get_user_events('foo@example.com', 0, 10)`` returns the first 10
|
``get_user_events('foo@example.com', 0, 10)`` returns the first 10
|
||||||
events.
|
events.
|
||||||
@@ -584,7 +585,7 @@ if EVENTS_CONFIG_FILE:
|
|||||||
15th events.
|
15th events.
|
||||||
"""
|
"""
|
||||||
return _get_events(username, start, count)
|
return _get_events(username, start, count)
|
||||||
|
|
||||||
def get_org_user_events(org_id, username, start, count):
|
def get_org_user_events(org_id, username, start, count):
|
||||||
return _get_events(username, start, count, org_id=org_id)
|
return _get_events(username, start, count, org_id=org_id)
|
||||||
|
|
||||||
@@ -600,7 +601,7 @@ def calc_file_path_hash(path, bits=12):
|
|||||||
path = path.encode('UTF-8')
|
path = path.encode('UTF-8')
|
||||||
|
|
||||||
path_hash = hashlib.md5(urllib2.quote(path)).hexdigest()[:bits]
|
path_hash = hashlib.md5(urllib2.quote(path)).hexdigest()[:bits]
|
||||||
|
|
||||||
return path_hash
|
return path_hash
|
||||||
|
|
||||||
def get_service_url():
|
def get_service_url():
|
||||||
@@ -616,7 +617,7 @@ def get_server_id():
|
|||||||
def get_site_scheme_and_netloc():
|
def get_site_scheme_and_netloc():
|
||||||
"""Return a string contains site scheme and network location part from
|
"""Return a string contains site scheme and network location part from
|
||||||
service url.
|
service url.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
>>> get_site_scheme_and_netloc("https://example.com:8000/seafile/")
|
>>> get_site_scheme_and_netloc("https://example.com:8000/seafile/")
|
||||||
https://example.com:8000
|
https://example.com:8000
|
||||||
@@ -629,7 +630,7 @@ def send_html_email(subject, con_template, con_context, from_email, to_email):
|
|||||||
"""Send HTML email
|
"""Send HTML email
|
||||||
"""
|
"""
|
||||||
base_context = {
|
base_context = {
|
||||||
'url_base': get_site_scheme_and_netloc(),
|
'url_base': get_site_scheme_and_netloc(),
|
||||||
'site_name': SITE_NAME,
|
'site_name': SITE_NAME,
|
||||||
'media_url': MEDIA_URL,
|
'media_url': MEDIA_URL,
|
||||||
'logo_path': LOGO_PATH,
|
'logo_path': LOGO_PATH,
|
||||||
@@ -639,7 +640,7 @@ def send_html_email(subject, con_template, con_context, from_email, to_email):
|
|||||||
msg = EmailMessage(subject, t.render(Context(con_context)), from_email, to_email)
|
msg = EmailMessage(subject, t.render(Context(con_context)), from_email, to_email)
|
||||||
msg.content_subtype = "html"
|
msg.content_subtype = "html"
|
||||||
msg.send()
|
msg.send()
|
||||||
|
|
||||||
def gen_dir_share_link(token):
|
def gen_dir_share_link(token):
|
||||||
"""Generate directory share link.
|
"""Generate directory share link.
|
||||||
"""
|
"""
|
||||||
@@ -727,7 +728,7 @@ def convert_cmmt_desc_link(commit):
|
|||||||
"""
|
"""
|
||||||
repo_id = commit.repo_id
|
repo_id = commit.repo_id
|
||||||
cmmt_id = commit.id
|
cmmt_id = commit.id
|
||||||
conv_link_url = reverse('convert_cmmt_desc_link')
|
conv_link_url = reverse('convert_cmmt_desc_link')
|
||||||
|
|
||||||
def link_repl(matchobj):
|
def link_repl(matchobj):
|
||||||
op = matchobj.group(1)
|
op = matchobj.group(1)
|
||||||
@@ -776,7 +777,7 @@ def api_convert_desc_link(e):
|
|||||||
if file_or_dir not in d.name:
|
if file_or_dir not in d.name:
|
||||||
# skip to next diff_result if file/folder user clicked does not
|
# skip to next diff_result if file/folder user clicked does not
|
||||||
# match the diff_result
|
# match the diff_result
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if d.status == 'add' or d.status == 'mod':
|
if d.status == 'add' or d.status == 'mod':
|
||||||
e.link = "api://repo/%s/files/?p=/%s" % (repo_id, d.name)
|
e.link = "api://repo/%s/files/?p=/%s" % (repo_id, d.name)
|
||||||
@@ -820,7 +821,7 @@ if EVENTS_CONFIG_FILE:
|
|||||||
return seafevents.get_office_converter_limit(config)
|
return seafevents.get_office_converter_limit(config)
|
||||||
|
|
||||||
HAS_OFFICE_CONVERTER = check_office_converter_enabled()
|
HAS_OFFICE_CONVERTER = check_office_converter_enabled()
|
||||||
|
|
||||||
if HAS_OFFICE_CONVERTER:
|
if HAS_OFFICE_CONVERTER:
|
||||||
|
|
||||||
OFFICE_HTML_DIR = get_office_converter_html_dir()
|
OFFICE_HTML_DIR = get_office_converter_html_dir()
|
||||||
@@ -849,7 +850,7 @@ if HAS_OFFICE_CONVERTER:
|
|||||||
rpc = _get_office_converter_rpc()
|
rpc = _get_office_converter_rpc()
|
||||||
return rpc.query_file_pages(file_id)
|
return rpc.query_file_pages(file_id)
|
||||||
|
|
||||||
def get_converted_html_detail(file_id):
|
def get_converted_html_detail(file_id):
|
||||||
d = {}
|
d = {}
|
||||||
outline_file = os.path.join(OFFICE_HTML_DIR, file_id, 'file.outline')
|
outline_file = os.path.join(OFFICE_HTML_DIR, file_id, 'file.outline')
|
||||||
|
|
||||||
@@ -945,3 +946,51 @@ def user_traffic_over_limit(username):
|
|||||||
|
|
||||||
month_traffic = stat['file_view'] + stat['file_download'] + stat['dir_download']
|
month_traffic = stat['file_view'] + stat['file_download'] + stat['dir_download']
|
||||||
return True if month_traffic >= traffic_limit else False
|
return True if month_traffic >= traffic_limit else False
|
||||||
|
|
||||||
|
def is_user_password_strong(password):
|
||||||
|
"""Return ``True`` if user's password is STRONG, otherwise ``False``.
|
||||||
|
STRONG means password has at least USER_PASSWORD_STRENGTH_LEVEL(3) types of the bellow:
|
||||||
|
num, upper letter, lower letter, other symbols
|
||||||
|
"""
|
||||||
|
|
||||||
|
if len(password) < USER_PASSWORD_MIN_LENGTH:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
num = 0
|
||||||
|
for letter in password:
|
||||||
|
# get ascii dec
|
||||||
|
# bitwise OR
|
||||||
|
num |= get_char_mode(ord(letter))
|
||||||
|
|
||||||
|
if calculate_bitwise(num) < USER_PASSWORD_STRENGTH_LEVEL:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_char_mode(n):
|
||||||
|
"""Return different num according to the type of given letter:
|
||||||
|
'1': num,
|
||||||
|
'2': upper_letter,
|
||||||
|
'4': lower_letter,
|
||||||
|
'8': other symbols
|
||||||
|
"""
|
||||||
|
if (n >= 48 and n <= 57): #nums
|
||||||
|
return 1;
|
||||||
|
if (n >= 65 and n <= 90): #uppers
|
||||||
|
return 2;
|
||||||
|
if (n >= 97 and n <= 122): #lowers
|
||||||
|
return 4;
|
||||||
|
else:
|
||||||
|
return 8;
|
||||||
|
|
||||||
|
def calculate_bitwise(num):
|
||||||
|
"""Return different level according to the given num:
|
||||||
|
"""
|
||||||
|
level = 0
|
||||||
|
for i in range(4):
|
||||||
|
# bitwise AND
|
||||||
|
if (num&1):
|
||||||
|
level += 1
|
||||||
|
# Right logical shift
|
||||||
|
num = num >> 1
|
||||||
|
return level
|
||||||
|
@@ -79,7 +79,7 @@ def root(request):
|
|||||||
def validate_owner(request, repo_id):
|
def validate_owner(request, repo_id):
|
||||||
"""
|
"""
|
||||||
Check whether user in the request owns the repo.
|
Check whether user in the request owns the repo.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
ret = is_repo_owner(request.user.username, repo_id)
|
ret = is_repo_owner(request.user.username, repo_id)
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ def get_system_default_repo_id():
|
|||||||
def check_repo_access_permission(repo_id, user):
|
def check_repo_access_permission(repo_id, user):
|
||||||
"""Check repo access permission of a user, always return 'rw' when repo is
|
"""Check repo access permission of a user, always return 'rw' when repo is
|
||||||
system repo and user is admin.
|
system repo and user is admin.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
- `repo_id`:
|
- `repo_id`:
|
||||||
- `user`:
|
- `user`:
|
||||||
@@ -140,13 +140,13 @@ def check_repo_access_permission(repo_id, user):
|
|||||||
return 'rw'
|
return 'rw'
|
||||||
else:
|
else:
|
||||||
return seafile_api.check_repo_access_permission(repo_id, user.username)
|
return seafile_api.check_repo_access_permission(repo_id, user.username)
|
||||||
|
|
||||||
def get_file_access_permission(repo_id, path, username):
|
def get_file_access_permission(repo_id, path, username):
|
||||||
"""Check user has permission to view the file.
|
"""Check user has permission to view the file.
|
||||||
1. check whether this file is private shared.
|
1. check whether this file is private shared.
|
||||||
2. if failed, check whether the parent of this directory is private shared.
|
2. if failed, check whether the parent of this directory is private shared.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pfs = PrivateFileDirShare.objects.get_private_share_in_file(username,
|
pfs = PrivateFileDirShare.objects.get_private_share_in_file(username,
|
||||||
repo_id, path)
|
repo_id, path)
|
||||||
if pfs is None:
|
if pfs is None:
|
||||||
@@ -157,11 +157,11 @@ def get_file_access_permission(repo_id, path, username):
|
|||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
return pfs.permission
|
return pfs.permission
|
||||||
|
|
||||||
def gen_path_link(path, repo_name):
|
def gen_path_link(path, repo_name):
|
||||||
"""
|
"""
|
||||||
Generate navigate paths and links in repo page.
|
Generate navigate paths and links in repo page.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if path and path[-1] != '/':
|
if path and path[-1] != '/':
|
||||||
path += '/'
|
path += '/'
|
||||||
@@ -178,9 +178,9 @@ def gen_path_link(path, repo_name):
|
|||||||
if repo_name:
|
if repo_name:
|
||||||
paths.insert(0, repo_name)
|
paths.insert(0, repo_name)
|
||||||
links.insert(0, '/')
|
links.insert(0, '/')
|
||||||
|
|
||||||
zipped = zip(paths, links)
|
zipped = zip(paths, links)
|
||||||
|
|
||||||
return zipped
|
return zipped
|
||||||
|
|
||||||
def get_repo_dirents(request, repo, commit, path, offset=-1, limit=-1):
|
def get_repo_dirents(request, repo, commit, path, offset=-1, limit=-1):
|
||||||
@@ -584,7 +584,7 @@ def repo_change_passwd(request, repo_id):
|
|||||||
{'repo_name': repo.name})
|
{'repo_name': repo.name})
|
||||||
return HttpResponse(json.dumps({'success': True}),
|
return HttpResponse(json.dumps({'success': True}),
|
||||||
content_type=content_type)
|
content_type=content_type)
|
||||||
|
|
||||||
def upload_error_msg (code):
|
def upload_error_msg (code):
|
||||||
err_msg = _(u'Internal Server Error')
|
err_msg = _(u'Internal Server Error')
|
||||||
if (code == 0):
|
if (code == 0):
|
||||||
@@ -644,7 +644,7 @@ def update_file_error(request, repo_id):
|
|||||||
'zipped': zipped,
|
'zipped': zipped,
|
||||||
'err_msg': err_msg,
|
'err_msg': err_msg,
|
||||||
}, context_instance=RequestContext(request))
|
}, context_instance=RequestContext(request))
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def repo_history(request, repo_id):
|
def repo_history(request, repo_id):
|
||||||
"""
|
"""
|
||||||
@@ -663,8 +663,8 @@ def repo_history(request, repo_id):
|
|||||||
server_crypto = UserOptions.objects.is_server_crypto(username)
|
server_crypto = UserOptions.objects.is_server_crypto(username)
|
||||||
except CryptoOptionNotSetError:
|
except CryptoOptionNotSetError:
|
||||||
# Assume server_crypto is ``False`` if this option is not set.
|
# Assume server_crypto is ``False`` if this option is not set.
|
||||||
server_crypto = False
|
server_crypto = False
|
||||||
|
|
||||||
password_set = False
|
password_set = False
|
||||||
if repo.props.encrypted and \
|
if repo.props.encrypted and \
|
||||||
(repo.enc_version == 1 or (repo.enc_version == 2 and server_crypto)):
|
(repo.enc_version == 1 or (repo.enc_version == 2 and server_crypto)):
|
||||||
@@ -723,8 +723,8 @@ def repo_view_snapshot(request, repo_id):
|
|||||||
server_crypto = UserOptions.objects.is_server_crypto(username)
|
server_crypto = UserOptions.objects.is_server_crypto(username)
|
||||||
except CryptoOptionNotSetError:
|
except CryptoOptionNotSetError:
|
||||||
# Assume server_crypto is ``False`` if this option is not set.
|
# Assume server_crypto is ``False`` if this option is not set.
|
||||||
server_crypto = False
|
server_crypto = False
|
||||||
|
|
||||||
password_set = False
|
password_set = False
|
||||||
if repo.props.encrypted and \
|
if repo.props.encrypted and \
|
||||||
(repo.enc_version == 1 or (repo.enc_version == 2 and server_crypto)):
|
(repo.enc_version == 1 or (repo.enc_version == 2 and server_crypto)):
|
||||||
@@ -779,8 +779,8 @@ def repo_history_revert(request, repo_id):
|
|||||||
server_crypto = UserOptions.objects.is_server_crypto(username)
|
server_crypto = UserOptions.objects.is_server_crypto(username)
|
||||||
except CryptoOptionNotSetError:
|
except CryptoOptionNotSetError:
|
||||||
# Assume server_crypto is ``False`` if this option is not set.
|
# Assume server_crypto is ``False`` if this option is not set.
|
||||||
server_crypto = False
|
server_crypto = False
|
||||||
|
|
||||||
password_set = False
|
password_set = False
|
||||||
if repo.props.encrypted and \
|
if repo.props.encrypted and \
|
||||||
(repo.enc_version == 1 or (repo.enc_version == 2 and server_crypto)):
|
(repo.enc_version == 1 or (repo.enc_version == 2 and server_crypto)):
|
||||||
@@ -889,7 +889,7 @@ def create_default_library(request):
|
|||||||
default_repo, '/', obj_name, username, 0)
|
default_repo, '/', obj_name, username, 0)
|
||||||
except SearpcError as e:
|
except SearpcError as e:
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
return
|
return
|
||||||
|
|
||||||
UserOptions.objects.set_default_repo(username, default_repo)
|
UserOptions.objects.set_default_repo(username, default_repo)
|
||||||
|
|
||||||
@@ -984,7 +984,7 @@ def myhome(request):
|
|||||||
@user_mods_check
|
@user_mods_check
|
||||||
def starred(request):
|
def starred(request):
|
||||||
"""List starred files.
|
"""List starred files.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
- `request`:
|
- `request`:
|
||||||
"""
|
"""
|
||||||
@@ -995,7 +995,7 @@ def starred(request):
|
|||||||
return render_to_response('starred.html', {
|
return render_to_response('starred.html', {
|
||||||
"starred_files": starred_files,
|
"starred_files": starred_files,
|
||||||
}, context_instance=RequestContext(request))
|
}, context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@user_mods_check
|
@user_mods_check
|
||||||
@@ -1007,24 +1007,24 @@ def devices(request):
|
|||||||
return render_to_response('devices.html', {
|
return render_to_response('devices.html', {
|
||||||
"devices": user_devices,
|
"devices": user_devices,
|
||||||
}, context_instance=RequestContext(request))
|
}, context_instance=RequestContext(request))
|
||||||
|
|
||||||
@login_required_ajax
|
@login_required_ajax
|
||||||
def unlink_device(request):
|
def unlink_device(request):
|
||||||
content_type = 'application/json; charset=utf-8'
|
content_type = 'application/json; charset=utf-8'
|
||||||
|
|
||||||
platform = request.POST.get('platform', '')
|
platform = request.POST.get('platform', '')
|
||||||
device_id = request.POST.get('device_id', '')
|
device_id = request.POST.get('device_id', '')
|
||||||
|
|
||||||
if not platform or not device_id:
|
if not platform or not device_id:
|
||||||
return HttpResponseBadRequest(json.dumps({'error': _(u'Argument missing')}),
|
return HttpResponseBadRequest(json.dumps({'error': _(u'Argument missing')}),
|
||||||
content_type=content_type)
|
content_type=content_type)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
do_unlink_device(request.user.username, platform, device_id)
|
do_unlink_device(request.user.username, platform, device_id)
|
||||||
except:
|
except:
|
||||||
return HttpResponse(json.dumps({'error': _(u'Internal server error')}),
|
return HttpResponse(json.dumps({'error': _(u'Internal server error')}),
|
||||||
status=500, content_type=content_type)
|
status=500, content_type=content_type)
|
||||||
|
|
||||||
return HttpResponse(json.dumps({'success': True}), content_type=content_type)
|
return HttpResponse(json.dumps({'success': True}), content_type=content_type)
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@@ -1078,7 +1078,7 @@ def unsetinnerpub(request, repo_id):
|
|||||||
# quota_usage = seafserv_threaded_rpc.get_user_quota_usage(owner_name)
|
# quota_usage = seafserv_threaded_rpc.get_user_quota_usage(owner_name)
|
||||||
|
|
||||||
# user_dict = user_info(request, owner_name)
|
# user_dict = user_info(request, owner_name)
|
||||||
|
|
||||||
# return render_to_response('ownerhome.html', {
|
# return render_to_response('ownerhome.html', {
|
||||||
# "owned_repos": owned_repos,
|
# "owned_repos": owned_repos,
|
||||||
# "quota_usage": quota_usage,
|
# "quota_usage": quota_usage,
|
||||||
@@ -1090,10 +1090,10 @@ def unsetinnerpub(request, repo_id):
|
|||||||
def repo_set_access_property(request, repo_id):
|
def repo_set_access_property(request, repo_id):
|
||||||
ap = request.GET.get('ap', '')
|
ap = request.GET.get('ap', '')
|
||||||
seafserv_threaded_rpc.repo_set_access_property(repo_id, ap)
|
seafserv_threaded_rpc.repo_set_access_property(repo_id, ap)
|
||||||
|
|
||||||
return HttpResponseRedirect(reverse('repo', args=[repo_id]))
|
return HttpResponseRedirect(reverse('repo', args=[repo_id]))
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def repo_del_file(request, repo_id):
|
def repo_del_file(request, repo_id):
|
||||||
if check_repo_access_permission(repo_id, request.user) != 'rw':
|
if check_repo_access_permission(repo_id, request.user) != 'rw':
|
||||||
return render_permission_error(request, _('Failed to delete file.'))
|
return render_permission_error(request, _('Failed to delete file.'))
|
||||||
@@ -1109,7 +1109,7 @@ def repo_del_file(request, repo_id):
|
|||||||
|
|
||||||
url = reverse('repo', args=[repo_id]) + ('?p=%s' % urllib2.quote(parent_dir.encode('utf-8')))
|
url = reverse('repo', args=[repo_id]) + ('?p=%s' % urllib2.quote(parent_dir.encode('utf-8')))
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
def repo_access_file(request, repo_id, obj_id):
|
def repo_access_file(request, repo_id, obj_id):
|
||||||
"""Delete or download file.
|
"""Delete or download file.
|
||||||
TODO: need to be rewrite.
|
TODO: need to be rewrite.
|
||||||
@@ -1190,7 +1190,7 @@ def file_upload_progress_page(request):
|
|||||||
'upload_progress_con_id': upload_progress_con_id,
|
'upload_progress_con_id': upload_progress_con_id,
|
||||||
}, context_instance=RequestContext(request))
|
}, context_instance=RequestContext(request))
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def validate_filename(request):
|
def validate_filename(request):
|
||||||
repo_id = request.GET.get('repo_id')
|
repo_id = request.GET.get('repo_id')
|
||||||
filename = request.GET.get('filename')
|
filename = request.GET.get('filename')
|
||||||
@@ -1240,7 +1240,7 @@ def render_file_revisions (request, repo_id):
|
|||||||
|
|
||||||
if not commits:
|
if not commits:
|
||||||
return render_error(request)
|
return render_error(request)
|
||||||
|
|
||||||
# Check whether user is repo owner
|
# Check whether user is repo owner
|
||||||
if validate_owner(request, repo_id):
|
if validate_owner(request, repo_id):
|
||||||
is_owner = True
|
is_owner = True
|
||||||
@@ -1400,10 +1400,10 @@ def view_shared_dir(request, token):
|
|||||||
repo_id = fileshare.repo_id
|
repo_id = fileshare.repo_id
|
||||||
path = request.GET.get('p', '')
|
path = request.GET.get('p', '')
|
||||||
path = fileshare.path if not path else path
|
path = fileshare.path if not path else path
|
||||||
if path[-1] != '/': # Normalize dir path
|
if path[-1] != '/': # Normalize dir path
|
||||||
path += '/'
|
path += '/'
|
||||||
|
|
||||||
if not path.startswith(fileshare.path):
|
if not path.startswith(fileshare.path):
|
||||||
path = fileshare.path # Can not view upper dir of shared dir
|
path = fileshare.path # Can not view upper dir of shared dir
|
||||||
|
|
||||||
repo = get_repo(repo_id)
|
repo = get_repo(repo_id)
|
||||||
@@ -1417,13 +1417,13 @@ def view_shared_dir(request, token):
|
|||||||
zipped = gen_path_link(path, '')
|
zipped = gen_path_link(path, '')
|
||||||
|
|
||||||
if path == fileshare.path: # When user view the shared dir..
|
if path == fileshare.path: # When user view the shared dir..
|
||||||
# increase shared link view_cnt,
|
# increase shared link view_cnt,
|
||||||
fileshare = FileShare.objects.get(token=token)
|
fileshare = FileShare.objects.get(token=token)
|
||||||
fileshare.view_cnt = F('view_cnt') + 1
|
fileshare.view_cnt = F('view_cnt') + 1
|
||||||
fileshare.save()
|
fileshare.save()
|
||||||
|
|
||||||
traffic_over_limit = user_traffic_over_limit(fileshare.username)
|
traffic_over_limit = user_traffic_over_limit(fileshare.username)
|
||||||
|
|
||||||
return render_to_response('view_shared_dir.html', {
|
return render_to_response('view_shared_dir.html', {
|
||||||
'repo': repo,
|
'repo': repo,
|
||||||
'token': token,
|
'token': token,
|
||||||
@@ -1461,7 +1461,7 @@ def view_shared_upload_link(request, token):
|
|||||||
else:
|
else:
|
||||||
return render_to_response('share_access_validation.html', d,
|
return render_to_response('share_access_validation.html', d,
|
||||||
context_instance=RequestContext(request))
|
context_instance=RequestContext(request))
|
||||||
|
|
||||||
username = uploadlink.username
|
username = uploadlink.username
|
||||||
repo_id = uploadlink.repo_id
|
repo_id = uploadlink.repo_id
|
||||||
path = uploadlink.path
|
path = uploadlink.path
|
||||||
@@ -1525,9 +1525,9 @@ def pubrepo(request):
|
|||||||
"""
|
"""
|
||||||
if not request.user.permissions.can_view_org():
|
if not request.user.permissions.can_view_org():
|
||||||
raise Http404
|
raise Http404
|
||||||
|
|
||||||
username = request.user.username
|
username = request.user.username
|
||||||
|
|
||||||
if request.cloud_mode and request.user.org is not None:
|
if request.cloud_mode and request.user.org is not None:
|
||||||
org_id = request.user.org.org_id
|
org_id = request.user.org.org_id
|
||||||
public_repos = seaserv.list_org_inner_pub_repos(org_id, username)
|
public_repos = seaserv.list_org_inner_pub_repos(org_id, username)
|
||||||
@@ -1538,7 +1538,7 @@ def pubrepo(request):
|
|||||||
'public_repos': public_repos,
|
'public_repos': public_repos,
|
||||||
'create_shared_repo': True,
|
'create_shared_repo': True,
|
||||||
}, context_instance=RequestContext(request))
|
}, context_instance=RequestContext(request))
|
||||||
|
|
||||||
if not request.cloud_mode:
|
if not request.cloud_mode:
|
||||||
public_repos = seaserv.list_inner_pub_repos(username)
|
public_repos = seaserv.list_inner_pub_repos(username)
|
||||||
for r in public_repos:
|
for r in public_repos:
|
||||||
@@ -1558,14 +1558,14 @@ def pubgrp(request):
|
|||||||
"""
|
"""
|
||||||
if not request.user.permissions.can_view_org():
|
if not request.user.permissions.can_view_org():
|
||||||
raise Http404
|
raise Http404
|
||||||
|
|
||||||
if request.cloud_mode and request.user.org is not None:
|
if request.cloud_mode and request.user.org is not None:
|
||||||
org_id = request.user.org.org_id
|
org_id = request.user.org.org_id
|
||||||
groups = seaserv.get_org_groups(org_id, -1, -1)
|
groups = seaserv.get_org_groups(org_id, -1, -1)
|
||||||
return render_to_response('organizations/pubgrp.html', {
|
return render_to_response('organizations/pubgrp.html', {
|
||||||
'groups': groups,
|
'groups': groups,
|
||||||
}, context_instance=RequestContext(request))
|
}, context_instance=RequestContext(request))
|
||||||
|
|
||||||
if not request.cloud_mode:
|
if not request.cloud_mode:
|
||||||
groups = seaserv.get_personal_groups(-1, -1)
|
groups = seaserv.get_personal_groups(-1, -1)
|
||||||
return render_to_response('pubgrp.html', {
|
return render_to_response('pubgrp.html', {
|
||||||
@@ -1579,7 +1579,7 @@ def get_pub_users(request, start, limit):
|
|||||||
url_prefix = request.user.org.url_prefix
|
url_prefix = request.user.org.url_prefix
|
||||||
users_plus_one = seaserv.get_org_users_by_url_prefix(url_prefix,
|
users_plus_one = seaserv.get_org_users_by_url_prefix(url_prefix,
|
||||||
start, limit)
|
start, limit)
|
||||||
|
|
||||||
elif request.cloud_mode:
|
elif request.cloud_mode:
|
||||||
raise Http404 # no pubuser in cloud mode
|
raise Http404 # no pubuser in cloud mode
|
||||||
|
|
||||||
@@ -1608,7 +1608,7 @@ def pubuser(request):
|
|||||||
"""
|
"""
|
||||||
if not request.user.permissions.can_view_org():
|
if not request.user.permissions.can_view_org():
|
||||||
raise Http404
|
raise Http404
|
||||||
|
|
||||||
# Make sure page request is an int. If not, deliver first page.
|
# Make sure page request is an int. If not, deliver first page.
|
||||||
try:
|
try:
|
||||||
current_page = int(request.GET.get('page', '1'))
|
current_page = int(request.GET.get('page', '1'))
|
||||||
@@ -1629,21 +1629,21 @@ def pubuser(request):
|
|||||||
users = users_plus_one[:per_page]
|
users = users_plus_one[:per_page]
|
||||||
username = request.user.username
|
username = request.user.username
|
||||||
contacts = Contact.objects.get_contacts_by_user(username)
|
contacts = Contact.objects.get_contacts_by_user(username)
|
||||||
contact_emails = []
|
contact_emails = []
|
||||||
for c in contacts:
|
for c in contacts:
|
||||||
contact_emails.append(c.contact_email)
|
contact_emails.append(c.contact_email)
|
||||||
for u in users:
|
for u in users:
|
||||||
if u.email == username or u.email in contact_emails:
|
if u.email == username or u.email in contact_emails:
|
||||||
u.can_be_contact = False
|
u.can_be_contact = False
|
||||||
else:
|
else:
|
||||||
u.can_be_contact = True
|
u.can_be_contact = True
|
||||||
|
|
||||||
return render_to_response('pubuser.html', {
|
return render_to_response('pubuser.html', {
|
||||||
'users': users,
|
'users': users,
|
||||||
'current_page': current_page,
|
'current_page': current_page,
|
||||||
'has_prev': has_prev,
|
'has_prev': has_prev,
|
||||||
'has_next': has_next,
|
'has_next': has_next,
|
||||||
'page_range': page_range,
|
'page_range': page_range,
|
||||||
}, context_instance=RequestContext(request))
|
}, context_instance=RequestContext(request))
|
||||||
|
|
||||||
@login_required_ajax
|
@login_required_ajax
|
||||||
@@ -1693,7 +1693,7 @@ def repo_download_dir(request, repo_id):
|
|||||||
dirname = os.path.basename(path.rstrip('/')) # Here use `rstrip` to cut out last '/' in path
|
dirname = os.path.basename(path.rstrip('/')) # Here use `rstrip` to cut out last '/' in path
|
||||||
else:
|
else:
|
||||||
dirname = repo.name
|
dirname = repo.name
|
||||||
|
|
||||||
allow_download = False
|
allow_download = False
|
||||||
fileshare_token = request.GET.get('t', '')
|
fileshare_token = request.GET.get('t', '')
|
||||||
from_shared_link = False
|
from_shared_link = False
|
||||||
@@ -1789,18 +1789,18 @@ def group_events_data(events):
|
|||||||
utc = dt.replace(tzinfo=timezone.utc)
|
utc = dt.replace(tzinfo=timezone.utc)
|
||||||
local = timezone.make_naive(utc, tz)
|
local = timezone.make_naive(utc, tz)
|
||||||
return local
|
return local
|
||||||
|
|
||||||
event_groups = []
|
event_groups = []
|
||||||
for e in events:
|
for e in events:
|
||||||
e.time = utc_to_local(e.timestamp)
|
e.time = utc_to_local(e.timestamp)
|
||||||
e.date = e.time.strftime("%Y-%m-%d")
|
e.date = e.time.strftime("%Y-%m-%d")
|
||||||
if e.etype == 'repo-update':
|
if e.etype == 'repo-update':
|
||||||
e.author = e.commit.creator_name
|
e.author = e.commit.creator_name
|
||||||
elif e.etype == 'repo-create':
|
elif e.etype == 'repo-create':
|
||||||
e.author = e.creator
|
e.author = e.creator
|
||||||
else:
|
else:
|
||||||
e.author = e.repo_owner
|
e.author = e.repo_owner
|
||||||
|
|
||||||
if len(event_groups) == 0 or \
|
if len(event_groups) == 0 or \
|
||||||
len(event_groups) > 0 and e.date != event_groups[-1]['date']:
|
len(event_groups) > 0 and e.date != event_groups[-1]['date']:
|
||||||
event_group = {}
|
event_group = {}
|
||||||
@@ -1814,7 +1814,7 @@ def group_events_data(events):
|
|||||||
|
|
||||||
def pdf_full_view(request):
|
def pdf_full_view(request):
|
||||||
'''For pdf view with pdf.js.'''
|
'''For pdf view with pdf.js.'''
|
||||||
|
|
||||||
repo_id = request.GET.get('repo_id', '')
|
repo_id = request.GET.get('repo_id', '')
|
||||||
obj_id = request.GET.get('obj_id', '')
|
obj_id = request.GET.get('obj_id', '')
|
||||||
file_name = request.GET.get('file_name', '')
|
file_name = request.GET.get('file_name', '')
|
||||||
@@ -1840,7 +1840,7 @@ def convert_cmmt_desc_link(request):
|
|||||||
# perm check
|
# perm check
|
||||||
if check_repo_access_permission(repo_id, request.user) is None:
|
if check_repo_access_permission(repo_id, request.user) is None:
|
||||||
raise Http404
|
raise Http404
|
||||||
|
|
||||||
diff_result = seafserv_threaded_rpc.get_diff(repo_id, '', cmmt_id)
|
diff_result = seafserv_threaded_rpc.get_diff(repo_id, '', cmmt_id)
|
||||||
if not diff_result:
|
if not diff_result:
|
||||||
raise Http404
|
raise Http404
|
||||||
@@ -1849,7 +1849,7 @@ def convert_cmmt_desc_link(request):
|
|||||||
if name not in d.name:
|
if name not in d.name:
|
||||||
# skip to next diff_result if file/folder user clicked does not
|
# skip to next diff_result if file/folder user clicked does not
|
||||||
# match the diff_result
|
# match the diff_result
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if d.status == 'add' or d.status == 'mod': # Add or modify file
|
if d.status == 'add' or d.status == 'mod': # Add or modify file
|
||||||
return HttpResponseRedirect(reverse('repo_view_file', args=[repo_id]) + \
|
return HttpResponseRedirect(reverse('repo_view_file', args=[repo_id]) + \
|
||||||
@@ -1879,7 +1879,7 @@ def toggle_modules(request):
|
|||||||
|
|
||||||
referer = request.META.get('HTTP_REFERER', None)
|
referer = request.META.get('HTTP_REFERER', None)
|
||||||
next = settings.SITE_ROOT if referer is None else referer
|
next = settings.SITE_ROOT if referer is None else referer
|
||||||
|
|
||||||
username = request.user.username
|
username = request.user.username
|
||||||
personal_wiki = request.POST.get('personal_wiki', 'off')
|
personal_wiki = request.POST.get('personal_wiki', 'off')
|
||||||
if personal_wiki == 'on':
|
if personal_wiki == 'on':
|
||||||
|
@@ -9,6 +9,8 @@ from django.shortcuts import render_to_response
|
|||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
|
|
||||||
from registration.backends import get_backend
|
from registration.backends import get_backend
|
||||||
|
from seahub.settings import USER_PASSWORD_MIN_LENGTH, \
|
||||||
|
USER_STRONG_PASSWORD_REQUIRED, USER_PASSWORD_STRENGTH_LEVEL
|
||||||
|
|
||||||
def activate(request, backend,
|
def activate(request, backend,
|
||||||
template_name='registration/activate.html',
|
template_name='registration/activate.html',
|
||||||
@@ -204,5 +206,8 @@ def register(request, backend, success_url=None, form_class=None,
|
|||||||
form = form_class(initial={'email': src})
|
form = form_class(initial={'email': src})
|
||||||
|
|
||||||
return render_to_response(template_name,
|
return render_to_response(template_name,
|
||||||
{ 'form': form },
|
{ 'form': form,
|
||||||
context_instance=context)
|
'min_len': USER_PASSWORD_MIN_LENGTH,
|
||||||
|
'strong_pwd_required': USER_STRONG_PASSWORD_REQUIRED,
|
||||||
|
'level': USER_PASSWORD_STRENGTH_LEVEL,
|
||||||
|
}, context_instance=context)
|
||||||
|
Reference in New Issue
Block a user