1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-19 10:26:17 +00:00

Added innpub messages

This commit is contained in:
xiez
2012-09-14 22:15:14 +08:00
parent c8d708980c
commit 32f7463a1d
9 changed files with 396 additions and 20 deletions

View File

@@ -1,6 +1,14 @@
import datetime import datetime
import re
from django.db import models from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
from seaserv import get_emailusers
from shortcuts import get_first_object_or_none
from notifications.models import UserNotification
from profile.models import Profile
class UuidObjidMap(models.Model): class UuidObjidMap(models.Model):
""" """
@@ -24,3 +32,105 @@ class FileComment(models.Model):
class Meta: class Meta:
ordering = ['-timestamp'] ordering = ['-timestamp']
class InnerPubMsg(models.Model):
"""
Model used for leave message on inner pub page.
"""
from_email = models.EmailField()
message = models.CharField(max_length=500)
timestamp = models.DateTimeField(default=datetime.datetime.now)
class Meta:
ordering = ['-timestamp']
class InnerPubMsgReply(models.Model):
reply_to = models.ForeignKey(InnerPubMsg)
from_email = models.EmailField()
message = models.CharField(max_length=150)
timestamp = models.DateTimeField(default=datetime.datetime.now)
at_pattern = re.compile(r'(\s|^)(@\w+)', flags=re.U)
@receiver(post_save, sender=InnerPubMsgReply)
def msgreply_save_handler(sender, instance, **kwargs):
"""
Handle sending notification to '@<user>' when reply messages.
"""
from_email = instance.from_email
reply_msg = instance.message
innerpub_msg = instance.reply_to
to_user = ''
m = re.match(at_pattern, reply_msg)
if m:
nickname_or_emailprefix = m.group()[1:]
for member in get_emailusers(-1, -1):
# For every user, get his username and nickname if
# it exists, check whether match.
username = member.email
if username == from_email:
continue
p = get_first_object_or_none(
Profile.objects.filter(user=username))
nickname = p.nickname if p else ''
if nickname == nickname_or_emailprefix or \
username.split('@')[0] == nickname_or_emailprefix:
to_user = username
break
if to_user:
# Send notification to the user if he replies someone else'
# message.
try:
UserNotification.objects.get(to_user=to_user,
msg_type='innerpubmsg_reply',
detail=innerpub_msg.id)
except UserNotification.DoesNotExist:
n = UserNotification(to_user=to_user,
msg_type='innerpubmsg_reply',
detail=innerpub_msg.id)
n.save()
@receiver(post_save, sender=InnerPubMsg)
def innerpub_msg_added_cb(sender, instance, **kwargs):
from_email = instance.from_email
users = get_emailusers(-1, -1)
for u in users:
if u.email == from_email:
continue
try:
UserNotification.objects.get(to_user=u.email,
msg_type='innerpub_msg')
except UserNotification.DoesNotExist:
n = UserNotification(to_user=u.email, msg_type='innerpub_msg',
detail='')
n.save()
@receiver(post_save, sender=InnerPubMsgReply)
def innerpubmsg_reply_added_cb(sender, instance, **kwargs):
innerpub_msg = instance.reply_to
from_email = instance.from_email
msg_id = innerpub_msg.id
if from_email == innerpub_msg.from_email:
# No need to send notification when reply own message.
return
try:
innerpub_msg = InnerPubMsg.objects.get(id=msg_id)
except InnerPubMsg.DoesNotExist:
pass
try:
UserNotification.objects.get(to_user=innerpub_msg.from_email,
msg_type='innerpubmsg_reply',
detail=msg_id)
except UserNotification.DoesNotExist:
n = UserNotification(to_user=innerpub_msg.from_email,
msg_type='innerpubmsg_reply',
detail=msg_id)
n.save()

View File

@@ -2,7 +2,7 @@ from seaserv import ccnet_threaded_rpc
from signals import grpmsg_added from signals import grpmsg_added
from models import GroupMessage from models import GroupMessage
from seahub.notifications.models import UserNotification from notifications.models import UserNotification
def grpmsg_added_cb(sender, **kwargs): def grpmsg_added_cb(sender, **kwargs):
group_id = kwargs['group_id'] group_id = kwargs['group_id']

View File

@@ -6,14 +6,6 @@
{% block nav_group_class %}class="cur"{% endblock %} {% block nav_group_class %}class="cur"{% endblock %}
{% block main_panel %} {% block main_panel %}
{% if messages %}
<ul class="messages hide">
{% for message in messages %}
<li class="info">{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
<h2>{{ group.group_name }}</h2> <h2>{{ group.group_name }}</h2>
<div class="side fright"> <div class="side fright">
@@ -125,7 +117,7 @@
{{ msg.message|seahub_urlize|find_at|linebreaksbr }} {{ msg.message|seahub_urlize|find_at|linebreaksbr }}
</p> </p>
<button class="reply op" data="{{ msg.id }}"><span class="reply-cnt">{% if msg.reply_cnt != 0 %}{{ msg.reply_cnt }} {% endif %}</span>回复</button> <button class="reply op" data="{% url 'msg_reply' msg.id %}"><span class="reply-cnt">{% if msg.reply_cnt != 0 %}{{ msg.reply_cnt }} {% endif %}</span>回复</button>
<button class="replyclose op hide">收起回复</button> <button class="replyclose op hide">收起回复</button>
<div class="reply-bd"></div> <div class="reply-bd"></div>
</div> </div>

View File

@@ -8,7 +8,7 @@ $('.reply, .replyclose').hover(
); );
$('.reply').click(function() { $('.reply').click(function() {
var myself = $(this), var myself = $(this),
msg_id = $(this).attr('data'), msg_reply_url = $(this).attr('data'),
msg_bd = $(this).parent(), msg_bd = $(this).parent(),
reply_cnt = msg_bd.find('.reply-cnt'), reply_cnt = msg_bd.find('.reply-cnt'),
reply_bd = msg_bd.children('.reply-bd'); reply_bd = msg_bd.children('.reply-bd');
@@ -30,7 +30,7 @@ $('.reply').click(function() {
if (reply && reply.length <= 150) { if (reply && reply.length <= 150) {
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: '{{ SITE_ROOT }}group/reply/' + msg_id + '/', url: msg_reply_url,
dataType: 'json', dataType: 'json',
cache: false, cache: false,
contentType: 'application/json; charset=utf-8', contentType: 'application/json; charset=utf-8',
@@ -56,7 +56,7 @@ $('.reply').click(function() {
} else { } else {
reply_bd.html('<img src="{{MEDIA_URL}}img/loading-icon.gif" alt="加载中..." />'); reply_bd.html('<img src="{{MEDIA_URL}}img/loading-icon.gif" alt="加载中..." />');
$.ajax({ $.ajax({
url: '{{ SITE_ROOT }}group/reply/' + msg_id + '/', url: msg_reply_url,
dataType: 'json', dataType: 'json',
success: function(data) { success: function(data) {
reply_bd.html(data['html']).attr('class', 'reply-bd'); reply_bd.html(data['html']).attr('class', 'reply-bd');

View File

@@ -30,6 +30,12 @@
{% if grpmsg_reply_list %} {% if grpmsg_reply_list %}
<li><a href="{{ SITE_ROOT }}group/reply/new/" class="no-bold">{{ grpmsg_reply_list|length }}条留言有新回复</a></li> <li><a href="{{ SITE_ROOT }}group/reply/new/" class="no-bold">{{ grpmsg_reply_list|length }}条留言有新回复</a></li>
{% endif %} {% endif %}
{% if new_innerpub_msg %}
<li><a href="{% url 'public_home' %}" class="no-bold">公共页面有新留言</a></li>
{% endif %}
{% if innerpubmsg_reply_list %}
<li><a href="{% url 'innerpub_msg_reply_new' %}" class="no-bold">{{ innerpubmsg_reply_list|length }}条留言有新回复</a></li>
{% endif %}
{% if orgmsg_list %} {% if orgmsg_list %}
<li><a href="{% url 'org_msg' %}" class="no-bold">{{ orgmsg_list|length }}条团体消息</a></li> <li><a href="{% url 'org_msg' %}" class="no-bold">{{ orgmsg_list|length }}条团体消息</a></li>
{% endif %} {% endif %}

View File

@@ -0,0 +1,95 @@
{% extends "myhome_base.html" %}
{% load seahub_tags avatar_tags %}
{% load url from future %}
{% block right_panel %}
{% if innerpub_msgs %}
<ul class="msg-list">
{% for msg in innerpub_msgs %}
<li class="msg w100 ovhd">
<div class="pic fleft">
<a href="{% url 'user_profile' msg.from_email %}">{% avatar msg.from_email 48 %}</a>
</div>
<div class="txt fright">
<div class="msg-hd">
<span class="time">{{ msg.timestamp|translate_commit_time }}</span>
<a href="{% url 'user_profile' msg.from_email %}">{{ msg.from_email|email2nickname }}</a>
<span class="group">留言所属:<a href="{% url 'public_home' %}">公共页面</a></span>
</div>
<div class="msg-bd">
<p>
{{ msg.message|seahub_urlize|find_at|linebreaksbr }}
</p>
<button class="reply op hide" data="{% url 'innerpub_msg_reply' msg.id %}"><span class="reply-cnt">{{ msg.reply_cnt }} </span>回复</a>
<button class="replyclose op">收起回复</button>
<div class="reply-bd">
<ul class="reply-list">
{% for reply in msg.reply_list %}
<li class="w100 ovhd">
<a href="{% url 'user_profile' reply.from_email %}" class="pic fleft">{% avatar reply.from_email 28 %}</a>
<div class="txt fright">
<a href="{% url 'user_profile' reply.from_email %}">{{ reply.from_email|email2nickname }}</a> : {{ reply.message|seahub_urlize|find_at }} --
<button class="reply-at op" data="{{ reply.from_email|email2nickname }}">回复</button>
</div>
</li>
{% endfor %}
</ul>
<textarea name="message" class="reply-input"></textarea>
<button class="submit">回复</button>
<p class="error hide">输入不能为空且应少于150个字符。</p>
</div>
</div>
</div>
</li>
{% endfor %}
</ul>
{% else %}
<p>暂无</p>
{% endif %}
{% endblock %}
{% block extra_script %}
<script type="text/javascript">
{% include 'group/msg_reply_js.html' %}
$('.reply-at').click(function() {
var reply_input = $(this).parent().parent().parent().next();
reply_input.val('@' + $(this).attr('data') + ' ');
var pos = reply_input.val().length;
setCaretPos(reply_input[0], pos);
reply_input.focus();
});
$('.reply-bd .submit').click(function() {
var msg_bd = $(this).parent().parent(),
msg_reply_url = msg_bd.find('.reply').attr('data'),
reply_cnt = msg_bd.find('.reply-cnt'),
reply_input = $(this).prev(),
reply = $.trim(reply_input.val()),
error = $(this).next();
if (reply && reply.length <= 150) {
$.ajax({
type: "POST",
url: msg_reply_url,
dataType: 'json',
cache: false,
contentType: 'application/json; charset=utf-8',
beforeSend: prepareCSRFToken,
data: "message=" + reply,
success: function(data) {
msg_bd.find('.reply-list').append(data['html']);
reply_input.val('');
error.attr('class', 'error hide');
reply_cnt.html(parseInt(reply_cnt.html()) + 1 + ' ');
msg_bd.find('.reply-at').click(function() {
reply_input.val('@' + $(this).attr('data') + ' ');
var pos = reply_input.val().length;
setCaretPos(reply_input[0], pos);
reply_input.focus();
});
}
});
} else {
error.removeClass('hide');
}
});
</script>
{% endblock %}

View File

@@ -56,8 +56,54 @@
{% endfor %} {% endfor %}
</table> </table>
{% endif %} {% endif %}
</div>
<!-- 信息栏 -->
<div id="innerpub-msg">
<h3>信息栏</h3>
<form id="innerpub-msg-form" action="" method="post">
<textarea name="message" id="message">{{ form.data.message }}</textarea><br />
{% for error in form.message.errors %}
<p class="error">{{ error|escape }}</p>
{% endfor %}
<input type="submit" value="提交" class="submit" />
</form>
</div>
{% if innerpub_msgs %}
<ul class="msg-list">
{% for msg in innerpub_msgs %}
<li class="msg w100 ovhd">
<div class="pic fleft">
<a href="{{ SITE_ROOT }}profile/{{ msg.from_email }}/">{% avatar msg.from_email 48 %}</a>
</div>
<div class="txt fright">
<div class="msg-hd">
<span class="time">{{ msg.timestamp|translate_commit_time }}</span>
<a href="{{ SITE_ROOT }}profile/{{ msg.from_email }}/" title="{{ msg.from_email }}">{{ msg.from_email|email2nickname }}</a>
</div>
<div class="msg-bd">
<p>
{{ msg.message|seahub_urlize|find_at|linebreaksbr }}
</p>
<button class="reply op" data="{% url 'innerpub_msg_reply' msg.id %}"><span class="reply-cnt">{% if msg.reply_cnt != 0 %}{{ msg.reply_cnt }} {% endif %}</span>回复</button>
<button class="replyclose op hide">收起回复</button>
<div class="reply-bd"></div>
</div>
</div>
</li>
{% endfor %}
</ul>
{% endif %}
<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>
<!-- /.main -->
{% include "snippets/repo_share_form.html" %} {% include "snippets/repo_share_form.html" %}
{% include "snippets/repo_create_form.html" %} {% include "snippets/repo_create_form.html" %}
{% include "snippets/user_profile_html.html" %} {% include "snippets/user_profile_html.html" %}
@@ -72,5 +118,7 @@
{% 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 %}
{% include 'group/msg_reply_js.html' %}
</script> </script>
{% endblock %} {% endblock %}

View File

@@ -28,6 +28,8 @@ urlpatterns = patterns('',
#url(r'^home/$', direct_to_template, { 'template': 'home.html' } ), #url(r'^home/$', direct_to_template, { 'template': 'home.html' } ),
url(r'^home/my/$', myhome, name='myhome'), url(r'^home/my/$', myhome, name='myhome'),
url(r'^home/public/$', public_home, name='public_home'), url(r'^home/public/$', public_home, name='public_home'),
url(r'^home/public/reply/(?P<msg_id>[\d]+)/$', innerpub_msg_reply, name='innerpub_msg_reply'),
url(r'^home/public/reply/new/$', innerpub_msg_reply_new, name='innerpub_msg_reply_new'),
url(r'^home/owner/(?P<owner_name>[^/]+)/$', ownerhome, name='ownerhome'), url(r'^home/owner/(?P<owner_name>[^/]+)/$', ownerhome, name='ownerhome'),
(r'^share/', include('share.urls')), (r'^share/', include('share.urls')),

135
views.py
View File

@@ -20,6 +20,7 @@ from django.http import HttpResponse, HttpResponseBadRequest, Http404, \
HttpResponseRedirect HttpResponseRedirect
from django.shortcuts import render_to_response, redirect from django.shortcuts import render_to_response, redirect
from django.template import Context, loader, RequestContext from django.template import Context, loader, RequestContext
from django.template.loader import render_to_string
from django.utils.hashcompat import md5_constructor from django.utils.hashcompat import md5_constructor
from django.views.decorators.csrf import csrf_protect from django.views.decorators.csrf import csrf_protect
from django.views.generic.base import TemplateView, TemplateResponseMixin from django.views.generic.base import TemplateView, TemplateResponseMixin
@@ -43,12 +44,14 @@ from pysearpc import SearpcError
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
from seahub.base.models import UuidObjidMap, FileComment from base.models import UuidObjidMap, FileComment, InnerPubMsg, InnerPubMsgReply
from seahub.contacts.models import Contact from contacts.models import Contact
from seahub.contacts.signals import mail_sended from contacts.signals import mail_sended
from group.forms import MessageForm, MessageReplyForm
from group.models import GroupMessage, MessageAttachment from group.models import GroupMessage, MessageAttachment
from group.signals import grpmsg_added from group.signals import grpmsg_added
from seahub.notifications.models import UserNotification from notifications.models import UserNotification
from profile.models import Profile
from forms import AddUserForm, FileLinkShareForm, RepoCreateForm, \ from forms import AddUserForm, FileLinkShareForm, RepoCreateForm, \
RepoNewDirForm, RepoNewFileForm, FileCommentForm, RepoRenameFileForm, \ RepoNewDirForm, RepoNewFileForm, FileCommentForm, RepoRenameFileForm, \
RepoPassowrdForm RepoPassowrdForm
@@ -59,7 +62,6 @@ from utils import render_permission_error, render_error, list_to_string, \
get_file_revision_id_size, get_ccnet_server_addr_port, \ get_file_revision_id_size, get_ccnet_server_addr_port, \
gen_file_get_url, string2list, MAX_INT, \ gen_file_get_url, string2list, MAX_INT, \
gen_file_upload_url, check_and_get_org_by_repo gen_file_upload_url, check_and_get_org_by_repo
from seahub.profile.models import Profile
try: try:
from settings import DOCUMENT_CONVERTOR_ROOT from settings import DOCUMENT_CONVERTOR_ROOT
if DOCUMENT_CONVERTOR_ROOT[-1:] != '/': if DOCUMENT_CONVERTOR_ROOT[-1:] != '/':
@@ -695,6 +697,8 @@ def myhome(request):
grpmsg_reply_list = [] grpmsg_reply_list = []
orgmsg_list = [] orgmsg_list = []
notes = UserNotification.objects.filter(to_user=request.user.username) notes = UserNotification.objects.filter(to_user=request.user.username)
new_innerpub_msg = False
innerpubmsg_reply_list = []
for n in notes: for n in notes:
if n.msg_type == 'group_msg': if n.msg_type == 'group_msg':
grp = get_group(n.detail) grp = get_group(n.detail)
@@ -705,6 +709,10 @@ def myhome(request):
grpmsg_reply_list.append(n.detail) grpmsg_reply_list.append(n.detail)
elif n.msg_type == 'org_join_msg': elif n.msg_type == 'org_join_msg':
orgmsg_list.append(n.detail) orgmsg_list.append(n.detail)
elif n.msg_type == 'innerpub_msg':
new_innerpub_msg = True
elif n.msg_type == 'innerpubmsg_reply':
innerpubmsg_reply_list.append(n.detail)
# my groups # my groups
groups = get_personal_groups(email) groups = get_personal_groups(email)
@@ -732,6 +740,8 @@ def myhome(request):
"grpmsg_list": grpmsg_list, "grpmsg_list": grpmsg_list,
"grpmsg_reply_list": grpmsg_reply_list, "grpmsg_reply_list": grpmsg_reply_list,
"orgmsg_list": orgmsg_list, "orgmsg_list": orgmsg_list,
"new_innerpub_msg": new_innerpub_msg,
"innerpubmsg_reply_list": innerpubmsg_reply_list,
}, context_instance=RequestContext(request)) }, context_instance=RequestContext(request))
@login_required @login_required
@@ -739,14 +749,127 @@ def public_home(request):
""" """
Show public home page when CLOUD_MODE is False. Show public home page when CLOUD_MODE is False.
""" """
if request.method == 'POST':
form = MessageForm(request.POST)
if form.is_valid():
msg = InnerPubMsg()
msg.from_email = request.user.username
msg.message = form.cleaned_data['message']
msg.save()
return HttpResponseRedirect(reverse('public_home'))
else:
form = MessageForm()
users = get_emailusers(-1, -1) users = get_emailusers(-1, -1)
public_repos = list_inner_pub_repos() public_repos = list_inner_pub_repos()
"""inner pub 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 = InnerPubMsg.objects.all()[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
innerpub_msgs = msgs_plus_one[:per_page]
msg_replies = InnerPubMsgReply.objects.filter(reply_to__in=innerpub_msgs)
reply_to_list = [ r.reply_to_id for r in msg_replies ]
for msg in innerpub_msgs:
msg.reply_cnt = reply_to_list.count(msg.id)
# remove user notifications
UserNotification.objects.filter(to_user=request.user.username,
msg_type='innerpub_msg').delete()
return render_to_response('public_home.html', { return render_to_response('public_home.html', {
'users': users, 'users': users,
'public_repos': public_repos, 'public_repos': public_repos,
'form': form,
'innerpub_msgs': innerpub_msgs,
'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 innerpub_msg_reply(request, msg_id):
"""Show inner pub message replies, and process message reply in ajax"""
content_type = 'application/json; charset=utf-8'
if request.is_ajax():
ctx = {}
if request.method == 'POST':
form = MessageReplyForm(request.POST)
# TODO: invalid form
if form.is_valid():
msg = form.cleaned_data['message']
try:
innerpub_msg = InnerPubMsg.objects.get(id=msg_id)
except InnerPubMsg.DoesNotExist:
return HttpResponseBadRequest(content_type=content_type)
msg_reply = InnerPubMsgReply()
msg_reply.reply_to = innerpub_msg
msg_reply.from_email = request.user.username
msg_reply.message = msg
msg_reply.save()
ctx['reply'] = msg_reply
html = render_to_string("group/group_reply_new.html", ctx)
else:
try:
msg = InnerPubMsg.objects.get(id=msg_id)
except InnerPubMsg.DoesNotExist:
raise HttpResponse(status=400)
replies = InnerPubMsgReply.objects.filter(reply_to=msg)
ctx['replies'] = replies
html = render_to_string("group/group_reply_list.html", ctx)
serialized_data = json.dumps({"html": html})
return HttpResponse(serialized_data, content_type=content_type)
else:
return HttpResponseBadRequest(content_type=content_type)
@login_required
def innerpub_msg_reply_new(request):
notes = UserNotification.objects.filter(to_user=request.user.username)
innerpub_reply_list = [ n.detail for n in notes if \
n.msg_type == 'innerpubmsg_reply']
innerpub_msgs = []
for msg_id in innerpub_reply_list:
try:
m = InnerPubMsg.objects.get(id=msg_id)
except InnerPubMsg.DoesNotExist:
continue
else:
m.reply_list = InnerPubMsgReply.objects.filter(reply_to=m)
m.reply_cnt = m.reply_list.count()
innerpub_msgs.append(m)
# remove new innerpub msg reply notification
UserNotification.objects.filter(to_user=request.user.username,
msg_type='innerpubmsg_reply').delete()
return render_to_response("new_innerpubmsg_reply.html", {
'innerpub_msgs': innerpub_msgs,
}, context_instance=RequestContext(request))
@login_required @login_required
def public_repo_create(request): def public_repo_create(request):
''' '''