mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-26 07:22:34 +00:00
update (#8140)
* update * update * Update utils.py * Update utils.py * add fontend code * Update utils.py * update --------- Co-authored-by: 小强 <shuntian@Mac.lan>
This commit is contained in:
@@ -32,6 +32,12 @@ class CommentPanel extends React.Component {
|
||||
this.toBeAddedParticipant = [];
|
||||
}
|
||||
|
||||
forceUpdate = () => {
|
||||
this.listComments();
|
||||
this.getParticipants();
|
||||
this.listRepoRelatedUsers();
|
||||
};
|
||||
|
||||
listComments = () => {
|
||||
seafileAPI.listComments(repoID, fileUuid).then((res) => {
|
||||
this.setState({
|
||||
|
@@ -22,7 +22,8 @@ const propTypes = {
|
||||
toggleCommentPanel: PropTypes.func.isRequired,
|
||||
toggleDetailsPanel: PropTypes.func.isRequired,
|
||||
setImageScale: PropTypes.func,
|
||||
rotateImage: PropTypes.func
|
||||
rotateImage: PropTypes.func,
|
||||
isCommentUpdated: PropTypes.bool,
|
||||
};
|
||||
|
||||
const {
|
||||
@@ -103,7 +104,7 @@ class FileToolbar extends React.Component {
|
||||
|
||||
const { moreDropdownOpen } = this.state;
|
||||
|
||||
const { isLocked, lockedByMe } = this.props;
|
||||
const { isLocked, lockedByMe, isCommentUpdated } = this.props;
|
||||
let showLockUnlockBtn = false;
|
||||
let lockUnlockText; let lockUnlockIcon;
|
||||
if (canLockUnlockFile) {
|
||||
@@ -214,6 +215,7 @@ class FileToolbar extends React.Component {
|
||||
aria-label={gettext('Comment')}
|
||||
>
|
||||
<i className="sdocfont sdoc-comments"></i>
|
||||
{isCommentUpdated && <span className='comment-tip'></span>}
|
||||
</div>
|
||||
{showShareBtn && (
|
||||
<IconButton
|
||||
|
@@ -15,6 +15,7 @@ import OnlyofficeFileToolbar from './onlyoffice-file-toolbar';
|
||||
import EmbeddedFileDetails from '../dirent-detail/embedded-file-details';
|
||||
import { MetadataMiddlewareProvider, MetadataStatusProvider } from '../../hooks';
|
||||
import Loading from '../loading';
|
||||
import WebSocketClient from '../../utils/websocket-service';
|
||||
|
||||
import '../../css/file-view.css';
|
||||
|
||||
@@ -29,7 +30,7 @@ const propTypes = {
|
||||
};
|
||||
|
||||
const { isStarred, isLocked, lockedByMe,
|
||||
repoID, filePath, filePerm, enableWatermark, userNickName,
|
||||
repoID, fileUuid, filePath, filePerm, enableWatermark, userNickName,
|
||||
fileName, repoEncrypted, isRepoAdmin, fileType
|
||||
} = window.app.pageOptions;
|
||||
|
||||
@@ -44,8 +45,11 @@ class FileView extends React.Component {
|
||||
lockedByMe: lockedByMe,
|
||||
isCommentPanelOpen: false,
|
||||
isHeaderShown: (storedIsHeaderShown === null) || (storedIsHeaderShown == 'true'),
|
||||
isDetailsPanelOpen: false
|
||||
isDetailsPanelOpen: false,
|
||||
isCommentUpdated: false,
|
||||
};
|
||||
|
||||
this.socketManager = new WebSocketClient(this.onMessageCallback, repoID);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@@ -53,10 +57,25 @@ class FileView extends React.Component {
|
||||
document.getElementById('favicon').href = fileIcon;
|
||||
}
|
||||
|
||||
onMessageCallback = (data) => {
|
||||
const { type, content } = data;
|
||||
if (type === 'comment-update') {
|
||||
const { repo_id, file_uuid } = content;
|
||||
if (repoID === repo_id && file_uuid === fileUuid) {
|
||||
if (!this.state.isCommentPanelOpen) {
|
||||
this.setState({ isCommentUpdated: true });
|
||||
} else {
|
||||
this.commentPanelRef.forceUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
toggleCommentPanel = () => {
|
||||
this.setState({
|
||||
isCommentPanelOpen: !this.state.isCommentPanelOpen,
|
||||
isDetailsPanelOpen: false,
|
||||
isCommentUpdated: false,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -121,6 +140,10 @@ class FileView extends React.Component {
|
||||
});
|
||||
};
|
||||
|
||||
setCommentPanelRef = (ref) => {
|
||||
this.commentPanelRef = ref;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { isOnlyofficeFile = false } = this.props;
|
||||
const { isDetailsPanelOpen, isHeaderShown } = this.state;
|
||||
@@ -142,6 +165,7 @@ class FileView extends React.Component {
|
||||
/>
|
||||
{isOnlyofficeFile ?
|
||||
<OnlyofficeFileToolbar
|
||||
isCommentUpdated={this.state.isCommentUpdated}
|
||||
toggleDetailsPanel={this.toggleDetailsPanel}
|
||||
toggleHeader={this.toggleHeader}
|
||||
toggleCommentPanel={this.toggleCommentPanel}
|
||||
@@ -149,6 +173,7 @@ class FileView extends React.Component {
|
||||
<FileToolbar
|
||||
isLocked={this.state.isLocked}
|
||||
lockedByMe={this.state.lockedByMe}
|
||||
isCommentUpdated={this.state.isCommentUpdated}
|
||||
onSave={this.props.onSave}
|
||||
isSaving={this.props.isSaving}
|
||||
needSave={this.props.needSave}
|
||||
@@ -175,6 +200,7 @@ class FileView extends React.Component {
|
||||
{this.props.content}
|
||||
{this.state.isCommentPanelOpen &&
|
||||
<CommentPanel
|
||||
ref={this.setCommentPanelRef}
|
||||
toggleCommentPanel={this.toggleCommentPanel}
|
||||
participants={this.props.participants}
|
||||
onParticipantsChange={this.props.onParticipantsChange}
|
||||
|
@@ -7,8 +7,9 @@ import Icon from '../../components/icon';
|
||||
import IconButton from '../icon-button';
|
||||
|
||||
const propTypes = {
|
||||
isCommentUpdated: PropTypes.bool,
|
||||
toggleDetailsPanel: PropTypes.func.isRequired,
|
||||
toggleHeader: PropTypes.func.isRequired
|
||||
toggleHeader: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
const {
|
||||
@@ -38,6 +39,7 @@ class OnlyofficeFileToolbar extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { isCommentUpdated } = this.props;
|
||||
const { moreDropdownOpen } = this.state;
|
||||
return (
|
||||
<Fragment>
|
||||
@@ -54,6 +56,7 @@ class OnlyofficeFileToolbar extends React.Component {
|
||||
aria-label={gettext('Comment')}
|
||||
>
|
||||
<i className="sdocfont sdoc-comments"></i>
|
||||
{isCommentUpdated && <span className='comment-tip'></span>}
|
||||
</div>
|
||||
<Dropdown isOpen={moreDropdownOpen} toggle={this.toggleMoreOpMenu}>
|
||||
<DropdownToggle
|
||||
|
@@ -43,6 +43,7 @@ body {
|
||||
}
|
||||
|
||||
.file-view-header .file-toolbar-btn {
|
||||
position: relative;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
margin-left: 10px;
|
||||
@@ -78,6 +79,17 @@ body {
|
||||
color: #ED7109;
|
||||
}
|
||||
|
||||
.file-view-header .file-toolbar-btn .comment-tip {
|
||||
position: absolute;
|
||||
left: 4px;
|
||||
top: 4px;
|
||||
border-radius: 50%;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
z-index: 100;
|
||||
background: red;
|
||||
}
|
||||
|
||||
.file-view-header .file-toolbar-more-operations {
|
||||
height: 38px;
|
||||
padding: 0;
|
||||
@@ -140,6 +152,7 @@ body {
|
||||
right: -500px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
to {
|
||||
right: 0px;
|
||||
opacity: 1;
|
||||
|
@@ -14,7 +14,7 @@ from django.utils import timezone
|
||||
from seahub.api2.authentication import TokenAuthentication
|
||||
from seahub.api2.permissions import IsRepoAccessible
|
||||
from seahub.api2.throttling import UserRateThrottle
|
||||
from seahub.api2.utils import api_error, user_to_dict, to_python_boolean
|
||||
from seahub.api2.utils import api_error, user_to_dict, to_python_boolean, send_comment_update_event
|
||||
from seahub.avatar.settings import AVATAR_DEFAULT_SIZE
|
||||
from seahub.base.models import FileComment
|
||||
from seahub.utils.repo import get_repo_owner
|
||||
@@ -132,6 +132,7 @@ class FileCommentsView(APIView):
|
||||
notification = detail
|
||||
notification['to_users'] = to_users
|
||||
comment['notification'] = notification
|
||||
send_comment_update_event(file_uuid)
|
||||
return Response(comment)
|
||||
|
||||
|
||||
@@ -166,6 +167,7 @@ class FileCommentView(APIView):
|
||||
|
||||
file_comment.delete()
|
||||
SeadocCommentReply.objects.filter(comment_id=comment_id).delete()
|
||||
send_comment_update_event(file_uuid)
|
||||
return Response({'success': True})
|
||||
|
||||
def put(self, request, repo_id, file_uuid, comment_id):
|
||||
@@ -204,6 +206,7 @@ class FileCommentView(APIView):
|
||||
|
||||
comment = file_comment.to_dict()
|
||||
comment.update(user_to_dict(file_comment.author, request=request))
|
||||
send_comment_update_event(file_uuid)
|
||||
return Response(comment)
|
||||
|
||||
|
||||
@@ -313,6 +316,7 @@ class FileCommentRepliesView(APIView):
|
||||
notification = detail
|
||||
notification['to_users'] = to_users
|
||||
data['notification'] = notification
|
||||
send_comment_update_event(file_uuid)
|
||||
return Response(data)
|
||||
|
||||
|
||||
@@ -353,6 +357,7 @@ class FileCommentReplyView(APIView):
|
||||
if not reply:
|
||||
return api_error(status.HTTP_404_NOT_FOUND, 'reply not found.')
|
||||
reply.delete()
|
||||
send_comment_update_event(file_uuid)
|
||||
return Response({'success': True})
|
||||
|
||||
def put(self, request, repo_id, file_uuid, comment_id, reply_id):
|
||||
@@ -380,4 +385,5 @@ class FileCommentReplyView(APIView):
|
||||
data = reply.to_dict()
|
||||
data.update(
|
||||
user_to_dict(reply.author, request=request))
|
||||
send_comment_update_event(file_uuid)
|
||||
return Response(data)
|
||||
|
@@ -8,7 +8,7 @@ import json
|
||||
import re
|
||||
import logging
|
||||
import jwt
|
||||
|
||||
import requests
|
||||
from collections import defaultdict
|
||||
from functools import wraps
|
||||
from django.core.cache import cache
|
||||
@@ -34,9 +34,11 @@ from seahub.utils import get_user_repos
|
||||
from seahub.utils.mail import send_html_email_with_dj_template
|
||||
from django.utils.translation import gettext as _
|
||||
import seahub.settings as settings
|
||||
from seahub.tags.models import FileUUIDMap
|
||||
|
||||
JWT_PRIVATE_KEY = getattr(settings, 'JWT_PRIVATE_KEY', '')
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def api_error(code, msg):
|
||||
@@ -361,3 +363,37 @@ def is_valid_internal_jwt(auth):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def send_comment_update_event(file_uuid):
|
||||
if not settings.ENABLE_NOTIFICATION_SERVER:
|
||||
return
|
||||
|
||||
uuid_map = FileUUIDMap.objects.get_fileuuidmap_by_uuid(file_uuid)
|
||||
if not uuid_map:
|
||||
return
|
||||
repo_id = uuid_map.repo_id
|
||||
event_data = {
|
||||
"type": "comment-update",
|
||||
"content": {
|
||||
"repo_id": repo_id,
|
||||
"type": "comment_updated",
|
||||
"file_uuid": file_uuid,
|
||||
"file_path": ""
|
||||
}
|
||||
}
|
||||
notification_server_event_url = "%s/events" % settings.INNER_NOTIFICATION_SERVER_URL.rstrip('/')
|
||||
payload = {
|
||||
'exp': int(time.time()) + 500
|
||||
}
|
||||
jwt_token = jwt.encode(payload, JWT_PRIVATE_KEY, algorithm='HS256')
|
||||
headers = {
|
||||
'Authorization': 'Token %s' % jwt_token,
|
||||
|
||||
}
|
||||
try:
|
||||
resp = requests.post(notification_server_event_url, json=event_data, headers=headers)
|
||||
if not resp.ok:
|
||||
logger.error(f'Send comment update event failed: {resp.content}')
|
||||
except Exception as e:
|
||||
logger.error(f'Send comment update event error. ERROR: {e}')
|
||||
|
@@ -982,6 +982,7 @@ ENABLE_WHITEBOARD = False
|
||||
|
||||
ENABLE_NOTIFICATION_SERVER = os.environ.get('ENABLE_NOTIFICATION_SERVER', 'false') == 'true'
|
||||
NOTIFICATION_SERVER_URL = os.environ.get('NOTIFICATION_SERVER_URL', '')
|
||||
INNER_NOTIFICATION_SERVER_URL = os.environ.get('INNER_NOTIFICATION_SERVER_URL', 'http://127.0.0.1:8083' )
|
||||
|
||||
############################
|
||||
# Settings for Seahub Priv #
|
||||
|
Reference in New Issue
Block a user