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:
8
group/forms.py
Normal file
8
group/forms.py
Normal 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)
|
||||
|
@@ -1,3 +1,14 @@
|
||||
import datetime
|
||||
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)
|
||||
|
@@ -65,6 +65,62 @@
|
||||
{% else %}
|
||||
<p>暂无</p>
|
||||
{% 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 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>
|
||||
{% endblock %}
|
||||
|
@@ -32,7 +32,7 @@
|
||||
<p>暂无</p>
|
||||
{% 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 />
|
||||
<input id="group_name" name="group_name" value="" /><br />
|
||||
<input type="submit" value="提交" />
|
||||
|
61
group/templates/group/msg_reply.html
Normal file
61
group/templates/group/msg_reply.html
Normal 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 %}
|
@@ -1,11 +1,11 @@
|
||||
from django.conf.urls.defaults import *
|
||||
|
||||
from views import group_list, group_operations, group_member_operations, \
|
||||
group_members
|
||||
from views import group_list, group_info, group_member_operations, \
|
||||
group_members, msg_reply
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^$', group_list, name='group_list'),
|
||||
(r'^(?P<group_id>[\d]+)/$', group_operations),
|
||||
url(r'^(?P<group_id>[\d]+)/$', group_info, name='group_info'),
|
||||
url(r'^reply/(?P<msg_id>[\d]+)/$', msg_reply, name='msg_reply'),
|
||||
url(r'^(?P<group_id>[\d]+)/members/$', group_members, name='group_members'),
|
||||
(r'^(?P<group_id>[\d]+)/member/(?P<user_name>[^/]+)/$', group_member_operations),
|
||||
)
|
||||
|
106
group/views.py
106
group/views.py
@@ -1,5 +1,6 @@
|
||||
# encoding: utf-8
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core import serializers
|
||||
from django.http import HttpResponse, HttpResponseRedirect, Http404
|
||||
from django.shortcuts import render_to_response, redirect
|
||||
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
|
||||
from pysearpc import SearpcError
|
||||
|
||||
from models import GroupMessage, MessageReply
|
||||
from forms import MessageForm
|
||||
from seahub.contacts.models import Contact
|
||||
from seahub.utils import go_error, go_permission_error, validate_group_name
|
||||
from seahub.views import validate_emailuser
|
||||
@@ -41,16 +44,6 @@ def group_list(request):
|
||||
"groups": groups,
|
||||
}, 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
|
||||
def group_remove(request, group_id):
|
||||
try:
|
||||
@@ -96,8 +89,7 @@ def group_quit(request, group_id):
|
||||
|
||||
return HttpResponseRedirect(reverse('group_list', args=[]))
|
||||
|
||||
@login_required
|
||||
def group_info(request, group_id):
|
||||
def render_group_info(request, group_id, form):
|
||||
try:
|
||||
group_id_int = int(group_id)
|
||||
except ValueError:
|
||||
@@ -146,6 +138,29 @@ def group_info(request, group_id):
|
||||
repo.share_from_me = False
|
||||
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", {
|
||||
"managers": managers,
|
||||
"common_members": common_members,
|
||||
@@ -154,8 +169,75 @@ def group_info(request, group_id):
|
||||
"group" : group,
|
||||
"is_staff": is_staff,
|
||||
"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));
|
||||
|
||||
@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
|
||||
def group_members(request, group_id):
|
||||
try:
|
||||
|
@@ -442,3 +442,31 @@ h2.repo-history {
|
||||
font-size:12px;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@@ -11,7 +11,7 @@
|
||||
</li>
|
||||
{% endif %}
|
||||
<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>
|
||||
<a href="{{ SITE_ROOT }}shareadmin/" {% block nav_shareadmin_class %}{% endblock %}>共享管理</a>
|
||||
|
2
urls.py
2
urls.py
@@ -12,6 +12,7 @@ from seahub.views import root, peers, myhome, \
|
||||
seafile_access_check, back_local, repo_history_changes
|
||||
from seahub.notifications.views import notification_list
|
||||
from seahub.share.views import share_admin
|
||||
from seahub.group.views import group_list
|
||||
|
||||
# Uncomment the next two lines to enable the admin:
|
||||
#from django.contrib import admin
|
||||
@@ -66,6 +67,7 @@ urlpatterns = patterns('',
|
||||
url(r'^sys/notificationadmin/', notification_list, name='notification_list'),
|
||||
(r'^contacts/', include('contacts.urls')),
|
||||
(r'^group/', include('seahub.group.urls')),
|
||||
url(r'^groups/', group_list, name='group_list'),
|
||||
(r'^profile/', include('seahub.profile.urls')),
|
||||
|
||||
### SeaHub admin ###
|
||||
|
Reference in New Issue
Block a user