1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-25 14:50:29 +00:00

Add ENABLE_ADDRESSBOOK_OPT_IN setting

Enable user to choose if show himself in global address book
This commit is contained in:
lian
2017-08-12 15:10:08 +08:00
parent 4cae20f376
commit 9bdbb1671a
12 changed files with 241 additions and 41 deletions

View File

@@ -43,6 +43,7 @@ def get_account_info(user):
info['is_active'] = user.is_active
info['create_time'] = user.ctime
info['login_id'] = profile.login_id if profile else ''
info['list_in_address_book'] = profile.list_in_address_book if profile else False
info['total'] = seafile_api.get_user_quota(email)
info['usage'] = seafile_api.get_user_self_usage(email)
@@ -106,7 +107,7 @@ class Account(APIView):
def _update_account_additional_info(self, request, email):
# update account profile
# update account name
name = request.data.get("name", None)
if name is not None:
profile = Profile.objects.get_profile_by_user(email)
@@ -115,6 +116,16 @@ class Account(APIView):
profile.nickname = name
profile.save()
# update account list_in_address_book
list_in_address_book = request.data.get("list_in_address_book", None)
if list_in_address_book is not None:
profile = Profile.objects.get_profile_by_user(email)
if profile is None:
profile = Profile(user=email)
profile.list_in_address_book = list_in_address_book.lower() == 'true'
profile.save()
# update account loginid
loginid = request.data.get("login_id", '').strip()
if loginid != '':
@@ -186,6 +197,13 @@ class Account(APIView):
return api_error(status.HTTP_400_BAD_REQUEST,
_(u"Name should not include '/'."))
# argument check for list_in_address_book
list_in_address_book = request.data.get("list_in_address_book", None)
if list_in_address_book is not None:
if list_in_address_book.lower() not in ('true', 'false'):
return api_error(status.HTTP_400_BAD_REQUEST,
'list_in_address_book invalid')
#argument check for loginid
loginid = request.data.get("login_id", None)
if loginid is not None:

View File

@@ -1,14 +1,14 @@
# Copyright (c) 2012-2016 Seafile Ltd.
import os
import sys
import json
import logging
from django.db.models import Q
from django.http import HttpResponse
from django.conf import settings as django_settings
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status
@@ -19,7 +19,8 @@ from seahub.api2.throttling import UserRateThrottle
from seahub.api2.utils import api_error
from seahub.utils import is_valid_email, is_org_context
from seahub.base.accounts import User
from seahub.base.templatetags.seahub_tags import email2nickname
from seahub.base.templatetags.seahub_tags import email2nickname, \
email2contact_email
from seahub.profile.models import Profile
from seahub.contacts.models import Contact
from seahub.avatar.templatetags.avatar_tags import api_avatar_url
@@ -115,7 +116,8 @@ class SearchUser(APIView):
# search user from user's contacts
email_list += search_user_when_global_address_book_disabled(request, q)
## search finished
## search finished, now filter out some users
# remove duplicate emails
email_list = {}.fromkeys(email_list).keys()
@@ -129,6 +131,13 @@ class SearchUser(APIView):
except User.DoesNotExist:
continue
if django_settings.ENABLE_ADDRESSBOOK_OPT_IN:
# get users who has setted to show in address book
listed_users = Profile.objects.filter(list_in_address_book=True).values('user')
listed_user_list = [ u['user'] for u in listed_users ]
email_result = list(set(email_result) & set(listed_user_list))
# check if include myself in user result
try:
include_self = int(request.GET.get('include_self', 1))
@@ -151,8 +160,7 @@ class SearchUser(APIView):
formated_result = format_searched_user_result(
request, email_result[:10], size)
return HttpResponse(json.dumps({"users": formated_result}),
status=200, content_type='application/json; charset=utf-8')
return Response({"users": formated_result})
def format_searched_user_result(request, users, size):
results = []
@@ -163,7 +171,7 @@ def format_searched_user_result(request, users, size):
"email": email,
"avatar_url": request.build_absolute_uri(url),
"name": email2nickname(email),
"contact_email": Profile.objects.get_contact_email_by_user(email),
"contact_email": email2contact_email(email),
})
return results

View File

@@ -0,0 +1,76 @@
# Copyright (c) 2012-2016 Seafile Ltd.
import logging
from rest_framework import status
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from seahub.api2.authentication import TokenAuthentication
from seahub.api2.throttling import UserRateThrottle
from seahub.api2.utils import api_error
from seahub.base.templatetags.seahub_tags import email2nickname, \
email2contact_email
from seahub.profile.models import Profile
logger = logging.getLogger(__name__)
json_content_type = 'application/json; charset=utf-8'
class User(APIView):
""" Query/update user info of myself.
"""
authentication_classes = (TokenAuthentication, SessionAuthentication)
permission_classes = (IsAuthenticated, )
throttle_classes = (UserRateThrottle, )
def _get_user_info(self, email):
profile = Profile.objects.get_profile_by_user(email)
info = {}
info['email'] = email
info['name'] = email2nickname(email)
info['contact_email'] = email2contact_email(email)
info['list_in_address_book'] = profile.list_in_address_book if profile else False
return info
def _update_user_additional_info(self, request, email):
# update user list_in_address_book
list_in_address_book = request.data.get("list_in_address_book", None)
if list_in_address_book is not None:
profile = Profile.objects.get_profile_by_user(email)
if profile is None:
profile = Profile(user=email)
profile.list_in_address_book = list_in_address_book.lower() == 'true'
profile.save()
def get(self, request):
email = request.user.username
info = self._get_user_info(email)
return Response(info)
def put(self, request):
email = request.user.username
# argument check for list_in_address_book
list_in_address_book = request.data.get("list_in_address_book", None)
if list_in_address_book is not None:
if list_in_address_book.lower() not in ('true', 'false'):
error_msg = 'list_in_address_book invalid.'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
try:
# update user additional info
self._update_user_additional_info(request, email)
except Exception as e:
logger.error(e)
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
# get user info and return
info = self._get_user_info(email)
return Response(info)

View File

@@ -6,7 +6,7 @@ from .views_misc import ServerInfoView
from .views_auth import LogoutDeviceView, ClientLoginTokenView
from .endpoints.admin.two_factor_auth import TwoFactorAuthView
from .endpoints.dir_shared_items import DirSharedItemsEndpoint
from .endpoints.account import Account
from .endpoints.admin.account import Account
from .endpoints.shared_upload_links import SharedUploadLinksView
from .endpoints.be_shared_repo import BeSharedRepo
from .endpoints.file_comment import FileCommentView

View File

@@ -101,6 +101,7 @@ class Profile(models.Model):
# Contact email is used to receive emails.
contact_email = models.EmailField(max_length=225, db_index=True, null=True, blank=True)
institution = models.CharField(max_length=225, db_index=True, null=True, blank=True, default='')
list_in_address_book = models.BooleanField(default=False, db_index=True)
objects = ProfileManager()
def set_lang_code(self, lang_code):

View File

@@ -75,6 +75,20 @@
</form>
</div>
{% if ENABLE_ADDRESSBOOK_OPT_IN %}
<div class="setting-item" id="list-in-address-book">
<h3>{% trans "Global Address Book" %}</h3>
<form id="list-in-address-book-form" method="post" action="">{% csrf_token %}
{% if form.data.list_in_address_book %}
<input type="checkbox" name="list_in_address_book" checked="checked">
{% else %}
<input type="checkbox" name="list_in_address_book">
{% endif %}
<label for="list_in_address_book">{% trans "List my account in global address book, so that others can find you by type your name." %}</label>
</form>
</div>
{% endif %}
<div class="setting-item" id="lang-setting">
<h3>{% trans "Language Setting" %}</h3>
<a href="#" id="lang-context" data-lang="{{ LANGUAGE_CODE }}">{{ LANGUAGE_CODE|language_name_local }} <span class="icon-caret-down"></span></a>
@@ -234,6 +248,32 @@ $('#default-lib-form').submit(function() {
});
{% endif %}
{% if ENABLE_ADDRESSBOOK_OPT_IN %}
$("#list-in-address-book input[type='checkbox']").change(function() {
var _this = $(this), data = {};
if (_this.prop('checked')) {
data['list_in_address_book'] = 'true';
} else {
data['list_in_address_book'] = 'false';
}
$.ajax({
url: "{% url 'api-v2.1-user' %}",
type: 'PUT',
dataType: 'json',
cache: false,
beforeSend: prepareCSRFToken,
data: data,
success: function(data) {
_this.attr('checked', data['list_in_address_book']);
feedback("{% trans "Success" %}", 'success');
},
error: ajaxErrorHandler
});
});
{% endif %}
(function() {
var lang_context = $('#lang-context'),
lang_selector = $('#lang-context-selector');

View File

@@ -1,6 +1,5 @@
# Copyright (c) 2012-2016 Seafile Ltd.
# encoding: utf-8
from constance import config
from django.conf import settings
import json
from django.core.urlresolvers import reverse
@@ -15,7 +14,6 @@ from seaserv import seafile_api
from forms import DetailedProfileForm
from models import Profile, DetailedProfile
from utils import refresh_cache
from seahub.auth.decorators import login_required
from seahub.utils import is_org_context, is_pro_version, is_valid_username
from seahub.base.accounts import User
@@ -53,9 +51,11 @@ def edit_profile(request):
init_dict['nickname'] = profile.nickname
init_dict['login_id'] = profile.login_id
init_dict['contact_email'] = profile.contact_email
init_dict['list_in_address_book'] = profile.list_in_address_book
if d_profile:
init_dict['department'] = d_profile.department
init_dict['telephone'] = d_profile.telephone
form = form_class(init_dict)
# common logic
@@ -81,6 +81,7 @@ def edit_profile(request):
'server_crypto': server_crypto,
"sub_lib_enabled": sub_lib_enabled,
'force_server_crypto': settings.FORCE_SERVER_CRYPTO,
'ENABLE_ADDRESSBOOK_OPT_IN': settings.ENABLE_ADDRESSBOOK_OPT_IN,
'default_repo': default_repo,
'owned_repos': owned_repos,
'is_pro': is_pro_version(),

View File

@@ -566,6 +566,7 @@ OFFICE_TEMPLATE_ROOT = os.path.join(MEDIA_ROOT, 'office-template')
# Global AddressBook #
#####################
ENABLE_GLOBAL_ADDRESSBOOK = True
ENABLE_ADDRESSBOOK_OPT_IN = False
#####################
# Folder Permission #

View File

@@ -50,6 +50,7 @@ from seahub.api2.endpoints.user_enabled_modules import UserEnabledModulesView
from seahub.api2.endpoints.repo_file_uploaded_bytes import RepoFileUploadedBytesView
from seahub.api2.endpoints.user_avatar import UserAvatarView
from seahub.api2.endpoints.revision_tag import TaggedItemsView,TagNamesView
from seahub.api2.endpoints.user import User
# Admin
from seahub.api2.endpoints.admin.revision_tag import AdminTaggedItemsView
@@ -200,6 +201,9 @@ urlpatterns = patterns(
### Apps ###
(r'^api2/', include('seahub.api2.urls')),
## user
url(r'^api/v2.1/user/$', User.as_view(), name="api-v2.1-user"),
## user::groups
url(r'^api/v2.1/groups/$', Groups.as_view(), name='api-v2.1-groups'),
url(r'^api/v2.1/groups/all/$', AllGroupsView.as_view(), name='api-v2.1-all-groups'),
@@ -258,7 +262,6 @@ urlpatterns = patterns(
url(r'^api/v2.1/notification/$', NotificationView.as_view(), name='api-v2.1-notification'),
url(r'^api/v2.1/user-enabled-modules/$', UserEnabledModulesView.as_view(), name='api-v2.1-user-enabled-module'),
## user::invitations
url(r'^api/v2.1/invitations/$', InvitationsView.as_view()),
url(r'^api/v2.1/invitations/(?P<token>[a-f0-9]{32})/$', InvitationView.as_view()),

View File

@@ -9,8 +9,6 @@ from seahub.base.templatetags.seahub_tags import email2nickname
from seahub.profile.models import Profile
from seahub.test_utils import BaseTestCase
from tests.common.utils import randstring
from tests.api.urls import TOKEN_URL
from seahub.api2.models import TokenV2
class AccountTest(BaseTestCase):
def setUp(self):
@@ -113,7 +111,7 @@ class AccountTest(BaseTestCase):
resp = self._do_get_info()
json_resp = json.loads(resp.content)
assert len(json_resp) == 11
assert len(json_resp) == 12
assert json_resp['email'] == self.user1.username
assert json_resp['is_staff'] is False
assert json_resp['is_active'] is True
@@ -145,14 +143,14 @@ class AccountTest(BaseTestCase):
def test_update_name(self):
"""only test name"""
self.login_as(self.admin)
self._do_update_name()
resp = self._do_update_name()
self.assertEqual(Profile.objects.get_profile_by_user(
self.user1.username).nickname, 'user1')
def test_update_loginid(self):
"""only test loginid"""
self.login_as(self.admin)
self._do_update_loginid()
resp = self._do_update_loginid()
self.assertEqual(Profile.objects.get_profile_by_user(
self.user1.username).login_id, 'hello')
@@ -242,29 +240,6 @@ class AccountTest(BaseTestCase):
self.assertEqual(user2_groups[1].id, other_group.id)
self.assertEqual(user2_groups[1].creator_name, self.user.username)
def test_inactive_user(self):
self.login_as(self.admin)
username = self.user1.username
data = {
'username': username,
'password': 'secret',
'platform': 'windows',
'device_id': randstring(length=40),
'device_name': 'fake-device-name',
'client_version': '4.1.0',
'platform_version': '',
}
self.client.post(TOKEN_URL, data=data)
assert len(TokenV2.objects.filter(user=username)) == 1
url = reverse('api2-account', args=[self.user1.username])
data = 'is_active=0'
resp = self.client.put(url, data, 'application/x-www-form-urlencoded')
self.assertEqual(200, resp.status_code)
assert len(TokenV2.objects.filter(user=username)) == 0
def test_delete(self):
self.login_as(self.admin)

View File

@@ -17,6 +17,7 @@ class SearchUserTest(BaseTestCase):
self.endpoint = reverse('search-user')
@override_settings(CLOUD_MODE = False)
@override_settings(ENABLE_ADDRESSBOOK_OPT_IN = False)
def test_can_search(self):
email = self.admin.email
nickname = 'admin_test'
@@ -35,7 +36,37 @@ class SearchUserTest(BaseTestCase):
assert json_resp['users'][0]['name'] == nickname
assert json_resp['users'][0]['contact_email'] == contact_email
@override_settings(ENABLE_ADDRESSBOOK_OPT_IN = True)
def test_search_when_enable_addressbook_opt_in(self):
email = self.admin.email
nickname = 'admin_test'
contact_email= 'new_admin_test@test.com'
p = Profile.objects.add_or_update(email, nickname=nickname)
p.contact_email = contact_email
p.save()
resp = self.client.get(self.endpoint + '?q=' + email)
json_resp = json.loads(resp.content)
self.assertEqual(200, resp.status_code)
assert json_resp['users'] is not None
assert len(json_resp['users']) == 0
p.list_in_address_book = True
p.save()
resp = self.client.get(self.endpoint + '?q=' + email)
json_resp = json.loads(resp.content)
self.assertEqual(200, resp.status_code)
assert json_resp['users'] is not None
assert json_resp['users'][0]['email'] == email
assert json_resp['users'][0]['avatar_url'] is not None
assert json_resp['users'][0]['name'] == nickname
assert json_resp['users'][0]['contact_email'] == contact_email
@override_settings(CLOUD_MODE = False)
@override_settings(ENABLE_ADDRESSBOOK_OPT_IN = False)
def test_search_myself(self):
email = self.user.email
nickname = 'user_test'
@@ -55,6 +86,7 @@ class SearchUserTest(BaseTestCase):
assert json_resp['users'][0]['contact_email'] == contact_email
@override_settings(CLOUD_MODE = False)
@override_settings(ENABLE_ADDRESSBOOK_OPT_IN = False)
def test_search_without_myself(self):
email = self.user.email
resp = self.client.get(self.endpoint + '?include_self=0&q=' + email)
@@ -64,6 +96,7 @@ class SearchUserTest(BaseTestCase):
assert len(json_resp['users']) == 0
@override_settings(CLOUD_MODE = False)
@override_settings(ENABLE_ADDRESSBOOK_OPT_IN = False)
def test_search_unregistered_user(self):
resp = self.client.get(self.endpoint + '?q=unregistered_user@seafile.com')
json_resp = json.loads(resp.content)
@@ -72,6 +105,7 @@ class SearchUserTest(BaseTestCase):
assert len(json_resp['users']) == 0
@override_settings(CLOUD_MODE = False)
@override_settings(ENABLE_ADDRESSBOOK_OPT_IN = False)
def test_can_search_by_nickname(self):
admin_email = self.admin.email
@@ -92,6 +126,7 @@ class SearchUserTest(BaseTestCase):
assert json_resp['users'][0]['contact_email'] == 'new_mail@test.com'
@override_settings(CLOUD_MODE = False)
@override_settings(ENABLE_ADDRESSBOOK_OPT_IN = False)
def test_can_search_by_nickname_insensitive(self):
admin_email = self.admin.email
@@ -124,6 +159,7 @@ class SearchUserTest(BaseTestCase):
assert json_resp['users'][0]['contact_email'] == 'new_mail@test.com'
@override_settings(CLOUD_MODE = False)
@override_settings(ENABLE_ADDRESSBOOK_OPT_IN = False)
def test_can_search_by_contact_email(self):
admin_email = self.admin.email
nickname = 'admin_test'
@@ -146,6 +182,7 @@ class SearchUserTest(BaseTestCase):
@override_settings(CLOUD_MODE = True)
@override_settings(ENABLE_GLOBAL_ADDRESSBOOK = False)
@override_settings(ENABLE_ADDRESSBOOK_OPT_IN = False)
@patch('seahub.api2.endpoints.search_user.is_org_context')
def test_search_full_email(self, mock_is_org_context):
@@ -158,6 +195,7 @@ class SearchUserTest(BaseTestCase):
assert json_resp['users'][0]['email'] == self.admin.username
@patch.object(SearchUser, '_can_use_global_address_book')
@override_settings(ENABLE_ADDRESSBOOK_OPT_IN = False)
def test_search_when_not_use_global_address_book(self, mock_can_use_global_address_book):
mock_can_use_global_address_book.return_value = False

View File

@@ -0,0 +1,39 @@
import json
from django.core.urlresolvers import reverse
from seahub.test_utils import BaseTestCase
from seahub.base.templatetags.seahub_tags import email2nickname, \
email2contact_email
class AccountTest(BaseTestCase):
def setUp(self):
self.user_name = self.user.username
self.url = reverse('api-v2.1-user')
def tearDown(self):
pass
def test_get_info(self):
self.login_as(self.user)
resp = self.client.get(self.url)
json_resp = json.loads(resp.content)
assert json_resp['email'] == self.user_name
assert json_resp['name'] == email2nickname(self.user_name)
assert json_resp['contact_email'] == email2contact_email(self.user_name)
assert json_resp.has_key('list_in_address_book')
def test_update_list_in_address_book(self):
self.login_as(self.user)
data = {"list_in_address_book": "true"}
resp = self.client.put(self.url, json.dumps(data), 'application/json')
json_resp = json.loads(resp.content)
assert json_resp['list_in_address_book'] is True
data = {"list_in_address_book": "false"}
resp = self.client.put(self.url, json.dumps(data), 'application/json')
json_resp = json.loads(resp.content)
assert json_resp['list_in_address_book'] is False