diff --git a/handlers.py b/handlers.py index 1dc1da59f8..0b46275830 100644 --- a/handlers.py +++ b/handlers.py @@ -9,13 +9,15 @@ if not hasattr(settings, 'EVENTS_CONFIG_FILE'): else: import seafevents - from utils import get_seafevents_session + from utils import SeafEventsSession def repo_created_cb(sender, **kwargs): + org_id = kwargs['org_id'] creator = kwargs['creator'] repo_id = kwargs['repo_id'] repo_name = kwargs['repo_name'] + etype = 'repo-create' detail = { 'creator': creator, 'repo_id': repo_id, @@ -24,8 +26,11 @@ else: users = [creator] - session = get_seafevents_session() - seafevents.save_user_events (session, 'repo-create', detail, users, None) + session = SeafEventsSession() + if org_id > 0: + seafevents.save_org_user_events (session, org_id, etype, detail, users, None) + else: + seafevents.save_user_events (session, etype, detail, users, None) session.close() def repo_deleted_cb(sender, **kwargs): @@ -33,12 +38,14 @@ else: groups to which this repo is shared. """ + org_id = kwargs['org_id'] usernames = kwargs['usernames'] repo_owner = kwargs['repo_owner'] repo_id = kwargs['repo_id'] repo_name = kwargs['repo_name'] + etype = 'repo-delete' detail = { 'repo_owner': repo_owner, 'repo_id': repo_id, @@ -47,7 +54,9 @@ else: users = usernames - session = get_seafevents_session() - seafevents.save_user_events (session, 'repo-delete', detail, users, None) + session = SeafEventsSession() + if org_id > 0: + seafevents.save_org_user_events (session, org_id, etype, detail, users, None) + else: + seafevents.save_user_events (session, etype, detail, users, None) session.close() - diff --git a/media/css/seahub.css b/media/css/seahub.css index a4b024261b..c718b02794 100644 --- a/media/css/seahub.css +++ b/media/css/seahub.css @@ -922,7 +922,7 @@ ul.with-bg li { color:#666; margin-left:5px; } -.lsch { +.lsch, .lsch-encrypted { font-size:12px; font-weight:normal; color:#666; diff --git a/organizations/templates/organizations/personal.html b/organizations/templates/organizations/personal.html index 35ea15fb84..46c8eafc6d 100644 --- a/organizations/templates/organizations/personal.html +++ b/organizations/templates/organizations/personal.html @@ -29,6 +29,10 @@ {% include "snippets/my_owned_repos.html" %} +{% if events %} +{% include "snippets/events.html" %} +{% endif %} + {% url 'org_repo_share' org.url_prefix as repo_share_url %} {% with post_url=repo_share_url tips='必须是团体内部成员或群组。' %} {% include "snippets/repo_share_form.html" %} @@ -48,5 +52,10 @@ {% with post_url=repo_create_url %} {% include "snippets/repo_create_js.html" %} {% endwith %} + + +{% if events %} +{% include "snippets/events_js.html" %} +{% endif %} {% endblock %} diff --git a/organizations/views.py b/organizations/views.py index 1c165196ad..9cc5fe72fd 100644 --- a/organizations/views.py +++ b/organizations/views.py @@ -14,7 +14,7 @@ from django.utils.translation import ugettext as _ from auth.decorators import login_required from pysearpc import SearpcError -from seaserv import ccnet_threaded_rpc, seafserv_threaded_rpc, get_repo, \ +from seaserv import ccnet_threaded_rpc, seafserv_rpc, seafserv_threaded_rpc, get_repo, \ get_orgs_by_user, get_org_repos, list_org_inner_pub_repos, \ get_org_by_url_prefix, create_org, get_user_current_org, add_org_user, \ remove_org_user, get_org_groups, is_valid_filename, org_user_exists, \ @@ -36,8 +36,11 @@ from contacts import Contact from seahub.forms import RepoCreateForm, SharedRepoCreateForm import seahub.settings as seahub_settings from seahub.utils import render_error, render_permission_error, gen_token, \ - validate_group_name, string2list, calculate_repo_last_modify, MAX_INT + validate_group_name, string2list, calculate_repo_last_modify, MAX_INT, \ + EVENTS_ENABLED, get_org_user_events from seahub.views import myhome +from seahub.signals import repo_created + @login_required def create_org(request): @@ -131,6 +134,12 @@ def org_personal(request, url_prefix): profile = Profile.objects.filter(user=request.user.username)[0] nickname = profile.nickname + # events + if EVENTS_ENABLED: + events = get_org_user_events(org.org_id, user) + else: + events = None + return render_to_response('organizations/personal.html', { 'owned_repos': owned_repos, "in_repos": in_repos, @@ -141,6 +150,7 @@ def org_personal(request, url_prefix): 'create_shared_repo': False, 'allow_public_share': True, 'nickname': nickname, + 'events': events, }, context_instance=RequestContext(request)) @login_required @@ -179,6 +189,11 @@ def org_inner_pub_repo_create(request, url_prefix): result['error'] = u"创建失败" else: result['success'] = True + repo_created.send(sender=None, + org_id=org.org_id, + creator=user, + repo_id=repo_id, + repo_name=repo_name) return HttpResponse(json.dumps(result), content_type=content_type) else: return HttpResponseBadRequest(json.dumps(form.errors), @@ -414,6 +429,11 @@ def org_repo_create(request, url_prefix): result['error'] = u"创建失败" else: result['success'] = True + repo_created.send(sender=None, + org_id=org.org_id, + creator=user, + repo_id=repo_id, + repo_name=repo_name) return HttpResponse(json.dumps(result), content_type=content_type) else: return HttpResponseBadRequest(json.dumps(form.errors), diff --git a/signals.py b/signals.py index 46c5ae409a..931abc4cf0 100644 --- a/signals.py +++ b/signals.py @@ -1,4 +1,5 @@ import django.dispatch -repo_created = django.dispatch.Signal(providing_args=["creator", "repo_id", "repo_name"]) -repo_deleted = django.dispatch.Signal(providing_args=["usernames", "repo_owner", "repo_id", "repo_name"]) +# Use org_id = -1 if it's not an org repo +repo_created = django.dispatch.Signal(providing_args=["org_id", "creator", "repo_id", "repo_name"]) +repo_deleted = django.dispatch.Signal(providing_args=["org_id", "usernames", "repo_owner", "repo_id", "repo_name"]) diff --git a/templates/myhome.html b/templates/myhome.html index 805813bbd9..76d66bd802 100644 --- a/templates/myhome.html +++ b/templates/myhome.html @@ -25,7 +25,7 @@
  • 群组 {% for grp in grpmsg_list %} - {{ grp.group_name }} + {{ grp.group_name }} {% endfor %} 有新留言
  • @@ -56,58 +56,7 @@ {% include "snippets/my_owned_repos.html" %} {% if events %} -

    最近事件

    - -
    +{% include "snippets/events.html" %} {% endif %} {% url 'share_repo' as repo_share_url %} @@ -123,20 +72,15 @@ {% with groups=autocomp_groups %} {% include "snippets/myhome_extra_script.html" %} {% endwith %} - + {% url 'seahub.views.repo_create' as repo_create_url %} {% with post_url=repo_create_url %} {% include "snippets/repo_create_js.html" %} {% endwith %} {% if events %} -{% include 'snippets/list_commit_detail.html' %} -$('.event-item').each(function(index) { - if (index > 0 && $(this).children('.pic').attr('data') == $(this).prev().children('.pic').attr('data')) { - $(this).children('.pic').addClass('hide'); - } -}); -$('#events').removeClass('hide'); +{% include "snippets/events_js.html" %} {% endif %} + {% endblock %} diff --git a/templates/snippets/events.html b/templates/snippets/events.html new file mode 100644 index 0000000000..e8d34d4639 --- /dev/null +++ b/templates/snippets/events.html @@ -0,0 +1,75 @@ +{% load seahub_tags avatar_tags group_avatar_tags %} +{% load url from future %} +

    最近事件

    + +
    +

    资料库 已加密

    + + + +

    密码只会在服务器上暂存1小时

    +

    + + +
    +
    diff --git a/templates/snippets/events_js.html b/templates/snippets/events_js.html new file mode 100644 index 0000000000..ce0c7689f0 --- /dev/null +++ b/templates/snippets/events_js.html @@ -0,0 +1,57 @@ +{% include 'snippets/list_commit_detail.html' %} +$('.event-item').each(function(index) { + if (index > 0 && $(this).children('.pic').attr('data') == $(this).prev().children('.pic').attr('data')) { + $(this).children('.pic').addClass('hide'); + } +}); +$('#events').removeClass('hide'); + +// 查看加密 repo 的详情时, 先为其设置密码 +var cur_event; +$('a.lsch-encrypted').click(function() { + if ($(this).attr('password_set') == 'true') { + list_commit_change($(this)); + } else { + cur_event = $(this); + $('#repo-set-password-form input[name="repo_id"]').val($(this).attr('repo_id')); + $('#repo-set-password-form .repo-name').html($(this).attr('repo_name')); + $('#repo-set-password-form').modal({appendTo:'#main'}); + } + return false; +}); +$('#repo-set-password-form .submit').click(function() { + var input_password = $('#repo-set-password-form input[name="password"]'); + var repo_id = $('#repo-set-password-form input[name="repo_id"]').val(); + var password = input_password.val(); + if (!password) { + apply_form_error('repo-set-password-form', "密码不能为空"); + } else { + apply_form_error('repo-set-password-form', ''); + $.ajax({ + url: '{% url repo_set_password %}', + type: 'POST', + dataType: 'json', + cache: 'false', + beforeSend: prepareCSRFToken, + data: { + repo_id: repo_id, + password: password, + username: '{{request.user.username}}' + }, + success: function(data) { + if (data['success']) { + $.modal.close(); + $('a.lsch-encrypted[repo_id="' + repo_id + '"]').attr('password_set', 'true'); + list_commit_change(cur_event); + } else { + input_password.val(''); + apply_form_error('repo-set-password-form', data['error']); + } + }, + error: function(data, textStatus, jqXHR) { + apply_form_error('repo-set-password-form', '访问网站出错'); + } + }); + } + return false; +}); diff --git a/templates/snippets/list_commit_detail.html b/templates/snippets/list_commit_detail.html index d79522dc97..a84d4e4023 100644 --- a/templates/snippets/list_commit_detail.html +++ b/templates/snippets/list_commit_detail.html @@ -1,49 +1,66 @@ - $('.lsch').click(function() { - var time = '(' + $(this).attr('data') + ')'; - $.ajax({ - url: $(this).attr('href'), - dataType: 'json', - cache: false, - contentType: 'application/json; charset=utf-8', - success: function(data) { - var title = '

    修改详情' + time + '

    ', - con = ''; - var show = function(data_) { - con += ''; - }; - if (data['new'].length > 0) { - con += '

    新文件

    '; - show(data['new']); - } - if (data['removed'].length > 0) { - con += '

    删除的文件

    '; - show(data['removed']); - } - if (data['renamed'].length > 0) { - con += '

    重命名或移动的文件

    '; - show(data['renamed']); - } - if (data['modified'].length > 0) { - con += '

    修改的文件

    '; - show(data['modified']); - } - if (data['newdir'].length > 0) { - con += '

    新目录

    '; - show(data['newdir']); - } - if (data['deldir'].length > 0) { - con += '

    删除的目录

    '; - show(data['deldir']); - } - if (!con) { - con = '

    没有文件被改动

    '; - } - $('#ls-ch').html(title + con).modal({appendTo:'#main', maxHeight: window.innerHeight - 57, autoResize:true}); + + +function get_commit_diff(url, callback) { + $.ajax({ + url: url, + dataType: 'json', + cache: false, + contentType: 'application/json; charset=utf-8', + success: function(data) { + var con = ''; + var show = function(data_) { + con += ''; + }; + if (data['new'].length > 0) { + con += '

    新文件

    '; + show(data['new']); + } + if (data['removed'].length > 0) { + con += '

    删除的文件

    '; + show(data['removed']); + } + if (data['renamed'].length > 0) { + con += '

    重命名或移动的文件

    '; + show(data['renamed']); + } + if (data['modified'].length > 0) { + con += '

    修改的文件

    '; + show(data['modified']); + } + if (data['newdir'].length > 0) { + con += '

    新目录

    '; + show(data['newdir']); + } + if (data['deldir'].length > 0) { + con += '

    删除的目录

    '; + show(data['deldir']); + } + if (!con) { + con = '

    没有文件被改动

    '; + } + callback(con); + } + }); +} + +function list_commit_change(obj) { + var url = obj.attr('href'); + get_commit_diff(url, function(content) { + var time = '(' + obj.attr('data') + ')'; + var title = '

    修改详情' + time + '

    '; + $('#ls-ch').html(title + content).modal({ + appendTo:'#main', + maxHeight: window.innerHeight - 57, + autoResize:true, }); + }); +} + +$('.lsch').click(function() { + list_commit_change($(this)); + return false; +}); diff --git a/thirdpart/seaserv/__init__.py b/thirdpart/seaserv/__init__.py index 08fb4f8870..4b36dd0249 100644 --- a/thirdpart/seaserv/__init__.py +++ b/thirdpart/seaserv/__init__.py @@ -24,7 +24,7 @@ from service import create_org, get_orgs_by_user, get_org_by_url_prefix, \ get_org_id_by_repo_id, is_org_staff, get_org_users_by_url_prefix, \ org_user_exists, list_org_repos_by_owner -from service import get_related_users_by_repo +from service import get_related_users_by_repo, get_related_users_by_org_repo from service import CCNET_CONF_PATH, CCNET_SERVER_ADDR, CCNET_SERVER_PORT diff --git a/thirdpart/seaserv/service.py b/thirdpart/seaserv/service.py index 47ed837224..cfba9c14f6 100644 --- a/thirdpart/seaserv/service.py +++ b/thirdpart/seaserv/service.py @@ -669,19 +669,55 @@ def get_related_users_by_repo(repo_id): - users to which the repo is shared """ owner = seafserv_threaded_rpc.get_repo_owner(repo_id) + if not owner: + # Can't happen + return [] + users = [owner] groups = get_shared_groups_by_repo(repo_id) + for group in groups: members = get_group_members(group.id) for member in members: if member.user_name not in users: users.append(member.user_name) - share_repos = seafserv_threaded_rpc.list_share_repos(owner, 'from_email', -1, -1) + share_repos = seafserv_threaded_rpc.list_share_repos(owner, \ + 'from_email', -1, -1) + for repo in share_repos: - if repo.id == repo_id: - if repo.shared_email not in users: - users.append(repo.shared_email) + if repo.repo_id == repo_id: + if repo.user not in users: + users.append(repo.user) + + return users + +def get_related_users_by_org_repo(org_id, repo_id): + """Org version of get_related_users_by_repo + """ + owner = get_org_repo_owner(repo_id) + + if not owner: + # Can't happen + return [] + + users = [owner] + + groups = get_org_groups_by_repo(org_id, repo_id) + + for group in groups: + members = get_group_members(group.id) + for member in members: + if member.user_name not in users: + users.append(member.user_name) + + share_repos = seafserv_threaded_rpc.list_org_share_repos(org_id, \ + owner, 'from_email', -1, -1) + + for repo in share_repos: + if repo.repo_id == repo_id: + if repo.user not in users: + users.append(repo.user) return users diff --git a/urls.py b/urls.py index 679891cbfd..bc887823dc 100644 --- a/urls.py +++ b/urls.py @@ -48,6 +48,7 @@ urlpatterns = patterns('', (r'^repo/upload_check/$', validate_filename), (r'^repo/file_rename/$', repo_rename_file), (r'^repo/unsetinnerpub/(?P[^/]+)/$', unset_inner_pub_repo), + url(r'^repo/set_password/$', repo_set_password, name="repo_set_password"), url(r'^repo/revert_file/(?P[^/]+)/$', repo_revert_file, name='repo_revert_file'), url(r'^repo/revert_dir/(?P[^/]+)/$', repo_revert_dir, name='repo_revert_dir'), url(r'^repo/upload_file/(?P[^/]+)/$', repo_upload_file, name='repo_upload_file'), diff --git a/utils.py b/utils.py index b77170b4d2..feba51308f 100644 --- a/utils.py +++ b/utils.py @@ -421,11 +421,46 @@ def get_file_contributors(repo_id, file_path, file_path_hash, file_id): if hasattr(settings, 'EVENTS_CONFIG_FILE'): import seafevents - seafevents_session = None - def get_seafevents_session(): - global seafevents_session - if not seafevents_session: - seafevents_session = seafevents.init_db_session(settings.EVENTS_CONFIG_FILE) + EVENTS_ENABLED = True + SeafEventsSession = seafevents.init_db_session_class(settings.EVENTS_CONFIG_FILE) - return seafevents_session() + def get_user_events(username): + ev_session = SeafEventsSession() + events = seafevents.get_user_events(ev_session, username, 0, 10) + ev_session.close() + for ev in events: + if ev.etype == 'repo-update': + repo = get_repo(ev.repo_id) + if not repo: + ev.etype = 'dummy' + continue + if repo.encrypted: + repo.password_set = seafserv_rpc.is_passwd_set(repo.id, username) + ev.repo = repo + ev.commit = seafserv_threaded_rpc.get_commit(ev.commit_id) + + return events + + def get_org_user_events(org_id, username): + ev_session = SeafEventsSession() + events = seafevents.get_org_user_events(ev_session, \ + org_id, username, 0, 10) + ev_session.close() + for ev in events: + if ev.etype == 'repo-update': + repo = get_repo(ev.repo_id) + if not repo: + ev.etype = 'dummy' + continue + if repo.encrypted: + repo.password_set = seafserv_rpc.is_passwd_set(repo.id, username) + ev.repo = repo + ev.commit = seafserv_threaded_rpc.get_commit(ev.commit_id) + return events +else: + EVENTS_ENABLED = False + def get_user_events(): + pass + def get_org_user_events(): + pass diff --git a/views.py b/views.py index a25d01da96..5d17ca3257 100644 --- a/views.py +++ b/views.py @@ -41,7 +41,8 @@ from seaserv import ccnet_rpc, ccnet_threaded_rpc, get_repos, get_emailusers, \ get_group, get_shared_groups_by_repo, is_group_user, check_permission, \ list_personal_shared_repos, is_org_group, get_org_id_by_group, is_org_repo,\ list_inner_pub_repos, get_org_groups_by_repo, is_org_repo_owner, \ - get_org_repo_owner, is_passwd_set, get_file_size, get_related_users_by_repo + get_org_repo_owner, is_passwd_set, get_file_size, \ + get_related_users_by_repo, get_related_users_by_org_repo from pysearpc import SearpcError from signals import repo_created, repo_deleted @@ -67,7 +68,7 @@ from utils import render_permission_error, render_error, list_to_string, \ get_file_revision_id_size, get_ccnet_server_addr_port, \ gen_file_get_url, string2list, MAX_INT, \ gen_file_upload_url, check_and_get_org_by_repo, \ - get_file_contributors + get_file_contributors, EVENTS_ENABLED, get_user_events try: from settings import DOCUMENT_CONVERTOR_ROOT if DOCUMENT_CONVERTOR_ROOT[-1:] != '/': @@ -76,12 +77,6 @@ except ImportError: DOCUMENT_CONVERTOR_ROOT = None from settings import FILE_PREVIEW_MAX_SIZE, INIT_PASSWD -try: - from settings import EVENTS_CONFIG_FILE - from utils import get_seafevents_session - import seafevents -except ImportError: - EVENTS_CONFIG_FILE = None @login_required def root(request): @@ -816,7 +811,16 @@ def remove_repo(request, repo_id): # perform this operation. if request.user.is_staff or org.is_staff or \ is_org_repo_owner(org.org_id, repo_id, user): + # Must get related useres before remove the repo + usernames = get_related_users_by_org_repo(org.org_id, repo_id) seafserv_threaded_rpc.remove_repo(repo_id) + repo_deleted.send(sender=None, + org_id=org.org_id, + usernames=usernames, + repo_owner=user, + repo_id=repo_id, + repo_name=repo.name, + ) else: err_msg = u'删除资料库失败, 只有团体管理员或资料库创建者有权删除资料库。' return render_permission_error(request, err_msg) @@ -827,6 +831,7 @@ def remove_repo(request, repo_id): usernames = get_related_users_by_repo(repo_id) seafserv_threaded_rpc.remove_repo(repo_id) repo_deleted.send(sender=None, + org_id=-1, usernames=usernames, repo_owner=user, repo_id=repo_id, @@ -902,18 +907,11 @@ def myhome(request): contacts.append(u) # events - if EVENTS_CONFIG_FILE: - ev_session = get_seafevents_session() - events = seafevents.get_user_events(ev_session, request.user.username, 0, 10) - ev_session.close() - for ev in events: - if ev.etype == 'repo-update': - ev.repo = get_repo(ev.repo_id) - ev.commit = seafserv_threaded_rpc.get_commit(ev.commit_id) + if EVENTS_ENABLED: + events = get_user_events(request.user.username) else: events = None - return render_to_response('myhome.html', { "nickname": nickname, "owned_repos": owned_repos, @@ -1076,8 +1074,6 @@ def public_repo_create(request): passwd = form.cleaned_data['passwd'] user = request.user.username - print permission - try: # create a repo repo_id = seafserv_threaded_rpc.create_repo(repo_name, repo_desc, @@ -1091,6 +1087,7 @@ def public_repo_create(request): else: result['success'] = True repo_created.send(sender=None, + org_id=-1, creator=user, repo_id=repo_id, repo_name=repo_name) @@ -2185,6 +2182,7 @@ def repo_create(request): else: result['success'] = True repo_created.send(sender=None, + org_id=-1, creator=user, repo_id=repo_id, repo_name=repo_name) @@ -2570,21 +2568,6 @@ def use_flash_for_pdf(request): return True else: return False -''' -@login_required -def show_events(request): - ev_session = get_seafevents_session() - events = seafevents.get_user_events(ev_session, request.user.username, 0, 10) - ev_session.close() - for ev in events: - if ev.etype == 'repo-update': - ev.repo = get_repo(ev.repo_id) - ev.commit = seafserv_threaded_rpc.get_commit(ev.commit_id) - - return render_to_response ('events.html', { - 'events': events, - }, context_instance=RequestContext(request)) -''' def demo(request): """ @@ -2614,3 +2597,16 @@ def pubinfo(request): 'users': users, }, context_instance=RequestContext(request)) +def repo_set_password(request): + ret = {} + content_type = 'application/json; charset=utf-8' + + form = RepoPassowrdForm(request.POST) + if form.is_valid(): + ret['success'] = True + else: + ret['success'] = False + ret['error'] = str(form.errors.values()[0]) + + return HttpResponse(json.dumps(ret), + content_type=content_type)