1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-08 18:30:53 +00:00

Add group message feature

This commit is contained in:
xiez
2012-06-25 14:57:14 +08:00
parent e03c3205f7
commit 83c0242d78
10 changed files with 383 additions and 20 deletions

8
group/forms.py Normal file
View File

@@ -0,0 +1,8 @@
from django import forms
class MessageForm(forms.Form):
message = forms.CharField(max_length=150)
#class MessageReplyForm(forms.Form):
# message = forms.CharField(max_length=150)

View File

@@ -1,3 +1,14 @@
import datetime
from django.db import models from django.db import models
# Create your models here. class GroupMessage(models.Model):
group_id = models.IntegerField()
from_email = models.EmailField()
message = models.CharField(max_length=150)
timestamp = models.DateTimeField(default=datetime.datetime.now)
class MessageReply(models.Model):
reply_to = models.ForeignKey(GroupMessage)
from_email = models.EmailField()
message = models.CharField(max_length=150)
timestamp = models.DateTimeField(default=datetime.datetime.now)

View File

@@ -65,6 +65,62 @@
{% else %} {% else %}
<p>暂无</p> <p>暂无</p>
{% endif %} {% endif %}
<div id="group-reply">
<h3>留言板 (全部{{ msg_cnt }}条)</h3>
<form action="" method="post">
<textarea name="message" id="message">{{ form.data.message }}</textarea><br />
<input type="submit" value="留言" class="submit" />
{% for error in form.message.errors %}
<span class="error">{{ error|escape }}</span>
{% endfor %}
</form>
{% if group_msgs %}
<ul class="replies">
{% for msg in group_msgs %}
{% avatar msg.from_email 48 %}
<li id="li{{ msg.id }}">
<span class="from">
{{ msg.from_email }}
</span>
<span class="ts">
{{ msg.timestamp|date:"Y-m-d H:i" }}
</span>
<div class="msg-op">
<span class="msg">{{ msg.message }}</span>
<span>
<a class="op reply" href="#" data="{{ msg.id }}" >回复({{ msg.reply_cnt }}</a>
<a class="op replyclose" href="#" data="{{ msg.id }}" style="display:none; " >收起回复</a>
</span>
</div>
<div class="reply-list"></div>
<form class="hide reply-form" method="post" action="">
<input type="hidden" name="msg_id" value="{{ msg.id }}"/>
<input type="text" name="message" />
<input type="submit" value="回复" />
</form>
</li>
{% endfor %}
</ul>
{% endif %}
</div>
<div id="paginator">
{% if current_page != 1 %}
<a href="{{ SITE_ROOT }}group/{{ group.id}}/?page={{ prev_page }}&per_page={{ per_page }}">上一页</a>
{% endif %}
{% if page_next %}
<a href="{{ SITE_ROOT }}group/{{ group.id }}/?page={{ next_page }}&per_page={{ per_page }}">下一页</a>
{% endif %}
</div>
</div> </div>
<div id="user-profile" class="user-profile ovhd hide"></div> <div id="user-profile" class="user-profile ovhd hide"></div>
@@ -178,5 +234,120 @@ $('#user-profile').hover(
} }
); );
$('.reply').each(function() {
$(this).click(function() {
var msg_id = $(this).attr('data');
$.ajax({
url: "{{ SITE_ROOT }}group/reply/"+msg_id+"/",
dataType: 'json',
cache: false,
contentType: 'application/json; charset=utf-8',
success: function(data) {
var str_con = '';
var show = function(data_) {
for (var i = 0, len = data_.length; i < len; i++) {
var msg = data_[i]['fields']['message'];
str_con += '<p>';
str_con += msg;
str_con += '</p>';
}
};
show(data);
var s = '#li' + msg_id + ' > .reply-list';
var s1 = '#li' + msg_id + ' > form';
$(s).html(str_con);
$(s).show();
$(s1).removeClass('hide');
}
});
$(this).hide();
var s3 = '#li' + msg_id + ' a~a';
$(s3).show();
return false;
});
});
$('.replyclose').each(function() {
$(this).click(function() {
var msg_id = $(this).attr('data');
var s1 = '#li' + msg_id + ' a';
var s2 = '#li' + msg_id + ' > .reply-list';
var s3 = '#li' + msg_id + ' > form';
var s4 = '#li' + msg_id + ' a~a';
$(s2).hide();
$(s3).addClass('hide');
$(s1).show();
$(s4).hide();
return false;
});
});
$('.reply-form').each(function(){
$(this).submit(function(event) {
// prepare django csrf token
$.ajaxSetup({
beforeSend: function(xhr, settings) {
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
// Only send the token to relative URLs i.e. locally.
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
}
});
var $form = $( this ),
m_id = $form.find( 'input[name="msg_id"]' ).val(),
m = $form.find( 'input[name="message"]' ).val();
$.ajax({
type: "POST",
url: "{{ SITE_ROOT }}group/reply/"+m_id+"/",
dataType: 'json',
cache: false,
contentType: 'application/json; charset=utf-8',
data: "message="+m,
success: function(data) {
var str_con = '';
var show = function(data_) {
for (var i = 0, len = data_.length; i < len; i++) {
var msg = data_[i]['fields']['message'];
str_con += '<p>';
str_con += msg;
str_con += '</p>';
}
};
show(data);
var s = '#li' + m_id + ' > .reply-list';
var s1 = '#li' + m_id + ' > form';
$(s1).removeClass('hide');
$(s).html(str_con);
var s2 = '#li' + m_id + ' .reply';
var t = '回复(' + data.length+ '';
$(s2).text(t);
$form.find('input[name="message"]').val("");
}
});
return false;
});
});
</script> </script>
{% endblock %} {% endblock %}

View File

@@ -32,7 +32,7 @@
<p>暂无</p> <p>暂无</p>
{% endif %} {% endif %}
<form id="group-add-form" action="{{ SITE_ROOT }}group/" method="post" name="group-add-form" class="hide"> <form id="group-add-form" action="{{ SITE_ROOT }}groups/" method="post" name="group-add-form" class="hide">
<label>小组名称:</label><br /> <label>小组名称:</label><br />
<input id="group_name" name="group_name" value="" /><br /> <input id="group_name" name="group_name" value="" /><br />
<input type="submit" value="提交" /> <input type="submit" value="提交" />

View File

@@ -0,0 +1,61 @@
{% extends "myhome_base.html" %}
{% load seahub_tags avatar_tags %}
{% block nav_group_class %}class="cur"{% endblock %}
{% block main_panel %}
<div class="main fleft">
<h2>留言</h2>
<div>
<span>{% avatar msg.from_email 48 %}</span>
<div class="info">
<span class="from">{{ msg.from_email }}</span>
<span class="ts">{{ msg.timestamp|date:"Y-m-d H:i" }}</span>
</div>
<div class="reply">
<span class="msg">{{ msg.message }}</span>
</div>
</div>
<div id="reply">
<form action="" method="post">
<textarea name="message" id="message">{{ form.data.message }}</textarea><br />
<input type="submit" value="回复" class="submit" />
{% for error in form.message.errors %}
<span class="error">{{ error|escape }}</span>
{% endfor %}
</form>
</div>
</div>
{% endblock %}
{% block extra_script %}
<script type="text/javascript">
addConfirmTo($('#quit-group'), '确定要退出?');
addConfirmTo($('.cancel-share'), '确定要取消共享该目录?');
$("table tr:gt(0)").hover(
function() {
$(this).find('img').css('cursor', 'pointer').removeClass('vh');
},
function() {
$(this).find('img').addClass('vh');
}
);
$('.download').click(function() {
window.open($(this).attr('data'));
});
$('.reply').each(function() {
$(this).click(function() {
var reply_to = $(this).attr('data');
$('#to_email').val(reply_to);
$('#message').text("回复" + reply_to + "");
$('#message').focus();
});
});
</script>
{% endblock %}

View File

@@ -1,11 +1,11 @@
from django.conf.urls.defaults import * from django.conf.urls.defaults import *
from views import group_list, group_operations, group_member_operations, \ from views import group_list, group_info, group_member_operations, \
group_members group_members, msg_reply
urlpatterns = patterns('', urlpatterns = patterns('',
url(r'^$', group_list, name='group_list'), url(r'^(?P<group_id>[\d]+)/$', group_info, name='group_info'),
(r'^(?P<group_id>[\d]+)/$', group_operations), url(r'^reply/(?P<msg_id>[\d]+)/$', msg_reply, name='msg_reply'),
url(r'^(?P<group_id>[\d]+)/members/$', group_members, name='group_members'), url(r'^(?P<group_id>[\d]+)/members/$', group_members, name='group_members'),
(r'^(?P<group_id>[\d]+)/member/(?P<user_name>[^/]+)/$', group_member_operations), (r'^(?P<group_id>[\d]+)/member/(?P<user_name>[^/]+)/$', group_member_operations),
) )

View File

@@ -1,5 +1,6 @@
# encoding: utf-8 # encoding: utf-8
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.core import serializers
from django.http import HttpResponse, HttpResponseRedirect, Http404 from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.shortcuts import render_to_response, redirect from django.shortcuts import render_to_response, redirect
from django.template import RequestContext from django.template import RequestContext
@@ -9,6 +10,8 @@ from seaserv import ccnet_rpc, ccnet_threaded_rpc, seafserv_threaded_rpc, get_re
get_group_repoids, check_group_staff get_group_repoids, check_group_staff
from pysearpc import SearpcError from pysearpc import SearpcError
from models import GroupMessage, MessageReply
from forms import MessageForm
from seahub.contacts.models import Contact from seahub.contacts.models import Contact
from seahub.utils import go_error, go_permission_error, validate_group_name from seahub.utils import go_error, go_permission_error, validate_group_name
from seahub.views import validate_emailuser from seahub.views import validate_emailuser
@@ -41,16 +44,6 @@ def group_list(request):
"groups": groups, "groups": groups,
}, context_instance=RequestContext(request)) }, context_instance=RequestContext(request))
@login_required
def group_operations(request, group_id):
op = request.GET.get('op', '')
if op == 'delete':
return group_remove(request, group_id)
elif op == 'quit':
return group_quit(request, group_id)
else:
return group_info(request, group_id )
@login_required @login_required
def group_remove(request, group_id): def group_remove(request, group_id):
try: try:
@@ -96,8 +89,7 @@ def group_quit(request, group_id):
return HttpResponseRedirect(reverse('group_list', args=[])) return HttpResponseRedirect(reverse('group_list', args=[]))
@login_required def render_group_info(request, group_id, form):
def group_info(request, group_id):
try: try:
group_id_int = int(group_id) group_id_int = int(group_id)
except ValueError: except ValueError:
@@ -146,6 +138,29 @@ def group_info(request, group_id):
repo.share_from_me = False repo.share_from_me = False
repos.append(repo) repos.append(repo)
"""group messages"""
# Make sure page request is an int. If not, deliver first page.
try:
current_page = int(request.GET.get('page', '1'))
per_page= int(request.GET.get('per_page', '15'))
except ValueError:
current_page = 1
per_page = 15
msgs_plus_one = GroupMessage.objects.filter(group_id=group_id).order_by('-timestamp')[per_page*(current_page-1) : per_page*current_page+1]
if len(msgs_plus_one) == per_page + 1:
page_next = True
else:
page_next = False
group_msgs = msgs_plus_one[:per_page]
for msg in group_msgs:
msg.reply_list = MessageReply.objects.filter(reply_to=msg)
msg.reply_cnt = len(msg.reply_list)
msg_cnt = GroupMessage.objects.filter(group_id=group_id).count()
return render_to_response("group/group_info.html", { return render_to_response("group/group_info.html", {
"managers": managers, "managers": managers,
"common_members": common_members, "common_members": common_members,
@@ -154,8 +169,75 @@ def group_info(request, group_id):
"group" : group, "group" : group,
"is_staff": is_staff, "is_staff": is_staff,
"is_join": joined, "is_join": joined,
"group_msgs": group_msgs,
"msg_cnt": msg_cnt,
"form": form,
'current_page': current_page,
'prev_page': current_page-1,
'next_page': current_page+1,
'per_page': per_page,
'page_next': page_next,
}, context_instance=RequestContext(request)); }, context_instance=RequestContext(request));
@login_required
def msg_reply(request, msg_id):
"""Show group message replies, and process message reply in ajax"""
if request.is_ajax():
if request.method == 'POST':
form = MessageForm(request.POST)
# TODO: invalid form
if form.is_valid():
msg = form.cleaned_data['message']
try:
group_msg = GroupMessage.objects.get(id=msg_id)
except GroupMessage.DoesNotExist:
return HttpResponse(status=400)
msg_reply = MessageReply()
msg_reply.reply_to = group_msg
msg_reply.from_email = request.user.username
msg_reply.message = msg
msg_reply.save()
format = 'json'
mimetype = 'application/javascript'
try:
msg = GroupMessage.objects.get(id=msg_id)
except GroupMessage.DoesNotExist:
raise HttpResponse(status=400)
data = serializers.serialize(format, MessageReply.objects.filter(reply_to=msg))
return HttpResponse(data,mimetype)
else:
return HttpResponse(status=400)
@login_required
def group_info(request, group_id):
if request.method == 'POST':
form = MessageForm(request.POST)
if form.is_valid():
msg = form.cleaned_data['message']
message = GroupMessage()
message.group_id = group_id
message.from_email = request.user.username
message.message = msg
message.save()
# clear form data
form = MessageForm()
else:
form = MessageForm()
op = request.GET.get('op', '')
if op == 'delete':
return group_remove(request, group_id)
elif op == 'quit':
return group_quit(request, group_id)
return render_group_info(request, group_id, form)
@login_required @login_required
def group_members(request, group_id): def group_members(request, group_id):
try: try:

View File

@@ -442,3 +442,31 @@ h2.repo-history {
font-size:12px; font-size:12px;
margin-top:10px; margin-top:10px;
} }
/* group message and replies */
#group-reply textarea{
width: 680px;
height: 100px;
}
#group-reply ul {
margin-top: 20px;
}
#group-reply li {
border-bottom: 1px dashed #999;
overflow: hidden;
min-height: 55px;
}
#group-reply .reply-list {
padding-bottom: 6px;
}
#group-reply .from {
color: #880088;
}
#group-reply .ts {
color: #808080;
font-size: 10px;
}
#group-reply .msg-op .msg {
display: inline-block;
}

View File

@@ -11,7 +11,7 @@
</li> </li>
{% endif %} {% endif %}
<li> <li>
<a href="{{ SITE_ROOT }}group/" {% block nav_group_class %}{% endblock %}>小组</a> <a href="{{ SITE_ROOT }}groups/" {% block nav_group_class %}{% endblock %}>小组</a>
</li> </li>
<li> <li>
<a href="{{ SITE_ROOT }}shareadmin/" {% block nav_shareadmin_class %}{% endblock %}>共享管理</a> <a href="{{ SITE_ROOT }}shareadmin/" {% block nav_shareadmin_class %}{% endblock %}>共享管理</a>

View File

@@ -12,6 +12,7 @@ from seahub.views import root, peers, myhome, \
seafile_access_check, back_local, repo_history_changes seafile_access_check, back_local, repo_history_changes
from seahub.notifications.views import notification_list from seahub.notifications.views import notification_list
from seahub.share.views import share_admin from seahub.share.views import share_admin
from seahub.group.views import group_list
# Uncomment the next two lines to enable the admin: # Uncomment the next two lines to enable the admin:
#from django.contrib import admin #from django.contrib import admin
@@ -59,13 +60,14 @@ urlpatterns = patterns('',
(r'^useradmin/remove/(?P<user_id>[^/]+)/$', user_remove), (r'^useradmin/remove/(?P<user_id>[^/]+)/$', user_remove),
(r'^useradmin/info/(?P<email>[^/]+)/$', user_info), (r'^useradmin/info/(?P<email>[^/]+)/$', user_info),
(r'^useradmin/activate/(?P<user_id>[^/]+)/$', activate_user), (r'^useradmin/activate/(?P<user_id>[^/]+)/$', activate_user),
### Apps ### ### Apps ###
(r'^avatar/', include('avatar.urls')), (r'^avatar/', include('avatar.urls')),
(r'^notification/', include('notifications.urls')), (r'^notification/', include('notifications.urls')),
url(r'^sys/notificationadmin/', notification_list, name='notification_list'), url(r'^sys/notificationadmin/', notification_list, name='notification_list'),
(r'^contacts/', include('contacts.urls')), (r'^contacts/', include('contacts.urls')),
(r'^group/', include('seahub.group.urls')), (r'^group/', include('seahub.group.urls')),
url(r'^groups/', group_list, name='group_list'),
(r'^profile/', include('seahub.profile.urls')), (r'^profile/', include('seahub.profile.urls')),
### SeaHub admin ### ### SeaHub admin ###