1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-08-31 22:54:11 +00:00

optimize notification (#7521)

* update

* update

---------

Co-authored-by: 孙永强 <11704063+s-yongqiang@user.noreply.gitee.com>
This commit is contained in:
awu0403
2025-02-27 17:00:33 +08:00
committed by GitHub
parent 2fb65580e4
commit 3899577631
5 changed files with 81 additions and 67 deletions

View File

@@ -12,7 +12,7 @@ class Notification extends React.Component {
super(props); super(props);
this.state = { this.state = {
showNotice: false, showNotice: false,
unseenCount: 0, totalUnseenCount: 0,
generalNoticeList: [], generalNoticeList: [],
discussionNoticeList: [], discussionNoticeList: [],
currentTab: 'general', currentTab: 'general',
@@ -22,8 +22,11 @@ class Notification extends React.Component {
componentDidMount() { componentDidMount() {
seafileAPI.listAllNotifications().then(res => { seafileAPI.listAllNotifications().then(res => {
let unseen_count = res.data.general.unseen_count + res.data.discussion.unseen_count; this.setState({
this.setState({ unseenCount: unseen_count }); totalUnseenCount: res.data.total_unseen_count,
generalNoticeListUnseen: res.data.general.unseen_count,
discussionNoticeListUnseen: res.data.discussion.unseen_count
});
}); });
} }
@@ -33,7 +36,7 @@ class Notification extends React.Component {
seafileAPI.updateNotifications(); seafileAPI.updateNotifications();
this.setState({ this.setState({
showNotice: false, showNotice: false,
unseenCount: 0 totalUnseenCount: 0
}); });
} else { } else {
this.loadNotices(); this.loadNotices();
@@ -52,13 +55,17 @@ class Notification extends React.Component {
loadNotices = () => { loadNotices = () => {
let page = 1; let page = 1;
let perPage = 5; let perPage = 25;
seafileAPI.listAllNotifications(page, perPage).then(res => { seafileAPI.listAllNotifications(page, perPage).then(res => {
let generalNoticeList = res.data.general.notification_list; let generalNoticeList = res.data.general.notification_list;
let discussionNoticeList = res.data.discussion.notification_list; let discussionNoticeList = res.data.discussion.notification_list;
let generalNoticeListUnseen = res.data.general.unseen_count;
let discussionNoticeListUnseen = res.data.discussion.unseen_count;
this.setState({ this.setState({
generalNoticeList: generalNoticeList, generalNoticeList: generalNoticeList,
discussionNoticeList: discussionNoticeList discussionNoticeList: discussionNoticeList,
generalNoticeListUnseen: generalNoticeListUnseen,
discussionNoticeListUnseen: discussionNoticeListUnseen
}); });
}); });
}; };
@@ -71,10 +78,12 @@ class Notification extends React.Component {
} }
return item; return item;
}); });
let unseenCount = this.state.unseenCount === 0 ? 0 : this.state.unseenCount - 1; let totalUnseenCount = this.state.totalUnseenCount === 0 ? 0 : this.state.totalUnseenCount - 1;
let generalNoticeListUnseen = this.state.generalNoticeListUnseen === 0 ? 0 : this.state.generalNoticeListUnseen - 1;
this.setState({ this.setState({
generalNoticeList: noticeList, generalNoticeList: noticeList,
unseenCount: unseenCount, totalUnseenCount: totalUnseenCount,
generalNoticeListUnseen: generalNoticeListUnseen
}); });
seafileAPI.markNoticeAsRead(noticeItem.id); seafileAPI.markNoticeAsRead(noticeItem.id);
} }
@@ -85,10 +94,12 @@ class Notification extends React.Component {
} }
return item; return item;
}); });
let unseenCount = this.state.unseenCount === 0 ? 0 : this.state.unseenCount - 1; let totalUnseenCount = this.state.totalUnseenCount === 0 ? 0 : this.state.totalUnseenCount - 1;
let discussionNoticeListUnseen = this.state.discussionNoticeListUnseen === 0 ? 0 : this.state.discussionNoticeListUnseen - 1;
this.setState({ this.setState({
discussionNoticeList: noticeList, discussionNoticeList: noticeList,
unseenCount: unseenCount, totalUnseenCount: totalUnseenCount,
discussionNoticeListUnseen: discussionNoticeListUnseen
}); });
seafileAPI.markSdocNoticeAsRead(noticeItem.id); seafileAPI.markSdocNoticeAsRead(noticeItem.id);
} }
@@ -111,26 +122,62 @@ class Notification extends React.Component {
}; };
onMarkAllNotifications = () => { onMarkAllNotifications = () => {
seafileAPI.updateAllNotifications().then(() => { let generalNoticeListUnseen = this.state.generalNoticeListUnseen;
this.setState({ let discussionNoticeListUnseen = this.state.discussionNoticeListUnseen;
unseenCount: 0, if (this.state.currentTab === 'general') {
seafileAPI.updateNotifications().then((res) => {
this.setState({
generalNoticeList: this.state.generalNoticeList.map(item => {
item.seen = true;
return item;
}),
generalNoticeListUnseen: 0,
totalUnseenCount: discussionNoticeListUnseen
});
}).catch((error) => {
this.setState({
errorMsg: Utils.getErrorMsg(error, true) // true: show login tip if 403
});
}); });
}).catch((error) => { } else if (this.state.currentTab === 'discussion') {
this.setState({ seafileAPI.updateSdocNotifications().then((res) => {
errorMsg: Utils.getErrorMsg(error, true) this.setState({
discussionNoticeList: this.state.discussionNoticeList.map(item => {
item.seen = true;
return item;
}),
discussionNoticeListUnseen: 0,
totalUnseenCount: generalNoticeListUnseen
});
}).catch((error) => {
this.setState({
errorMsg: Utils.getErrorMsg(error, true) // true: show login tip if 403
});
}); });
}); }
};
updateTotalUnseenCount = (noticeType) => {
if (noticeType === 'general') {
this.setState({
generalNoticeListUnseen: 0,
totalUnseenCount: this.state.discussionNoticeListUnseen
});
} else if (noticeType === 'discussion') {
this.setState({
discussionNoticeListUnseen: 0,
totalUnseenCount: this.state.generalNoticeListUnseen
});
}
}; };
render() { render() {
const { unseenCount, currentTab, generalNoticeList, discussionNoticeList } = this.state; const { totalUnseenCount, currentTab, generalNoticeList, discussionNoticeList, generalNoticeListUnseen, discussionNoticeListUnseen } = this.state;
const generalNoticeListUnseen = generalNoticeList.filter(item => !item.seen).length;
const discussionNoticeListUnseen = discussionNoticeList.filter(item => !item.seen).length;
return ( return (
<div id="notifications"> <div id="notifications">
<a href="#" onClick={this.onClick} className="no-deco" id="notice-icon" title={gettext('Notifications')} aria-label={gettext('Notifications')}> <a href="#" onClick={this.onClick} className="no-deco" id="notice-icon" title={gettext('Notifications')} aria-label={gettext('Notifications')}>
<span className="sf2-icon-bell" id="notification-popover"></span> <span className="sf2-icon-bell" id="notification-popover"></span>
<span className={`num ${unseenCount ? '' : 'hide'}`}>{unseenCount}</span> <span className={`num ${totalUnseenCount ? '' : 'hide'}`}>{totalUnseenCount}</span>
</a> </a>
{this.state.showNotice && {this.state.showNotice &&
<NotificationPopover <NotificationPopover
@@ -170,6 +217,7 @@ class Notification extends React.Component {
onNotificationDialogToggle={this.onNotificationDialogToggle} onNotificationDialogToggle={this.onNotificationDialogToggle}
generalNoticeListUnseen={generalNoticeListUnseen} generalNoticeListUnseen={generalNoticeListUnseen}
discussionNoticeListUnseen={discussionNoticeListUnseen} discussionNoticeListUnseen={discussionNoticeListUnseen}
updateTotalUnseenCount={this.updateTotalUnseenCount}
/> />
} }
</div> </div>

View File

@@ -101,6 +101,7 @@ class UserNotificationsDialog extends React.Component {
return item; return item;
}) })
}); });
this.props.updateTotalUnseenCount('general');
}).catch((error) => { }).catch((error) => {
this.setState({ this.setState({
isLoading: false, isLoading: false,
@@ -115,6 +116,7 @@ class UserNotificationsDialog extends React.Component {
return item; return item;
}) })
}); });
this.props.updateTotalUnseenCount('discussion');
}).catch((error) => { }).catch((error) => {
this.setState({ this.setState({
isLoading: false, isLoading: false,
@@ -131,6 +133,7 @@ class UserNotificationsDialog extends React.Component {
this.setState({ this.setState({
items: [] items: []
}); });
this.props.updateTotalUnseenCount('general');
}).catch((error) => { }).catch((error) => {
this.setState({ this.setState({
isLoading: false, isLoading: false,
@@ -142,6 +145,7 @@ class UserNotificationsDialog extends React.Component {
this.setState({ this.setState({
items: [] items: []
}); });
this.props.updateTotalUnseenCount('discussion');
}).catch((error) => { }).catch((error) => {
this.setState({ this.setState({
isLoading: false, isLoading: false,

View File

@@ -12,7 +12,6 @@ from seahub.api2.authentication import TokenAuthentication
from seahub.api2.throttling import UserRateThrottle from seahub.api2.throttling import UserRateThrottle
from seahub.notifications.models import UserNotification from seahub.notifications.models import UserNotification
from seahub.notifications.models import get_cache_key_of_unseen_notifications
from seahub.notifications.utils import update_notice_detail from seahub.notifications.utils import update_notice_detail
from seahub.utils.timeutils import datetime_to_isoformat_timestr from seahub.utils.timeutils import datetime_to_isoformat_timestr
from seahub.api2.utils import api_error from seahub.api2.utils import api_error

View File

@@ -7,13 +7,11 @@ from rest_framework.response import Response
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework import status from rest_framework import status
from django.core.cache import cache
from seahub.api2.authentication import TokenAuthentication from seahub.api2.authentication import TokenAuthentication
from seahub.api2.throttling import UserRateThrottle from seahub.api2.throttling import UserRateThrottle
from seahub.notifications.models import UserNotification from seahub.notifications.models import UserNotification
from seahub.notifications.models import get_cache_key_of_unseen_notifications
from seahub.notifications.utils import update_notice_detail, update_sdoc_notice_detail from seahub.notifications.utils import update_notice_detail, update_sdoc_notice_detail
from seahub.api2.utils import api_error from seahub.api2.utils import api_error
from seahub.seadoc.models import SeadocNotification from seahub.seadoc.models import SeadocNotification
@@ -66,16 +64,8 @@ class NotificationsView(APIView):
notification_list.append(notice) notification_list.append(notice)
cache_key = get_cache_key_of_unseen_notifications(username) unseen_count = UserNotification.objects.filter(to_user=username, seen=False).count()
unseen_count_from_cache = cache.get(cache_key, None) result['unseen_count'] = unseen_count
# for case of count value is `0`
if unseen_count_from_cache is not None:
result['unseen_count'] = unseen_count_from_cache
else:
unseen_count = UserNotification.objects.filter(to_user=username, seen=False).count()
result['unseen_count'] = unseen_count
cache.set(cache_key, unseen_count)
total_count = UserNotification.objects.filter(to_user=username).count() total_count = UserNotification.objects.filter(to_user=username).count()
@@ -98,9 +88,6 @@ class NotificationsView(APIView):
notice.seen = True notice.seen = True
notice.save() notice.save()
cache_key = get_cache_key_of_unseen_notifications(username)
cache.delete(cache_key)
return Response({'success': True}) return Response({'success': True})
def delete(self, request): def delete(self, request):
@@ -113,9 +100,6 @@ class NotificationsView(APIView):
UserNotification.objects.remove_user_notifications(username) UserNotification.objects.remove_user_notifications(username)
cache_key = get_cache_key_of_unseen_notifications(username)
cache.delete(cache_key)
return Response({'success': True}) return Response({'success': True})
@@ -160,9 +144,6 @@ class NotificationView(APIView):
notice.seen = True notice.seen = True
notice.save() notice.save()
cache_key = get_cache_key_of_unseen_notifications(username)
cache.delete(cache_key)
return Response({'success': True}) return Response({'success': True})
@@ -310,10 +291,10 @@ class AllNotificationsView(APIView):
username = request.user.username username = request.user.username
try: try:
per_page = int(request.GET.get('per_page', '')) per_page = int(request.GET.get('per_page', '25'))
page = int(request.GET.get('page', '')) page = int(request.GET.get('page', '1'))
except ValueError: except ValueError:
per_page = 5 per_page = 25
page = 1 page = 1
if page < 1: if page < 1:
@@ -353,16 +334,8 @@ class AllNotificationsView(APIView):
sdoc_notification_list.append(notice) sdoc_notification_list.append(notice)
cache_key = get_cache_key_of_unseen_notifications(username) unseen_count = UserNotification.objects.filter(to_user=username, seen=False).count()
unseen_count_from_cache = cache.get(cache_key, None) result['general']['unseen_count'] = unseen_count
# for case of count value is `0`
if unseen_count_from_cache is not None:
result['general']['unseen_count'] = unseen_count_from_cache
else:
unseen_count = UserNotification.objects.filter(to_user=username, seen=False).count()
result['general']['unseen_count'] = unseen_count
cache.set(cache_key, unseen_count)
sdoc_unseen_count = SeadocNotification.objects.filter(username=username, seen=False).count() sdoc_unseen_count = SeadocNotification.objects.filter(username=username, seen=False).count()
result['discussion']['unseen_count'] = sdoc_unseen_count result['discussion']['unseen_count'] = sdoc_unseen_count
@@ -374,6 +347,7 @@ class AllNotificationsView(APIView):
result['discussion']['notification_list'] = sdoc_notification_list result['discussion']['notification_list'] = sdoc_notification_list
result['general']['count'] = total_count result['general']['count'] = total_count
result['discussion']['count'] = sdoc_total_count result['discussion']['count'] = sdoc_total_count
result['total_unseen_count'] = result['general']['unseen_count'] + result['discussion']['unseen_count']
return Response(result) return Response(result)
@@ -394,7 +368,5 @@ class AllNotificationsView(APIView):
error_msg = 'Internal Server Error' error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
cache_key = get_cache_key_of_unseen_notifications(username)
cache.delete(cache_key)
return Response({'success': True}) return Response({'success': True})

View File

@@ -81,7 +81,6 @@ MSG_TYPE_DELETED_FILES = 'deleted_files'
MSG_TYPE_SAML_SSO_FAILED = 'saml_sso_failed' MSG_TYPE_SAML_SSO_FAILED = 'saml_sso_failed'
MSG_TYPE_FACE_CLUSTER = 'face_cluster' MSG_TYPE_FACE_CLUSTER = 'face_cluster'
USER_NOTIFICATION_COUNT_CACHE_PREFIX = 'USER_NOTIFICATION_COUNT_'
def file_uploaded_msg_to_json(file_name, repo_id, uploaded_to): def file_uploaded_msg_to_json(file_name, repo_id, uploaded_to):
"""Encode file uploaded message to json string. """Encode file uploaded message to json string.
@@ -156,11 +155,6 @@ def saml_sso_error_msg_to_json(error_msg):
return json.dumps({'error_msg': error_msg}) return json.dumps({'error_msg': error_msg})
def get_cache_key_of_unseen_notifications(username):
return normalize_cache_key(username,
USER_NOTIFICATION_COUNT_CACHE_PREFIX)
class UserNotificationManager(models.Manager): class UserNotificationManager(models.Manager):
def _add_user_notification(self, to_user, msg_type, detail): def _add_user_notification(self, to_user, msg_type, detail):
"""Add generic user notification. """Add generic user notification.
@@ -174,9 +168,6 @@ class UserNotificationManager(models.Manager):
to_user=to_user, msg_type=msg_type, detail=detail) to_user=to_user, msg_type=msg_type, detail=detail)
n.save() n.save()
cache_key = get_cache_key_of_unseen_notifications(to_user)
cache.delete(cache_key)
return n return n
def get_all_notifications(self, seen=None, time_since=None): def get_all_notifications(self, seen=None, time_since=None):