Skip to content

Commit

Permalink
UI design
Browse files Browse the repository at this point in the history
  • Loading branch information
孙永强 committed Apr 30, 2024
1 parent f63b90d commit 470f091
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 26 deletions.
112 changes: 112 additions & 0 deletions frontend/src/components/dialog/group-invite-members-dialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button, Modal, ModalHeader, ModalBody } from 'reactstrap';
import copy from 'copy-to-clipboard';
import toaster from '../toast';
import { gettext } from '../../utils/constants';
import { seafileAPI } from '../../utils/seafile-api';
import { Utils } from '../../utils/utils';

import '../../css/group-invite-members-dialog.css';

const propTypes = {
groupID: PropTypes.string.isRequired,
toggleGroupInviteDialog: PropTypes.func.isRequired,
};

class GroupInviteMembersDialog extends React.Component {

constructor(props) {
super(props);
this.state = {
inviteList: [],
};
}

componentDidMount() {
this.listInviteLinks();
}

listInviteLinks = () => {
seafileAPI.getGroupInviteLinks(this.props.groupID).then((res) => {
this.setState({ inviteList: res.data.group_invite_link_list });
}).catch(error => {
this.onError(error);
});
};

addInviteLink = () => {
seafileAPI.addGroupInviteLinks(this.props.groupID).then(() => {
this.listInviteLinks();
}).catch(error => {
this.onError(error);
});
};

deleteLink = (token) => {
seafileAPI.deleteGroupInviteLinks(this.props.groupID, token).then(() => {
this.listInviteLinks();
}).catch(error => {
this.onError(error);
});
};

onError = (error) => {
let errMsg = Utils.getErrorMsg(error, true);
if (!error.response || error.response.status !== 403) {
toaster.danger(errMsg);
}
};

copyLink = () => {
const inviteLinkItem = this.state.inviteList[0];
copy(inviteLinkItem.link);
const message = gettext('Invitation link has been copied to clipboard');
toaster.success((message), {
duration: 2
});
};

toggle = () => {
this.props.toggleGroupInviteDialog();
};

render() {
const { inviteList } = this.state;
const link = inviteList[0];
return (
<Modal isOpen={true} toggle={this.toggle} className="group-invite-members">
<ModalHeader toggle={this.toggle}>{gettext('Invite members')}</ModalHeader>
<ModalBody>
{link ?
<>
<div>
<strong>{gettext('Group invitation link')}</strong>
</div>
<div className="invite-link-item">
<div className="form-item text-truncate">{link.link}</div>
<div className="invite-link-copy">
<Button color="primary" onClick={this.copyLink} className="invite-link-copy-btn text-truncate">{gettext('Copy')}</Button>
</div>
<Button color="secondary" onClick={this.deleteLink.bind(this, link.token)} className="delete-link-btn ml-2">
<i className="sf2-icon-delete"></i>
</Button>
</div>
</>
:
<>
<div className="no-link-tip mb-4">
{gettext('No group invitation link yet. Group invitation link let registered users to join the group by clicking a link.')}
</div>
<Button color="primary" onClick={this.addInviteLink} className="my-4">{gettext('Generate')}</Button>
</>
}
</ModalBody>
</Modal>
);
}
}

GroupInviteMembersDialog.propTypes = propTypes;

export default GroupInviteMembersDialog;
40 changes: 40 additions & 0 deletions frontend/src/css/group-invite-members-dialog.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
.group-invite-members th,
.group-invite-members td {
vertical-align: middle;
text-align: left;
}

.group-invite-members .no-link-tip {
line-height: 24px;
color: #999;
}

.invite-link-item {
display: flex;
margin: 1rem 0 2.5rem;
}

.invite-link-item .form-item {
width: calc(100% - 120px);
padding-left: 10px;
height: 40px;
line-height: 40px;
border: 1px solid #ccc;
border-right: none;
}

.invite-link-item .invite-link-copy {
width: 72px;
}

.invite-link-item .invite-link-copy-btn {
width: 72px;
height: 40px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}

.invite-link-item .delete-link-btn {
color: #999;
width: 40px;
}
17 changes: 17 additions & 0 deletions frontend/src/pages/groups/group-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import LeaveGroupDialog from '../../components/dialog/leave-group-dialog';
import SharedRepoListView from '../../components/shared-repo-list-view/shared-repo-list-view';
import LibDetail from '../../components/dirent-detail/lib-details';
import SortOptionsDialog from '../../components/dialog/sort-options';
import GroupInviteMembersDialog from '../../components/dialog/group-invite-members-dialog';

import '../../css/group-view.css';

Expand Down Expand Up @@ -64,6 +65,7 @@ class GroupView extends React.Component {
showTransferGroupDialog: false,
showImportMembersDialog: false,
showManageMembersDialog: false,
showInviteMembersDialog: false,
groupMembers: [],
isShowDetails: false,
isLeaveGroupDialogOpen: false,
Expand All @@ -75,6 +77,7 @@ class GroupView extends React.Component {
this.loadGroup(groupID);
}


UNSAFE_componentWillReceiveProps(nextProps) {
if (nextProps.groupID !== this.props.groupID) {
this.loadGroup(nextProps.groupID);
Expand Down Expand Up @@ -318,6 +321,13 @@ class GroupView extends React.Component {
});
};

toggleInviteMembersDialog = () => {
this.setState({
showInviteMembersDialog: !this.state.showInviteMembersDialog,
showGroupDropdown: false,
});
};

toggleLeaveGroupDialog = () => {
this.setState({
isLeaveGroupDialogOpen: !this.state.isLeaveGroupDialogOpen,
Expand Down Expand Up @@ -493,6 +503,7 @@ class GroupView extends React.Component {
<ul className="sf-popover-list">
<li><a href="#" className="sf-popover-item" onClick={this.toggleImportMembersDialog} >{gettext('Import Members')}</a></li>
<li><a href="#" className="sf-popover-item" onClick={this.toggleManageMembersDialog} >{gettext('Manage Members')}</a></li>
<li><a href="#" className="sf-popover-item" onClick={this.toggleInviteMembersDialog} >{gettext('Invite Members')}</a></li>
</ul>
}
{
Expand Down Expand Up @@ -645,6 +656,12 @@ class GroupView extends React.Component {
onGroupChanged={this.props.onGroupChanged}
/>
}
{this.state.showInviteMembersDialog &&
<GroupInviteMembersDialog
groupID={this.props.groupID}
onGroupChanged={this.props.onGroupChanged}
toggleGroupInviteDialog={this.toggleInviteMembersDialog}/>
}
</Fragment>
);
}
Expand Down
70 changes: 45 additions & 25 deletions seahub/api2/endpoints/group_members.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from seahub.api2.authentication import TokenAuthentication
from seahub.avatar.settings import AVATAR_DEFAULT_SIZE
from seahub.base.templatetags.seahub_tags import email2nickname
from seahub.utils import string2list, is_org_context, get_file_type_and_ext
from seahub.utils import string2list, is_org_context, get_file_type_and_ext, render_error
from seahub.utils.ms_excel import write_xls
from seahub.utils.error_msg import file_type_error_msg
from seahub.base.accounts import User
Expand All @@ -31,7 +31,7 @@
from seahub.profile.models import Profile, GroupInviteLinkModel
from .utils import api_check_group

from seahub.settings import SERVICE_URL
from seahub.settings import SERVICE_URL, MULTI_TENANCY
from seahub.auth.decorators import login_required
logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -575,6 +575,10 @@ def get(self, request, group_id):
email = request.user.username

group = ccnet_api.get_group(group_id)
if MULTI_TENANCY:
error_msg = ' Multiple tenancy is not supported.'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

if not group:
error_msg = 'group not found.'
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
Expand All @@ -598,6 +602,10 @@ def post(self, request, group_id):
email = request.user.username

group = ccnet_api.get_group(group_id)
if MULTI_TENANCY:
error_msg = ' Multiple tenancy is not supported.'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

if not group:
error_msg = 'group not found.'
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
Expand All @@ -615,49 +623,61 @@ def post(self, request, group_id):
return Response(invite_link.to_dict())


class GroupInviteLink(APIView):
authentication_classes = (TokenAuthentication, SessionAuthentication)
permission_classes = (IsAuthenticated,)
throttle_classes = (UserRateThrottle,)

@api_check_group
def delete(self, request, group_id, token):
group_id = int(group_id)
email = request.user.username

group = ccnet_api.get_group(group_id)
if MULTI_TENANCY:
error_msg = ' Multiple tenancy is not supported.'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

if not group:
error_msg = 'group not found.'
return api_error(status.HTTP_404_NOT_FOUND, error_msg)

if not is_group_owner_or_admin(group, email):
error_msg = 'Permission denied.'
return api_error(status.HTTP_403_FORBIDDEN, error_msg)

try:
GroupInviteLinkModel.objects.filter(token=token, group_id=group_id).delete()
except Exception as e:
logger.error(f'delete group invite links failed. {e}')
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, 'Internal Server Error')

return Response({'success': True})


@login_required
def group_invite(request, token):
"""
reigsterd user add to group
registered user add to group
"""
print(request.METHOD)
print(request.user)
email = request.user.username
print(request.user)
print(111)
next_url = request.GET.get('next', '/')
redirect_to = SERVICE_URL.rstrip('/') + '/' + next_url.lstrip('/')
group_invite_link = GroupInviteLinkModel.objects.filter(token=token).first()
if not group_invite_link:
return render_error(request, _('Group invite link does not exist'))

if is_group_member(group_invite_link.group_id, email):
print("is group member")
print(group_invite_link.group_id, group_invite_link.created_by, email)
return HttpResponseRedirect(redirect_to)

try:
group_org_id = ccnet_api.get_org_id_by_group(group_invite_link.group_id)
except Exception as e:
logger.error(f'get org id by group failed. {e}')
return render_error(request, 'Internal Server Error')

# org user but not same org
if request.user.org and request.user.org.org_id != group_org_id:
return render_error(request, _('You cannot join this group'))

# non-org user but group is in org
if not request.user.org and group_org_id > 0:
return render_error(request, _('You cannot join this group'))
return HttpResponseRedirect(redirect_to)

if not group_invite_link.created_by:
return render_error(request, _('Group invite link broken'))

try:
print(group_invite_link.group_id, group_invite_link.created_by, email)
ccnet_api.group_add_member(group_invite_link.group_id, group_invite_link.created_by, email)
except Exception as e:
logger.error(f'group invite add user failed. {e}')
return render_error(request, 'Internal Server Error')
print(redirect_to)

return HttpResponseRedirect(redirect_to)
3 changes: 2 additions & 1 deletion seahub/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
from seahub.api2.endpoints.address_book.members import AddressBookGroupsSearchMember

from seahub.api2.endpoints.group_members import GroupMembers, GroupSearchMember, GroupMember, \
GroupMembersBulk, GroupMembersImport, GroupMembersImportExample, GroupInviteLinks, group_invite
GroupMembersBulk, GroupMembersImport, GroupMembersImportExample, GroupInviteLinks, GroupInviteLink, group_invite
from seahub.api2.endpoints.search_group import SearchGroup
from seahub.api2.endpoints.share_links import ShareLinks, ShareLink, \
ShareLinkOnlineOfficeLock, ShareLinkDirents, ShareLinkSaveFileToRepo, \
Expand Down Expand Up @@ -343,6 +343,7 @@
re_path(r'^api/v2.1/search-group/$', SearchGroup.as_view(), name='api-v2.1-search-group'),

re_path(r'^api/v2.1/groups/(?P<group_id>\d+)/invite-links/$', GroupInviteLinks.as_view(),name='api-v2.1-group-invite-links'),
re_path(r'^api/v2.1/groups/(?P<group_id>\d+)/invite-links/(?P<token>[-0-9a-f]{8})/$', GroupInviteLink.as_view(), name='api-v2.1-group-invite-link'),
re_path(r'^group-invite/(?P<token>[-0-9a-f]{8})/$', group_invite, name='group_invite'),
## address book
re_path(r'^api/v2.1/address-book/groups/(?P<group_id>\d+)/sub-groups/$', AddressBookGroupsSubGroups.as_view(), name='api-v2.1-address-book-groups-sub-groups'),
Expand Down

0 comments on commit 470f091

Please sign in to comment.