mirror of
https://github.com/haiwen/seahub.git
synced 2025-08-19 15:38:38 +00:00
Update notifications.py
This commit is contained in:
parent
175803baba
commit
27dcce694b
@ -24,6 +24,8 @@ const MSG_TYPE_SAML_SSO_FAILED = 'saml_sso_failed';
|
|||||||
const MSG_TYPE_REPO_SHARE_PERM_CHANGE = 'repo_share_perm_change';
|
const MSG_TYPE_REPO_SHARE_PERM_CHANGE = 'repo_share_perm_change';
|
||||||
const MSG_TYPE_REPO_SHARE_PERM_DELETE = 'repo_share_perm_delete';
|
const MSG_TYPE_REPO_SHARE_PERM_DELETE = 'repo_share_perm_delete';
|
||||||
const MSG_TYPE_FACE_CLUSTER = 'face_cluster';
|
const MSG_TYPE_FACE_CLUSTER = 'face_cluster';
|
||||||
|
const MSG_TYPE_SEADOC_REPLY = 'reply';
|
||||||
|
const MSG_TYPE_SEADOC_COMMENT = 'comment';
|
||||||
|
|
||||||
dayjs.extend(relativeTime);
|
dayjs.extend(relativeTime);
|
||||||
|
|
||||||
@ -33,7 +35,7 @@ class NoticeItem extends React.Component {
|
|||||||
let noticeItem = this.props.noticeItem;
|
let noticeItem = this.props.noticeItem;
|
||||||
let noticeType = noticeItem.type;
|
let noticeType = noticeItem.type;
|
||||||
let detail = noticeItem.detail;
|
let detail = noticeItem.detail;
|
||||||
|
console.log(detail, noticeItem, noticeType)
|
||||||
if (noticeType === MSG_TYPE_ADD_USER_TO_GROUP) {
|
if (noticeType === MSG_TYPE_ADD_USER_TO_GROUP) {
|
||||||
|
|
||||||
let avatar_url = detail.group_staff_avatar_url;
|
let avatar_url = detail.group_staff_avatar_url;
|
||||||
@ -375,6 +377,22 @@ class NoticeItem extends React.Component {
|
|||||||
return { avatar_url: null, notice };
|
return { avatar_url: null, notice };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (noticeType === MSG_TYPE_SEADOC_COMMENT) {
|
||||||
|
let avatar_url = detail.share_from_user_avatar_url;
|
||||||
|
let notice = '';
|
||||||
|
console.log(111)
|
||||||
|
notice = Utils.HTMLescape(notice);
|
||||||
|
return { avatar_url, notice };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noticeType === MSG_TYPE_SEADOC_REPLY) {
|
||||||
|
let avatar_url = detail.share_from_user_avatar_url;
|
||||||
|
let notice = detail.reply;
|
||||||
|
notice = Utils.HTMLescape(notice);
|
||||||
|
console.log(notice)
|
||||||
|
return { avatar_url, notice };
|
||||||
|
}
|
||||||
|
|
||||||
// if (noticeType === MSG_TYPE_GUEST_INVITATION_ACCEPTED) {
|
// if (noticeType === MSG_TYPE_GUEST_INVITATION_ACCEPTED) {
|
||||||
|
|
||||||
// }
|
// }
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
.notification-container {
|
.notification-container {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
width: 320px;
|
width: 400px;
|
||||||
right: -16px;
|
right: -16px;
|
||||||
top: -1px;
|
top: -1px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
@ -65,21 +65,15 @@
|
|||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification-container .notification-body .mark-notifications {
|
.notification-container .mark-all-read {
|
||||||
color: #b4b4b4;
|
color: #b4b4b4;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-bottom: 1px solid #ededed;
|
|
||||||
height: 36px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
padding-right: 1rem;
|
padding-right: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification-container .notification-body .mark-notifications:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification-body .notification-list-container {
|
.notification-body .notification-list-container {
|
||||||
max-height: 260px;
|
max-height: 260px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
@ -190,3 +184,22 @@
|
|||||||
.notification-body .notification-footer:hover {
|
.notification-body .notification-footer:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.notification-container .notification-body .mark-notifications {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-container .notification-body .mark-notifications .mark-all-read:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-container .notification-body .nav .nav-item .nav-link {
|
||||||
|
height: 46px;
|
||||||
|
margin-right: 15px;
|
||||||
|
margin-left: 15px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-container .notification-body .nav .nav-item .nav-link.active {
|
||||||
|
color: #ED7109 !important;
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Popover } from 'reactstrap';
|
import { Popover } from 'reactstrap';
|
||||||
|
import { gettext } from '../../../utils/constants';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
export default class NotificationPopover extends React.Component {
|
export default class NotificationPopover extends React.Component {
|
||||||
@ -13,7 +15,9 @@ export default class NotificationPopover extends React.Component {
|
|||||||
onNotificationDialogToggle: PropTypes.func,
|
onNotificationDialogToggle: PropTypes.func,
|
||||||
listNotifications: PropTypes.func,
|
listNotifications: PropTypes.func,
|
||||||
onMarkAllNotifications: PropTypes.func,
|
onMarkAllNotifications: PropTypes.func,
|
||||||
|
tabItemClick: PropTypes.func,
|
||||||
children: PropTypes.any,
|
children: PropTypes.any,
|
||||||
|
currentTab: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
@ -47,8 +51,12 @@ export default class NotificationPopover extends React.Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
tabItemClick = (tab) => {
|
||||||
|
this.props.tabItemClick(tab);
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { headerText, bodyText, footerText } = this.props;
|
const { headerText, bodyText, footerText, currentTab } = this.props;
|
||||||
return (
|
return (
|
||||||
<Popover
|
<Popover
|
||||||
className="notification-wrapper"
|
className="notification-wrapper"
|
||||||
@ -64,12 +72,55 @@ export default class NotificationPopover extends React.Component {
|
|||||||
<span className="sf3-font sf3-font-x-01 notification-close-icon" onClick={this.props.onNotificationListToggle}></span>
|
<span className="sf3-font sf3-font-x-01 notification-close-icon" onClick={this.props.onNotificationListToggle}></span>
|
||||||
</div>
|
</div>
|
||||||
<div className="notification-body">
|
<div className="notification-body">
|
||||||
<div className="mark-notifications" onClick={this.props.onMarkAllNotifications}>{bodyText}</div>
|
<div className="mark-notifications">
|
||||||
|
<ul className="nav">
|
||||||
|
<li className="nav-item" onClick={() => this.tabItemClick('general')}>
|
||||||
|
<span className={`nav-link ${currentTab === 'general' ? 'active' : ''}`}>
|
||||||
|
{gettext('General')}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li className="nav-item" onClick={() => this.tabItemClick('discussion')}>
|
||||||
|
<span className={`nav-link ${currentTab === 'discussion' ? 'active' : ''}`}>
|
||||||
|
{gettext('Discussion')}
|
||||||
|
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<span className="mark-all-read" onClick={this.onMarkAllNotifications}>
|
||||||
|
{gettext('Mark all as read')}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{currentTab === 'general' &&
|
||||||
<div className="notification-list-container" onScroll={this.onHandleScroll} ref={ref => this.notificationListRef = ref}>
|
<div className="notification-list-container" onScroll={this.onHandleScroll} ref={ref => this.notificationListRef = ref}>
|
||||||
<div ref={ref => this.notificationsWrapperRef = ref}>
|
<div ref={ref => this.notificationsWrapperRef = ref}>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
|
{currentTab === 'discussion' &&
|
||||||
|
<div className="notification-list-container" onScroll={this.onHandleScroll} ref={ref => this.notificationListRef = ref}>
|
||||||
|
<div ref={ref => this.notificationsWrapperRef = ref}>
|
||||||
|
{this.props.children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
{/* <div className="mark-notifications" onClick={this.props.onMarkAllNotifications}>
|
||||||
|
<ul className="nav dtable-external-links-tab">
|
||||||
|
<li className="nav-item">
|
||||||
|
<span className="nav-link">General</span>
|
||||||
|
</li>
|
||||||
|
<li className="nav-item">
|
||||||
|
<span className="nav-link">Discussion</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<span className="mark-all-read">{bodyText}</span>
|
||||||
|
</div>
|
||||||
|
<div className="notification-list-container" onScroll={this.onHandleScroll} ref={ref => this.notificationListRef = ref}>
|
||||||
|
<div ref={ref => this.notificationsWrapperRef = ref}>
|
||||||
|
{this.props.children}
|
||||||
|
</div>
|
||||||
|
</div> */}
|
||||||
<div className="notification-footer" onClick={this.onNotificationDialogToggle}>{footerText}</div>
|
<div className="notification-footer" onClick={this.onNotificationDialogToggle}>{footerText}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,6 +14,7 @@ class Notification extends React.Component {
|
|||||||
showNotice: false,
|
showNotice: false,
|
||||||
unseenCount: 0,
|
unseenCount: 0,
|
||||||
noticeList: [],
|
noticeList: [],
|
||||||
|
currentTab: 'general',
|
||||||
isShowNotificationDialog: this.getInitDialogState(),
|
isShowNotificationDialog: this.getInitDialogState(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -38,13 +39,34 @@ class Notification extends React.Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
tabItemClick = (tab) => {
|
||||||
|
const { currentTab } = this.state;
|
||||||
|
if (currentTab === tab) return;
|
||||||
|
this.setState({
|
||||||
|
showNotice: true,
|
||||||
|
currentTab: tab
|
||||||
|
}, () => {
|
||||||
|
this.loadNotices();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
loadNotices = () => {
|
loadNotices = () => {
|
||||||
let page = 1;
|
let page = 1;
|
||||||
let perPage = 5;
|
let perPage = 5;
|
||||||
seafileAPI.listNotifications(page, perPage).then(res => {
|
if (this.state.currentTab === 'general') {
|
||||||
let noticeList = res.data.notification_list;
|
seafileAPI.listNotifications(page, perPage).then(res => {
|
||||||
this.setState({ noticeList: noticeList });
|
let noticeList = res.data.notification_list;
|
||||||
});
|
this.setState({ noticeList: noticeList });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.state.currentTab === 'discussion') {
|
||||||
|
seafileAPI.listSdocNotifications(page, perPage).then(res => {
|
||||||
|
let noticeList = res.data.notification_list;
|
||||||
|
console.log(noticeList)
|
||||||
|
this.setState({ noticeList: noticeList });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
onNoticeItemClick = (noticeItem) => {
|
onNoticeItemClick = (noticeItem) => {
|
||||||
@ -91,7 +113,7 @@ class Notification extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { unseenCount } = this.state;
|
const { unseenCount, currentTab } = this.state;
|
||||||
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')}>
|
||||||
@ -103,9 +125,11 @@ class Notification extends React.Component {
|
|||||||
headerText={gettext('Notification')}
|
headerText={gettext('Notification')}
|
||||||
bodyText={gettext('Mark all as read')}
|
bodyText={gettext('Mark all as read')}
|
||||||
footerText={gettext('View all notifications')}
|
footerText={gettext('View all notifications')}
|
||||||
|
currentTab={currentTab}
|
||||||
onNotificationListToggle={this.onNotificationListToggle}
|
onNotificationListToggle={this.onNotificationListToggle}
|
||||||
onNotificationDialogToggle={this.onNotificationDialogToggle}
|
onNotificationDialogToggle={this.onNotificationDialogToggle}
|
||||||
onMarkAllNotifications={this.onMarkAllNotifications}
|
onMarkAllNotifications={this.onMarkAllNotifications}
|
||||||
|
tabItemClick={this.tabItemClick}
|
||||||
>
|
>
|
||||||
<ul className="notice-list list-unstyled" id="notice-popover">
|
<ul className="notice-list list-unstyled" id="notice-popover">
|
||||||
{this.state.noticeList.map(item => {
|
{this.state.noticeList.map(item => {
|
||||||
|
@ -1460,6 +1460,16 @@ class SeafileAPI {
|
|||||||
return this.req.get(url, { params: params });
|
return this.req.get(url, { params: params });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
listSdocNotifications(page, perPage) {
|
||||||
|
const url = this.server + '/api/v2.1/sdoc-notifications/';
|
||||||
|
let params = {
|
||||||
|
page: page,
|
||||||
|
per_page: perPage
|
||||||
|
};
|
||||||
|
return this.req.get(url, { params: params });
|
||||||
|
}
|
||||||
|
|
||||||
updateNotifications() {
|
updateNotifications() {
|
||||||
const url = this.server + '/api/v2.1/notifications/';
|
const url = this.server + '/api/v2.1/notifications/';
|
||||||
return this.req.put(url);
|
return this.req.put(url);
|
||||||
|
@ -14,13 +14,16 @@ 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.models import get_cache_key_of_unseen_notifications
|
||||||
from seahub.notifications.utils import update_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 SeadocCommentReply, SeadocNotification
|
||||||
from seahub.utils.timeutils import datetime_to_isoformat_timestr
|
from seahub.utils.timeutils import datetime_to_isoformat_timestr
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
json_content_type = 'application/json; charset=utf-8'
|
json_content_type = 'application/json; charset=utf-8'
|
||||||
|
|
||||||
|
NOTIF_TYPE = ['general', 'discussion']
|
||||||
|
|
||||||
|
|
||||||
class NotificationsView(APIView):
|
class NotificationsView(APIView):
|
||||||
|
|
||||||
@ -161,3 +164,61 @@ class NotificationView(APIView):
|
|||||||
cache.delete(cache_key)
|
cache.delete(cache_key)
|
||||||
|
|
||||||
return Response({'success': True})
|
return Response({'success': True})
|
||||||
|
|
||||||
|
|
||||||
|
class SdocNotificationView(APIView):
|
||||||
|
def get(self, request):
|
||||||
|
""" used for get sdoc notifications
|
||||||
|
|
||||||
|
Permission checking:
|
||||||
|
1. login user.
|
||||||
|
"""
|
||||||
|
notice_type = request.GET.get('type', 'general')
|
||||||
|
if notice_type not in NOTIF_TYPE:
|
||||||
|
error_msg = 'notice_type invalid.'
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
username = request.user.username
|
||||||
|
|
||||||
|
try:
|
||||||
|
per_page = int(request.GET.get('per_page', ''))
|
||||||
|
page = int(request.GET.get('page', ''))
|
||||||
|
except ValueError:
|
||||||
|
per_page = 25
|
||||||
|
page = 1
|
||||||
|
|
||||||
|
start = (page - 1) * per_page
|
||||||
|
end = page * per_page
|
||||||
|
|
||||||
|
notice_list = SeadocNotification.objects.list_all_by_user(username, start, end)
|
||||||
|
result_notices = update_sdoc_notice_detail(request, notice_list)
|
||||||
|
notification_list = []
|
||||||
|
for i in result_notices:
|
||||||
|
if i.detail is not None:
|
||||||
|
notice = {}
|
||||||
|
notice['id'] = i.id
|
||||||
|
notice['type'] = i.msg_type
|
||||||
|
notice['detail'] = i.detail
|
||||||
|
notice['time'] = datetime_to_isoformat_timestr(i.created_at)
|
||||||
|
notice['seen'] = i.seen
|
||||||
|
|
||||||
|
notification_list.append(notice)
|
||||||
|
cache_key = get_cache_key_of_unseen_notifications(username)
|
||||||
|
unseen_count_from_cache = cache.get(cache_key, None)
|
||||||
|
|
||||||
|
# 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 = SeadocNotification.objects.filter(username=username, seen=False).count()
|
||||||
|
result['unseen_count'] = unseen_count
|
||||||
|
cache.set(cache_key, unseen_count)
|
||||||
|
|
||||||
|
total_count = SeadocNotification.objects.filter(username=username).count()
|
||||||
|
|
||||||
|
result['notification_list'] = notification_list
|
||||||
|
result['count'] = total_count
|
||||||
|
|
||||||
|
return Response(result)
|
||||||
|
@ -402,6 +402,24 @@ def update_notice_detail(request, notices):
|
|||||||
return notices
|
return notices
|
||||||
|
|
||||||
|
|
||||||
|
def update_sdoc_notice_detail(request, notices):
|
||||||
|
repo_dict = {}
|
||||||
|
for notice in notices:
|
||||||
|
if notice.is_comment():
|
||||||
|
try:
|
||||||
|
d = json.loads(notice.detail)
|
||||||
|
notice.detail = d
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
elif notice.is_reply():
|
||||||
|
try:
|
||||||
|
d = json.loads(notice.detail)
|
||||||
|
notice.detail = d
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
return notices
|
||||||
|
|
||||||
|
|
||||||
def gen_sdoc_smart_link(doc_uuid, with_service_url=True):
|
def gen_sdoc_smart_link(doc_uuid, with_service_url=True):
|
||||||
service_url = get_service_url()
|
service_url = get_service_url()
|
||||||
service_url = service_url.rstrip('/')
|
service_url = service_url.rstrip('/')
|
||||||
|
@ -247,6 +247,11 @@ class SeadocCommentReply(models.Model):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### sdoc notification
|
||||||
|
MSG_TYPE_REPLY = 'reply'
|
||||||
|
MSG_TYPE_COMMENT = 'comment'
|
||||||
|
|
||||||
class SeadocNotificationManager(models.Manager):
|
class SeadocNotificationManager(models.Manager):
|
||||||
def total_count(self, doc_uuid, username):
|
def total_count(self, doc_uuid, username):
|
||||||
return self.filter(doc_uuid=doc_uuid, username=username).count()
|
return self.filter(doc_uuid=doc_uuid, username=username).count()
|
||||||
@ -260,6 +265,9 @@ class SeadocNotificationManager(models.Manager):
|
|||||||
def delete_by_ids(self, doc_uuid, username, ids):
|
def delete_by_ids(self, doc_uuid, username, ids):
|
||||||
return self.filter(doc_uuid=doc_uuid, username=username, id__in=ids).delete()
|
return self.filter(doc_uuid=doc_uuid, username=username, id__in=ids).delete()
|
||||||
|
|
||||||
|
def list_all_by_user(self, username, start, end):
|
||||||
|
return self.filter(username=username).order_by('-created_at')[start: end]
|
||||||
|
|
||||||
|
|
||||||
class SeadocNotification(models.Model):
|
class SeadocNotification(models.Model):
|
||||||
doc_uuid = models.CharField(max_length=36)
|
doc_uuid = models.CharField(max_length=36)
|
||||||
@ -285,3 +293,9 @@ class SeadocNotification(models.Model):
|
|||||||
'detail': json.loads(self.detail),
|
'detail': json.loads(self.detail),
|
||||||
'seen': self.seen,
|
'seen': self.seen,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def is_comment(self):
|
||||||
|
return self.msg_type == MSG_TYPE_COMMENT
|
||||||
|
|
||||||
|
def is_reply(self):
|
||||||
|
return self.msg_type == MSG_TYPE_REPLY
|
||||||
|
@ -91,7 +91,7 @@ from seahub.api2.endpoints.invitations import InvitationsView, InvitationsBatchV
|
|||||||
from seahub.api2.endpoints.invitation import InvitationView, InvitationRevokeView
|
from seahub.api2.endpoints.invitation import InvitationView, InvitationRevokeView
|
||||||
from seahub.api2.endpoints.repo_share_invitations import RepoShareInvitationsView, RepoShareInvitationsBatchView
|
from seahub.api2.endpoints.repo_share_invitations import RepoShareInvitationsView, RepoShareInvitationsBatchView
|
||||||
from seahub.api2.endpoints.repo_share_invitation import RepoShareInvitationView
|
from seahub.api2.endpoints.repo_share_invitation import RepoShareInvitationView
|
||||||
from seahub.api2.endpoints.notifications import NotificationsView, NotificationView
|
from seahub.api2.endpoints.notifications import NotificationsView, NotificationView, SdocNotificationView
|
||||||
from seahub.api2.endpoints.repo_file_uploaded_bytes import RepoFileUploadedBytesView
|
from seahub.api2.endpoints.repo_file_uploaded_bytes import RepoFileUploadedBytesView
|
||||||
from seahub.api2.endpoints.user_avatar import UserAvatarView
|
from seahub.api2.endpoints.user_avatar import UserAvatarView
|
||||||
from seahub.api2.endpoints.wikis import WikisView, WikiView
|
from seahub.api2.endpoints.wikis import WikisView, WikiView
|
||||||
@ -522,6 +522,7 @@ urlpatterns = [
|
|||||||
|
|
||||||
re_path(r'^api/v2.1/notifications/$', NotificationsView.as_view(), name='api-v2.1-notifications'),
|
re_path(r'^api/v2.1/notifications/$', NotificationsView.as_view(), name='api-v2.1-notifications'),
|
||||||
re_path(r'^api/v2.1/notification/$', NotificationView.as_view(), name='api-v2.1-notification'),
|
re_path(r'^api/v2.1/notification/$', NotificationView.as_view(), name='api-v2.1-notification'),
|
||||||
|
re_path(r'^api/v2.1/sdoc-notifications/$', SdocNotificationView.as_view(), name='api-v2.1-sdoc-notifications'),
|
||||||
|
|
||||||
## user::invitations
|
## user::invitations
|
||||||
re_path(r'^api/v2.1/invitations/$', InvitationsView.as_view()),
|
re_path(r'^api/v2.1/invitations/$', InvitationsView.as_view()),
|
||||||
|
Loading…
Reference in New Issue
Block a user