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:
@@ -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>
|
||||||
|
@@ -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,
|
||||||
|
@@ -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
|
||||||
|
@@ -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})
|
||||||
|
@@ -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):
|
||||||
|
Reference in New Issue
Block a user