1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-02 15:38:15 +00:00

Merge branch 'events'

This commit is contained in:
llj
2012-09-29 17:18:21 +08:00
10 changed files with 231 additions and 5 deletions

View File

@@ -0,0 +1,5 @@
from signals import repo_created, repo_deleted
from handlers import repo_created_cb, repo_deleted_cb
repo_created.connect(repo_created_cb)
repo_deleted.connect(repo_deleted_cb)

42
handlers.py Normal file
View File

@@ -0,0 +1,42 @@
import seafevents
from utils import get_seafevents_session
def repo_created_cb(sender, **kwargs):
creator = kwargs['creator']
repo_id = kwargs['repo_id']
repo_name = kwargs['repo_name']
detail = {
'creator': creator,
'repo_id': repo_id,
'repo_name': repo_name,
}
users = [creator]
session = get_seafevents_session()
seafevents.save_user_events (session, 'repo-create', detail, users, None)
session.close()
def repo_deleted_cb(sender, **kwargs):
"""When a repo is deleted, an event would be added to every user in all
groups to which this repo is shared.
"""
usernames = kwargs['usernames']
repo_owner = kwargs['repo_owner']
repo_id = kwargs['repo_id']
repo_name = kwargs['repo_name']
detail = {
'repo_owner': repo_owner,
'repo_id': repo_id,
'repo_name': repo_name,
}
users = usernames
session = get_seafevents_session()
seafevents.save_user_events (session, 'repo-delete', detail, users, None)
session.close()

View File

@@ -610,6 +610,20 @@ ul.with-bg li {
width:262px; width:262px;
margin-bottom:10px; margin-bottom:10px;
} }
.event-item {
margin:10px 0 15px;
}
.event-item .txt {
width:610px;
padding-bottom:8px;
border-bottom:1px solid #eee;
}
.event-hd .time {
color:#888;
}
.event-item .avatar {
border-radius:3px;
}
/* avatar */ /* avatar */
.avatar-op .avatar, .avatar-op .avatar,
.home-profile .avatar, .home-profile .avatar,

4
signals.py Normal file
View File

@@ -0,0 +1,4 @@
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"])

View File

@@ -3,8 +3,8 @@
{% load url from future %} {% load url from future %}
{% block nav_myhome_class %}class="cur"{% endblock %} {% block nav_myhome_class %}class="cur"{% endblock %}
{% block left_panel %}
{% block left_panel %}
<h3>我的基本信息</h3> <h3>我的基本信息</h3>
<div class="home-profile w100 ovhd"> <div class="home-profile w100 ovhd">
<a href="{{ SITE_ROOT }}profile/" class="no-deco">{% avatar myname 48 %}</a> <a href="{{ SITE_ROOT }}profile/" class="no-deco">{% avatar myname 48 %}</a>
@@ -52,6 +52,61 @@
<!-- 共享给我的同步目录 --> <!-- 共享给我的同步目录 -->
{% include "snippets/shared_in_repos.html" %} {% include "snippets/shared_in_repos.html" %}
{% if events %}
<h3>最近事件</h3>
<ul id="events" class="hide">
{% for ev in events %}
<li class="event-item w100 ovhd">
{% if ev.etype == 'repo-update' %}
{% with author=ev.commit.creator_name commit=ev.commit repo=ev.repo %}
<div class="pic fleft" data="{{ author }}">
<a href="{% url 'user_profile' author %}" title="{{ author|email2nickname}}">{% avatar author 40 %}</a>
</div>
<div class="txt fright">
<div class="event-hd">
<span class="time">{{ commit.ctime|translate_commit_time }}</span>
<a href="{% url 'user_profile' author %}" title="{{ author|email2nickname}}">{{ author|email2nickname }}</a>
</div>
<p>更新了目录 <a href="{{SITE_ROOT}}repo/{{repo.id}}">{{ repo.name }}</a> <a class="lsch" href="{{ SITE_ROOT }}repo/history/changes/{{ repo.id }}/?commit_id={{ commit.id }}" data="{{ commit.props.ctime|tsstr_sec }}">详情</a></P>
</div>
{% endwith %}
{% endif %}
{% if ev.etype == 'repo-create' %}
{% with author=ev.creator repo_id=ev.repo_id repo_name=ev.repo_name %}
<div class="pic fleft" data="{{ author }}">
<a href="{% url 'user_profile' author %}" title="{{ author|email2nickname}}">{% avatar author 40 %}</a>
</div>
<div class="txt fright">
<div class="event-hd">
<span class="time">{{ ev.timestamp|translate_commit_time }}</span>
<a href="{% url 'user_profile' author %}" title="{{ author|email2nickname}}">{{ author|email2nickname }}</a>
</div>
<p>创建了目录 <a href="{{SITE_ROOT}}repo/{{repo_id}}">{{ repo_name }}</a></p>
</div>
{% endwith %}
{% endif %}
{% if ev.etype == 'repo-delete' %}
{% with author=ev.repo_owner repo_name=ev.repo_name %}
<div class="pic fleft" data="{{ author }}">
<a href="{% url 'user_profile' author %}" title="{{ author|email2nickname}}">{% avatar author 40 %}</a>
</div>
<div class="txt fright">
<div class="event-hd">
<span class="time">{{ ev.timestamp|translate_commit_time }}</span>
<a href="{% url 'user_profile' author %}" title="{{ author|email2nickname}}">{{ author|email2nickname }}</a>
</div>
<p>删除了目录 {{ repo_name }}</p>
</div>
{% endwith %}
{% endif %}
</li>
{% endfor %}
</ul>
<div id="ls-ch" class="hide"></div><!--list modification details of a commit-->
{% endif %}
{% url 'share_repo' as repo_share_url %} {% url 'share_repo' as repo_share_url %}
{% with post_url=repo_share_url tips='' %} {% with post_url=repo_share_url tips='' %}
{% include "snippets/repo_share_form.html" %} {% include "snippets/repo_share_form.html" %}
@@ -68,5 +123,15 @@
{% with post_url=repo_create_url %} {% with post_url=repo_create_url %}
{% include "snippets/repo_create_js.html" %} {% include "snippets/repo_create_js.html" %}
{% endwith %} {% 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');
{% endif %}
</script> </script>
{% endblock %} {% endblock %}

View File

@@ -24,5 +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, \ get_org_id_by_repo_id, is_org_staff, get_org_users_by_url_prefix, \
org_user_exists, list_org_repos_by_owner org_user_exists, list_org_repos_by_owner
from service import get_related_users_by_repo
from service import CCNET_CONF_PATH, CCNET_SERVER_ADDR, CCNET_SERVER_PORT from service import CCNET_CONF_PATH, CCNET_SERVER_ADDR, CCNET_SERVER_PORT

View File

@@ -662,3 +662,27 @@ def get_file_size(file_id):
except SearpcError, e: except SearpcError, e:
fs = 0 fs = 0
return fs return fs
def get_related_users_by_repo(repo_id):
"""Give a repo id, returns a list of users of:
- the repo owner
- members of groups to which the repo is shared
- users to which the repo is shared
"""
owner = seafserv_threaded_rpc.get_repo_owner(repo_id)
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)
for repo in share_repos:
if repo.id == repo_id:
if repo.shared_email not in users:
users.append(repo.shared_email)
return users

View File

@@ -99,7 +99,6 @@ urlpatterns = patterns('',
url(r'^sys/useradmin/$', sys_useradmin, name='sys_useradmin'), url(r'^sys/useradmin/$', sys_useradmin, name='sys_useradmin'),
url(r'^sys/orgadmin/$', sys_org_admin, name='sys_org_admin'), url(r'^sys/orgadmin/$', sys_org_admin, name='sys_org_admin'),
url(r'^sys/groupadmin/$', sys_group_admin, name='sys_group_admin'), url(r'^sys/groupadmin/$', sys_group_admin, name='sys_group_admin'),
) )
if settings.DEBUG: if settings.DEBUG:

View File

@@ -13,6 +13,8 @@ from base.models import FileContributors
from pysearpc import SearpcError from pysearpc import SearpcError
import seafevents
from seaserv import seafserv_rpc, ccnet_threaded_rpc, seafserv_threaded_rpc, \ from seaserv import seafserv_rpc, ccnet_threaded_rpc, seafserv_threaded_rpc, \
get_repo, get_commits, get_group_repoids, CCNET_SERVER_ADDR, \ get_repo, get_commits, get_group_repoids, CCNET_SERVER_ADDR, \
CCNET_SERVER_PORT, get_org_id_by_repo_id, get_org_by_id, is_org_staff, \ CCNET_SERVER_PORT, get_org_id_by_repo_id, get_org_by_id, is_org_staff, \
@@ -192,7 +194,7 @@ def get_accessible_repos(request, repo):
return True return True
return False return False
if repo.encrypted: if repo and repo.encrypted:
repo.has_subdir = check_has_subdir(repo) repo.has_subdir = check_has_subdir(repo)
accessible_repos = [repo] accessible_repos = [repo]
return accessible_repos return accessible_repos
@@ -406,3 +408,15 @@ def get_file_contributors(repo_id, file_path, file_path_hash, file_id):
last_modified = fc.last_modified last_modified = fc.last_modified
return contributors, last_modified return contributors, last_modified
seafevents_session = None
def get_seafevents_session():
if not hasattr(settings, 'EVENTS_CONFIG_FILE'):
return None
else:
global seafevents_session
if not seafevents_session:
seafevents_session = seafevents.init_db_session(settings.EVENTS_CONFIG_FILE)
return seafevents_session()

View File

@@ -39,9 +39,11 @@ from seaserv import ccnet_rpc, ccnet_threaded_rpc, get_repos, get_emailusers, \
get_group, get_shared_groups_by_repo, is_group_user, check_permission, \ 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_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, \ list_inner_pub_repos, get_org_groups_by_repo, is_org_repo_owner, \
get_org_repo_owner, is_passwd_set, get_file_size get_org_repo_owner, is_passwd_set, get_file_size, get_related_users_by_repo
from pysearpc import SearpcError from pysearpc import SearpcError
from signals import repo_created, repo_deleted
from base.accounts import User from base.accounts import User
from base.decorators import sys_staff_required, ctx_switch_required from base.decorators import sys_staff_required, ctx_switch_required
from base.mixins import LoginRequiredMixin, CtxSwitchRequiredMixin from base.mixins import LoginRequiredMixin, CtxSwitchRequiredMixin
@@ -72,6 +74,14 @@ except ImportError:
DOCUMENT_CONVERTOR_ROOT = None DOCUMENT_CONVERTOR_ROOT = None
from settings import FILE_PREVIEW_MAX_SIZE, INIT_PASSWD from settings import FILE_PREVIEW_MAX_SIZE, INIT_PASSWD
try:
from settings import EVENTS_CONFIG_FILE
import seafevents
except ImportError:
EVENTS_CONFIG_FILE = None
else:
from utils import get_seafevents_session
@login_required @login_required
def root(request): def root(request):
return HttpResponseRedirect(reverse(myhome)) return HttpResponseRedirect(reverse(myhome))
@@ -716,6 +726,10 @@ def modify_token(request, repo_id):
@login_required @login_required
def remove_repo(request, repo_id): def remove_repo(request, repo_id):
repo = get_repo(repo_id)
if not repo:
return render_error(request, u"该同步目录不存在")
user = request.user.username user = request.user.username
org, base_template = check_and_get_org_by_repo(repo_id, user) org, base_template = check_and_get_org_by_repo(repo_id, user)
if org: if org:
@@ -731,7 +745,14 @@ def remove_repo(request, repo_id):
# Remove repo in personal context, only repo owner or site staff can # Remove repo in personal context, only repo owner or site staff can
# perform this operation. # perform this operation.
if validate_owner(request, repo_id) or request.user.is_staff: if validate_owner(request, repo_id) or request.user.is_staff:
usernames = get_related_users_by_repo(repo_id)
seafserv_threaded_rpc.remove_repo(repo_id) seafserv_threaded_rpc.remove_repo(repo_id)
repo_deleted.send(sender=None,
usernames=usernames,
repo_owner=user,
repo_id=repo_id,
repo_name=repo.name,
)
else: else:
err_msg = u'删除同步目录失败, 只有管理员或目录创建者有权删除目录。' err_msg = u'删除同步目录失败, 只有管理员或目录创建者有权删除目录。'
return render_permission_error(request, err_msg) return render_permission_error(request, err_msg)
@@ -794,6 +815,19 @@ def myhome(request):
allow_public_share = True if not CLOUD_MODE else False allow_public_share = True if not CLOUD_MODE else False
# 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)
else:
events = None
return render_to_response('myhome.html', { return render_to_response('myhome.html', {
"myname": email, "myname": email,
"nickname": nickname, "nickname": nickname,
@@ -809,6 +843,7 @@ def myhome(request):
"orgmsg_list": orgmsg_list, "orgmsg_list": orgmsg_list,
"create_shared_repo": False, "create_shared_repo": False,
"allow_public_share": allow_public_share, "allow_public_share": allow_public_share,
"events": events,
}, context_instance=RequestContext(request)) }, context_instance=RequestContext(request))
@login_required @login_required
@@ -972,6 +1007,11 @@ def public_repo_create(request):
result['error'] = u"创建目录失败" result['error'] = u"创建目录失败"
else: else:
result['success'] = True result['success'] = True
repo_created.send(sender=None,
creator=user,
repo_id=repo_id,
repo_name=repo_name)
return HttpResponse(json.dumps(result), content_type=content_type) return HttpResponse(json.dumps(result), content_type=content_type)
else: else:
return HttpResponseBadRequest(json.dumps(form.errors), return HttpResponseBadRequest(json.dumps(form.errors),
@@ -2038,6 +2078,10 @@ def repo_create(request):
result['error'] = u"创建目录失败" result['error'] = u"创建目录失败"
else: else:
result['success'] = True result['success'] = True
repo_created.send(sender=None,
creator=user,
repo_id=repo_id,
repo_name=repo_name)
return HttpResponse(json.dumps(result), content_type=content_type) return HttpResponse(json.dumps(result), content_type=content_type)
else: else:
return HttpResponseBadRequest(json.dumps(form.errors), return HttpResponseBadRequest(json.dumps(form.errors),
@@ -2390,5 +2434,18 @@ def use_flash_for_pdf(request):
return True return True
else: else:
return False 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))
'''