diff --git a/base/middleware.py b/base/middleware.py index 9428ce3efc..490d62859b 100644 --- a/base/middleware.py +++ b/base/middleware.py @@ -1,5 +1,10 @@ +from django.core.cache import cache + from seaserv import get_binding_peerids +from seahub.notifications.models import Notification +from seahub.notifications.utils import refresh_cache + class UseridMiddleware(object): """Store ccnet user ids in request.user.userid_list""" @@ -16,3 +21,30 @@ class UseridMiddleware(object): def process_response(self, request, response): return response + +class InfobarMiddleware(object): + """Query info bar close status, and store into reqeust.""" + + def get_from_db(self): + ret = Notification.objects.all().filter(primary=1) + refresh_cache() + return ret + + def process_request(self, request): + topinfo_close = request.COOKIES.get('topinfo', '') + + cur_note = cache.get('CUR_TOPINFO') if cache.get('CUR_TOPINFO') else \ + self.get_from_db() + if not cur_note: + request.cur_note = None + else: + if str(cur_note[0].id) in topinfo_close.split(','): + request.cur_note = None + else: + request.cur_note = cur_note[0] + + return None + + def process_response(self, request, response): + return response + diff --git a/media/css/seahub.css b/media/css/seahub.css index db511a0283..815191fa1a 100644 --- a/media/css/seahub.css +++ b/media/css/seahub.css @@ -127,6 +127,12 @@ table img { width:680px; } #footer { color:#999; padding-top:2px; margin:25px auto; border-top:1px solid #DDD; } + +/* info-bar */ +#info-bar { height: 30px; color: #fff; background: #000; } +#info-bar .info { margin: 5px 0 auto 1em; float: left; } +#info-bar .close { margin: 7px 5px auto 0; float: right; background: url(../img/close-16.png); height: 16px; width:16px; } + /* top-bar */ #top-bar { height:20px; padding-bottom:21px; background:#fff url('../img/dropshadow.png') repeat-x center bottom; } .top-bar { height:20px; color:#fff; text-align:right; font-weight:bold; background:#606; } @@ -331,3 +337,6 @@ h2.repo-history { background:transparent url('../img/add.png') scroll no-repeat left 50%; margin-top:2px; } + +/* notification admin */ +.cur-note { color: red; font-size: 75%; } diff --git a/notifications/__init__.py b/notifications/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/notifications/models.py b/notifications/models.py new file mode 100644 index 0000000000..f7122faedf --- /dev/null +++ b/notifications/models.py @@ -0,0 +1,18 @@ +from django.db import models +from django.forms import ModelForm, Textarea + +class Notification(models.Model): + message = models.CharField(max_length=512) + primary = models.BooleanField(default=False) + +class NotificationForm(ModelForm): + """ + Form for adding notification. + """ + class Meta: + model = Notification + fields = ('message', 'primary') + widgets = { + 'message': Textarea(), + } + diff --git a/notifications/templates/notifications/add_notification_form.html b/notifications/templates/notifications/add_notification_form.html new file mode 100644 index 0000000000..d9a82398ec --- /dev/null +++ b/notifications/templates/notifications/add_notification_form.html @@ -0,0 +1,18 @@ +{% extends "admin_base.html" %} +{% block title %}添加通知{% endblock %} +{% block nav_notificationadmin_class %}class="cur"{% endblock %} +{% block main_panel %} +
+

添加通知

+
+ + {{ form.message }} + +
+
+{% endblock %} + +{% block extra_script %} + +{% endblock %} diff --git a/notifications/templates/notifications/notification_list.html b/notifications/templates/notifications/notification_list.html new file mode 100644 index 0000000000..b00f1877ca --- /dev/null +++ b/notifications/templates/notifications/notification_list.html @@ -0,0 +1,74 @@ +{% extends "admin_base.html" %} +{% block nav_notificationadmin_class %}class="cur"{% endblock %} + +{% block left_panel %} +

操作

+ +{% endblock %} + +{% block right_panel %} +

所有通知

+{% if notes %} + + + + + + {% for note in notes %} + + + + {% endfor %} +
内容操作
{{ note.message }} + {% if note.primary == 1 %} + (当前通知) + {% endif %} + + {% if note.primary != 1 %} + + {% endif %} + +
+ +{% else %} +

暂无

+{% endif %} +{% endblock %} + +{% block extra_script %} + +{% endblock %} + diff --git a/notifications/tests.py b/notifications/tests.py new file mode 100644 index 0000000000..501deb776c --- /dev/null +++ b/notifications/tests.py @@ -0,0 +1,16 @@ +""" +This file demonstrates writing tests using the unittest module. These will pass +when you run "manage.py test". + +Replace this with more appropriate tests for your application. +""" + +from django.test import TestCase + + +class SimpleTest(TestCase): + def test_basic_addition(self): + """ + Tests that 1 + 1 always equals 2. + """ + self.assertEqual(1 + 1, 2) diff --git a/notifications/urls.py b/notifications/urls.py new file mode 100644 index 0000000000..7d5ff43812 --- /dev/null +++ b/notifications/urls.py @@ -0,0 +1,11 @@ +from django.conf.urls.defaults import patterns, url + +urlpatterns = patterns('notifications.views', +# url(r'^$', 'notification_list', name='notification_list'), + url(r'^add/$', 'notification_add', name='notification_add'), + url(r'^delete/(?P[\d]+)/$', 'notification_delete', name='notification_delete'), + url(r'^set-primary/(?P[\d]+)/$', 'set_primary', name='set_primary'), + url(r'^close/(?P[\d]+)/$', 'notification_close', name='notification_close'), +) + + diff --git a/notifications/utils.py b/notifications/utils.py new file mode 100644 index 0000000000..c69bcff998 --- /dev/null +++ b/notifications/utils.py @@ -0,0 +1,11 @@ +from django.core.cache import cache + +from seahub.notifications.models import Notification + +def refresh_cache(): + """ + Function to be called when change primary notification. + """ + cache.set('CUR_TOPINFO', Notification.objects.all().filter(primary=1), + 24*60*60) + diff --git a/notifications/views.py b/notifications/views.py new file mode 100644 index 0000000000..759682c824 --- /dev/null +++ b/notifications/views.py @@ -0,0 +1,68 @@ +import datetime +from django.core.urlresolvers import reverse +from django.http import HttpResponseRedirect, Http404 +from django.shortcuts import render_to_response +from django.template import RequestContext + +from auth.decorators import login_required + +from seahub.notifications.models import Notification, NotificationForm +from seahub.notifications.utils import refresh_cache + +@login_required +def notification_close(request, note_id): + note_id += ',' + topinfo_close = request.COOKIES.get('topinfo', '') + topinfo_close += note_id + + res = HttpResponseRedirect(request.META['HTTP_REFERER']) + res.set_cookie("topinfo", topinfo_close, max_age=14*24*60*60) + + return res + +@login_required +def notification_list(request): + if not request.user.is_staff: + raise Http404 + notes = Notification.objects.all().order_by('-id') + + return render_to_response('notifications/notification_list.html', { + 'notes': notes, + }, context_instance=RequestContext(request)) + +@login_required +def notification_add(request): + if not request.user.is_staff: + raise Http404 + if request.method == 'POST': + f = NotificationForm(request.POST) + f.save() + return HttpResponseRedirect(reverse('notification_list', args=[])) + else: + form = NotificationForm() + + return render_to_response("notifications/add_notification_form.html", { + 'form': form, + }, context_instance=RequestContext(request)) + +@login_required +def notification_delete(request, nid): + if not request.user.is_staff: + raise Http404 + Notification.objects.filter(id=nid).delete() + refresh_cache() + + return HttpResponseRedirect(reverse('notification_list', args=[])) + +@login_required +def set_primary(request, nid): + if not request.user.is_staff: + raise Http404 + + # TODO: use transaction? + Notification.objects.filter(primary=1).update(primary=0) + Notification.objects.filter(id=nid).update(primary=1) + + refresh_cache() + + return HttpResponseRedirect(reverse('notification_list', args=[])) diff --git a/settings.py b/settings.py index a8bc34df5a..d0af2b673f 100644 --- a/settings.py +++ b/settings.py @@ -66,6 +66,7 @@ MIDDLEWARE_CLASSES = ( 'django.middleware.csrf.CsrfResponseMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'auth.middleware.AuthenticationMiddleware', + 'seahub.base.middleware.InfobarMiddleware', # 'seahub.base.middleware.UseridMiddleware', ) @@ -100,6 +101,7 @@ INSTALLED_APPS = ( # 'django.contrib.admin', 'registration', 'avatar', + 'seahub.notifications', 'seahub.base', 'seahub.profile', 'seahub.contacts', diff --git a/templates/admin_base.html b/templates/admin_base.html index 90ca23a04a..f89be677d8 100644 --- a/templates/admin_base.html +++ b/templates/admin_base.html @@ -12,6 +12,9 @@
  • 小组管理
  • +
  • + 通知管理 +
  • {% endif %} {% endblock %} diff --git a/templates/base.html b/templates/base.html index e3e5c64832..24e8fa1b4c 100644 --- a/templates/base.html +++ b/templates/base.html @@ -13,14 +13,21 @@
    + {% if request.user.is_authenticated and request.cur_note %} +
    + {{ request.cur_note.message|urlize }} + +
    + {% endif %} +
    {% if request.user.is_staff %} - + {% endif %}
    diff --git a/templates/registration/registration_form.html b/templates/registration/registration_form.html index fc04f724ec..91d30101b1 100644 --- a/templates/registration/registration_form.html +++ b/templates/registration/registration_form.html @@ -2,6 +2,9 @@ {% block title %}注册{% endblock %} {% block main_panel %}
    +{% if request.user.is_authenticated %} +

    欢迎回来,您已登录。

    +{% else %}

    注册

    @@ -16,6 +19,7 @@ {{ form.password2.errors }}
    +{% endif %}
    {% endblock %} diff --git a/thirdpart/auth/views.py b/thirdpart/auth/views.py index 7d94c7557b..6983f28468 100644 --- a/thirdpart/auth/views.py +++ b/thirdpart/auth/views.py @@ -23,10 +23,14 @@ from seaserv import get_ccnetuser @csrf_protect @never_cache def login(request, template_name='registration/login.html', + redirect_if_logged_in=None, redirect_field_name=REDIRECT_FIELD_NAME, authentication_form=AuthenticationForm): """Displays the login form and handles the login action.""" + if request.user.is_authenticated() and redirect_if_logged_in: + return HttpResponseRedirect(reverse(redirect_if_logged_in)) + redirect_to = request.REQUEST.get(redirect_field_name, '') if request.method == "POST": diff --git a/thirdpart/registration/auth_urls.py b/thirdpart/registration/auth_urls.py index dfbd989a6d..5e82184334 100644 --- a/thirdpart/registration/auth_urls.py +++ b/thirdpart/registration/auth_urls.py @@ -30,7 +30,8 @@ from auth import views as auth_views urlpatterns = patterns('', url(r'^login/$', auth_views.login, - {'template_name': 'registration/login.html'}, + {'template_name': 'registration/login.html', + 'redirect_if_logged_in': 'myhome'}, name='auth_login'), url(r'^logout/$', auth_views.logout, diff --git a/urls.py b/urls.py index 377bde5185..04474e4c24 100644 --- a/urls.py +++ b/urls.py @@ -9,6 +9,7 @@ from seahub.views import root, peers, myhome, \ user_info, repo_set_access_property, repo_access_file, \ repo_add_share, repo_list_share, repo_remove_share, repo_download, \ seafile_access_check, back_local, group_admin, repo_history_changes +from seahub.notifications.views import notification_list # Uncomment the next two lines to enable the admin: #from django.contrib import admin @@ -59,6 +60,8 @@ urlpatterns = patterns('', (r'^useradmin/activate/(?P[^/]+)/$', activate_user), (r'^avatar/', include('avatar.urls')), + (r'^notification/', include('notifications.urls')), + url(r'^notificationadmin/', notification_list, name='notification_list'), (r'^contacts/', include('contacts.urls')), (r'^group/', include('seahub.group.urls')), url(r'^groupadmin/$', group_admin, name='group_admin'),