1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-12 13:24:52 +00:00

Group to department (#6411)

* change group to department

* update group quota

* admin change group

* optimize code

* Update change-group-dialog.js

* update

* code-optimize

* code-optimize

* Update groups.py

* update

* fix group-name

---------

Co-authored-by: 孙永强 <11704063+s-yongqiang@user.noreply.gitee.com>
Co-authored-by: r350178982 <32759763+r350178982@users.noreply.github.com>
This commit is contained in:
awu0403
2024-07-27 11:21:59 +08:00
committed by GitHub
parent ed1424d4f9
commit 953f17e717
11 changed files with 321 additions and 10 deletions

View File

@@ -0,0 +1,49 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button, Modal, ModalHeader, ModalFooter, ModalBody } from 'reactstrap';
import { Utils } from '../../utils/utils';
import { gettext } from '../../utils/constants';
const propTypes = {
groupName: PropTypes.string.isRequired,
changeGroup2Department: PropTypes.func.isRequired,
toggleDialog: PropTypes.func.isRequired
};
class ChangeGroupDialog extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedOption: null
};
}
submit = () => {
this.props.changeGroup2Department();
this.props.toggleDialog();
};
render() {
const groupName = '<span class="op-target">' + Utils.HTMLescape(this.props.groupName) + '</span>';
const msg = gettext('Are you sure to change Group {placeholder} to Department ?').replace('{placeholder}', groupName);
return (
<Modal isOpen={true} toggle={this.props.toggleDialog}>
<ModalHeader toggle={this.props.toggleDialog}>
{gettext('Change group to departmen')}
</ModalHeader>
<ModalBody>
<p dangerouslySetInnerHTML={{ __html: msg }}></p>
</ModalBody>
<ModalFooter>
<Button color="secondary" onClick={this.props.toggleDialog}>{gettext('Cancel')}</Button>
<Button color="primary" onClick={this.submit}>{gettext('Submit')}</Button>
</ModalFooter>
</Modal>
);
}
}
ChangeGroupDialog.propTypes = propTypes;
export default ChangeGroupDialog;

View File

@@ -8,6 +8,8 @@ import { Utils } from '../../utils/utils';
import toaster from '../../components/toast'; import toaster from '../../components/toast';
import OrgGroupInfo from '../../models/org-group'; import OrgGroupInfo from '../../models/org-group';
import MainPanelTopbar from './main-panel-topbar'; import MainPanelTopbar from './main-panel-topbar';
import ChangeGroupDialog from '../../components/dialog/change-group-dialog';
import { orgAdminAPI } from '../../utils/org-admin-api';
class Search extends React.Component { class Search extends React.Component {
@@ -132,6 +134,24 @@ class OrgGroups extends Component {
}); });
}; };
changeGroupItem = (group) => {
orgAdminAPI.orgAdminGroup2Department(orgID, group.id).then(res => {
let newGroupList = this.state.orgGroups.map(item => {
if (item.id == group.id) {
item = new OrgGroupInfo(res.data);
}
return item;
});
this.setState({
orgGroups: newGroupList
});
toaster.success(gettext('Successfully Change the group.'));
}).catch(error => {
let errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
});
};
searchItems = (keyword) => { searchItems = (keyword) => {
navigate(`${siteRoot}org/groupadmin/search-groups/?query=${encodeURIComponent(keyword)}`); navigate(`${siteRoot}org/groupadmin/search-groups/?query=${encodeURIComponent(keyword)}`);
}; };
@@ -173,6 +193,7 @@ class OrgGroups extends Component {
onFreezedItem={this.onFreezedItem} onFreezedItem={this.onFreezedItem}
onUnfreezedItem={this.onUnfreezedItem} onUnfreezedItem={this.onUnfreezedItem}
deleteGroupItem={this.deleteGroupItem} deleteGroupItem={this.deleteGroupItem}
changeGroupItem={this.changeGroupItem}
/> />
); );
})} })}
@@ -197,6 +218,7 @@ const GroupItemPropTypes = {
onFreezedItem: PropTypes.func.isRequired, onFreezedItem: PropTypes.func.isRequired,
onUnfreezedItem: PropTypes.func.isRequired, onUnfreezedItem: PropTypes.func.isRequired,
deleteGroupItem: PropTypes.func.isRequired, deleteGroupItem: PropTypes.func.isRequired,
changeGroupItem: PropTypes.func.isRequired,
}; };
class GroupItem extends React.Component { class GroupItem extends React.Component {
@@ -206,7 +228,8 @@ class GroupItem extends React.Component {
this.state = { this.state = {
highlight: false, highlight: false,
showMenu: false, showMenu: false,
isItemMenuShow: false isItemMenuShow: false,
isChangeDialogOpen: false,
}; };
} }
@@ -253,6 +276,16 @@ class GroupItem extends React.Component {
toggleDelete = () => { toggleDelete = () => {
this.props.deleteGroupItem(this.props.group); this.props.deleteGroupItem(this.props.group);
}; };
toggleChange = () => {
this.props.changeGroupItem(this.props.group);
};
toggleChangeDialog = (e) => {
if (e) {
e.preventDefault();
}
this.setState({ isChangeDialogOpen: !this.state.isChangeDialogOpen });
};
renderGroupHref = (group) => { renderGroupHref = (group) => {
let groupInfoHref; let groupInfoHref;
@@ -304,11 +337,19 @@ class GroupItem extends React.Component {
/> />
<DropdownMenu> <DropdownMenu>
<DropdownItem onClick={this.toggleDelete}>{gettext('Delete')}</DropdownItem> <DropdownItem onClick={this.toggleDelete}>{gettext('Delete')}</DropdownItem>
<DropdownItem onClick={this.toggleChangeDialog}>{gettext('Change to department')}</DropdownItem>
</DropdownMenu> </DropdownMenu>
</Dropdown> </Dropdown>
} }
{this.state.isChangeDialogOpen &&
<ChangeGroupDialog
groupName={group.groupName}
changeGroup2Department={this.toggleChange}
toggleDialog={this.toggleChangeDialog} />
}
</td> </td>
</tr> </tr>
); );
} }

View File

@@ -10,6 +10,7 @@ import Paginator from '../../../components/paginator';
import OpMenu from '../../../components/dialog/op-menu'; import OpMenu from '../../../components/dialog/op-menu';
import CommonOperationConfirmationDialog from '../../../components/dialog/common-operation-confirmation-dialog'; import CommonOperationConfirmationDialog from '../../../components/dialog/common-operation-confirmation-dialog';
import SysAdminTransferGroupDialog from '../../../components/dialog/sysadmin-dialog/sysadmin-group-transfer-dialog'; import SysAdminTransferGroupDialog from '../../../components/dialog/sysadmin-dialog/sysadmin-group-transfer-dialog';
import ChangeGroupDialog from '../../../components/dialog/change-group-dialog';
import UserLink from '../user-link'; import UserLink from '../user-link';
class Content extends Component { class Content extends Component {
@@ -70,6 +71,7 @@ class Content extends Component {
onUnfreezedItem={this.onUnfreezedItem} onUnfreezedItem={this.onUnfreezedItem}
deleteGroup={this.props.deleteGroup} deleteGroup={this.props.deleteGroup}
transferGroup={this.props.transferGroup} transferGroup={this.props.transferGroup}
changeGroup2Department={this.props.changeGroup2Department}
/>); />);
})} })}
</tbody> </tbody>
@@ -102,6 +104,7 @@ Content.propTypes = {
getListByPage: PropTypes.func.isRequired, getListByPage: PropTypes.func.isRequired,
deleteGroup: PropTypes.func.isRequired, deleteGroup: PropTypes.func.isRequired,
transferGroup: PropTypes.func.isRequired, transferGroup: PropTypes.func.isRequired,
changeGroup2Department: PropTypes.func.isRequired,
}; };
class Item extends Component { class Item extends Component {
@@ -112,7 +115,8 @@ class Item extends Component {
isOpIconShown: false, isOpIconShown: false,
highlight: false, highlight: false,
isDeleteDialogOpen: false, isDeleteDialogOpen: false,
isTransferDialogOpen: false isTransferDialogOpen: false,
isChangeDialogOpen: false
}; };
} }
@@ -150,6 +154,9 @@ class Item extends Component {
case 'Transfer': case 'Transfer':
this.toggleTransferDialog(); this.toggleTransferDialog();
break; break;
case 'Change':
this.toggleChangeDialog();
break;
default: default:
break; break;
} }
@@ -169,6 +176,12 @@ class Item extends Component {
this.setState({ isTransferDialogOpen: !this.state.isTransferDialogOpen }); this.setState({ isTransferDialogOpen: !this.state.isTransferDialogOpen });
}; };
toggleChangeDialog = (e) => {
if (e) {
e.preventDefault();
}
this.setState({ isChangeDialogOpen: !this.state.isChangeDialogOpen });
};
deleteGroup = () => { deleteGroup = () => {
this.props.deleteGroup(this.props.item.id); this.props.deleteGroup(this.props.item.id);
}; };
@@ -177,6 +190,10 @@ class Item extends Component {
this.props.transferGroup(this.props.item.id, receiver); this.props.transferGroup(this.props.item.id, receiver);
}; };
changeGroup = () => {
this.props.changeGroup2Department(this.props.item.id);
};
translateOperations = (item) => { translateOperations = (item) => {
let translateResult = ''; let translateResult = '';
switch (item) { switch (item) {
@@ -186,6 +203,9 @@ class Item extends Component {
case 'Transfer': case 'Transfer':
translateResult = gettext('Transfer'); translateResult = gettext('Transfer');
break; break;
case 'Change':
translateResult = gettext('Change to department');
break;
} }
return translateResult; return translateResult;
@@ -193,7 +213,7 @@ class Item extends Component {
render() { render() {
const { item } = this.props; const { item } = this.props;
const { isOpIconShown, isDeleteDialogOpen, isTransferDialogOpen } = this.state; const { isOpIconShown, isDeleteDialogOpen, isTransferDialogOpen, isChangeDialogOpen } = this.state;
let groupName = '<span class="op-target">' + Utils.HTMLescape(item.name) + '</span>'; let groupName = '<span class="op-target">' + Utils.HTMLescape(item.name) + '</span>';
let deleteDialogMsg = gettext('Are you sure you want to delete {placeholder} ?').replace('{placeholder}', groupName); let deleteDialogMsg = gettext('Are you sure you want to delete {placeholder} ?').replace('{placeholder}', groupName);
@@ -218,7 +238,7 @@ class Item extends Component {
<td> <td>
{(isOpIconShown && item.owner != 'system admin') && {(isOpIconShown && item.owner != 'system admin') &&
<OpMenu <OpMenu
operations={['Delete', 'Transfer']} operations={['Delete', 'Transfer', 'Change']}
translateOperations={this.translateOperations} translateOperations={this.translateOperations}
onMenuItemClick={this.onMenuItemClick} onMenuItemClick={this.onMenuItemClick}
onFreezedItem={this.props.onFreezedItem} onFreezedItem={this.props.onFreezedItem}
@@ -243,6 +263,13 @@ class Item extends Component {
toggleDialog={this.toggleTransferDialog} toggleDialog={this.toggleTransferDialog}
/> />
} }
{isChangeDialogOpen &&
<ChangeGroupDialog
groupName={item.name}
changeGroup2Department={this.changeGroup}
toggleDialog={this.toggleChangeDialog}
/>
}
</Fragment> </Fragment>
); );
} }

View File

@@ -9,6 +9,7 @@ import SysAdminCreateGroupDialog from '../../../components/dialog/sysadmin-dialo
import MainPanelTopbar from '../main-panel-topbar'; import MainPanelTopbar from '../main-panel-topbar';
import Search from '../search'; import Search from '../search';
import Content from './groups-content'; import Content from './groups-content';
import { systemAdminAPI } from '../../../utils/system-admin-api';
class Groups extends Component { class Groups extends Component {
@@ -109,6 +110,24 @@ class Groups extends Component {
}); });
}; };
changeGroup2Department = (groupID) => {
systemAdminAPI.adminGroup2Department(groupID).then((res) => {
let newGroupList = this.state.groupList.map(item => {
if (item.id == groupID) {
item = res.data;
}
return item;
});
this.setState({
groupList: newGroupList
});
toaster.success(gettext('Successfully Change the group.'));
}).catch((error) => {
let errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
});
};
getSearch = () => { getSearch = () => {
return <Search return <Search
placeholder={gettext('Search groups by name')} placeholder={gettext('Search groups by name')}
@@ -144,6 +163,7 @@ class Groups extends Component {
pageInfo={this.state.pageInfo} pageInfo={this.state.pageInfo}
deleteGroup={this.deleteGroup} deleteGroup={this.deleteGroup}
transferGroup={this.transferGroup} transferGroup={this.transferGroup}
changeGroup2Department={this.changeGroup2Department}
getListByPage={this.getGroupListByPage} getListByPage={this.getGroupListByPage}
resetPerPage={this.resetPerPage} resetPerPage={this.resetPerPage}
curPerPage={this.state.perPage} curPerPage={this.state.perPage}

View File

@@ -0,0 +1,58 @@
import axios from 'axios';
import cookie from 'react-cookies';
import { siteRoot } from './constants';
class OrgAdminAPI {
init({ server, username, password, token }) {
this.server = server;
this.username = username;
this.password = password;
this.token = token;
if (this.token && this.server) {
this.req = axios.create({
baseURL: this.server,
headers: { 'Authorization': 'Token ' + this.token },
});
}
return this;
}
initForSeahubUsage({ siteRoot, xcsrfHeaders }) {
if (siteRoot && siteRoot.charAt(siteRoot.length - 1) === '/') {
var server = siteRoot.substring(0, siteRoot.length - 1);
this.server = server;
} else {
this.server = siteRoot;
}
this.req = axios.create({
headers: {
'X-CSRFToken': xcsrfHeaders,
}
});
return this;
}
_sendPostRequest(url, form) {
if (form.getHeaders) {
return this.req.post(url, form, {
headers: form.getHeaders()
});
} else {
return this.req.post(url, form);
}
}
orgAdminGroup2Department(orgID, groupID) {
var url = this.server + '/api/v2.1/org/' + orgID + '/admin/groups/' + groupID + '/group-to-department/';
return this.req.post(url);
}
}
let orgAdminAPI = new OrgAdminAPI();
let xcsrfHeaders = cookie.load('sfcsrftoken');
orgAdminAPI.initForSeahubUsage({ siteRoot, xcsrfHeaders });
export { orgAdminAPI };

View File

@@ -81,6 +81,11 @@ class SystemAdminAPI {
return this.req.get(url); return this.req.get(url);
} }
adminGroup2Department(groupID) {
const url = this.server + '/api/v2.1/admin/groups/' + groupID + '/group-to-department/';
return this.req.post(url);
}
} }
let systemAdminAPI = new SystemAdminAPI(); let systemAdminAPI = new SystemAdminAPI();

View File

@@ -26,6 +26,8 @@ from seahub.api2.utils import api_error
from seahub.api2.throttling import UserRateThrottle from seahub.api2.throttling import UserRateThrottle
from seahub.api2.authentication import TokenAuthentication from seahub.api2.authentication import TokenAuthentication
from seahub.share.models import ExtraGroupsSharePermission from seahub.share.models import ExtraGroupsSharePermission
from seahub.utils.ccnet_db import CcnetDB
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -398,3 +400,44 @@ class AdminDepartments(APIView):
return Response(result) return Response(result)
class AdminGroupToDeptView(APIView):
"""group to department"""
authentication_classes = (TokenAuthentication, SessionAuthentication)
permission_classes = (IsAdminUser,)
throttle_classes = (UserRateThrottle,)
def post(self, request, group_id):
""" Admin change a group
group to department
Permission checking:
1. Admin user;
"""
if not request.user.admin_permissions.can_manage_group():
return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.')
# recourse check
group_id = int(group_id)
group = ccnet_api.get_group(group_id)
if group.creator_name == 'system admin':
error_msg = 'Group %s is already a department' % group_id
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
if not group:
error_msg = 'Group %d not found.' % group_id
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
# group to department
try:
ccnet_db = CcnetDB()
ccnet_db.change_groups_into_departments(group_id)
seafile_api.set_group_quota(group_id, -2)
except Exception as e:
logger.error(e)
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
group_info = get_group_info(group_id)
return Response(group_info)

View File

@@ -6,7 +6,7 @@ from rest_framework.views import APIView
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.authentication import SessionAuthentication from rest_framework.authentication import SessionAuthentication
from seaserv import ccnet_api from seaserv import ccnet_api, seafile_api
from seahub.api2.permissions import IsProVersion, IsOrgAdminUser from seahub.api2.permissions import IsProVersion, IsOrgAdminUser
from seahub.api2.throttling import UserRateThrottle from seahub.api2.throttling import UserRateThrottle
@@ -18,6 +18,8 @@ from seahub.avatar.templatetags.group_avatar_tags import api_grp_avatar_url, get
from seahub.base.templatetags.seahub_tags import email2nickname, email2contact_email from seahub.base.templatetags.seahub_tags import email2nickname, email2contact_email
from seahub.utils.ccnet_db import CcnetDB from seahub.utils.ccnet_db import CcnetDB
from seahub.utils.timeutils import timestamp_to_isoformat_timestr from seahub.utils.timeutils import timestamp_to_isoformat_timestr
from seahub.admin_log.signals import admin_operation
from seahub.admin_log.models import GROUP_TRANSFER
from pysearpc import SearpcError from pysearpc import SearpcError
@@ -247,3 +249,48 @@ class OrgAdminDepartments(APIView):
result.append(department_info) result.append(department_info)
return Response(result) return Response(result)
class OrgAdminGroupToDeptView(APIView):
"""org group to department"""
authentication_classes = (TokenAuthentication, SessionAuthentication)
permission_classes = (IsProVersion, IsOrgAdminUser)
throttle_classes = (UserRateThrottle,)
def post(self, request, org_id, group_id):
# resource check
org_id = int(org_id)
if not ccnet_api.get_org_by_id(org_id):
error_msg = 'Organization %s not found.' % org_id
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
group_id = int(group_id)
if get_org_id_by_group(group_id) != org_id:
error_msg = 'Group %s not found.' % group_id
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
group = ccnet_api.get_group(group_id)
if group.creator_name == 'system admin':
error_msg = 'Group %s is already a department' % group_id
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
try:
# group to department
ccnet_db = CcnetDB()
ccnet_db.change_groups_into_departments(group_id)
seafile_api.set_group_quota(group_id, -2)
except Exception as e:
logger.error(e)
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
group = ccnet_api.get_group(group_id)
group_info = {
"id": group.id,
"group_name": group.group_name,
"ctime": timestamp_to_isoformat_timestr(group.timestamp),
"creator_email": group.creator_name,
"creator_name": email2nickname(group.creator_name),
'creator_contact_email': email2contact_email(group.creator_name),
}
return Response(group_info)

View File

@@ -13,7 +13,8 @@ from .api.group_members import AdminGroupMembers, AdminGroupMember
from .api.admin.users import OrgAdminUser, OrgAdminUsers, OrgAdminSearchUser, \ from .api.admin.users import OrgAdminUser, OrgAdminUsers, OrgAdminSearchUser, \
OrgAdminImportUsers, OrgAdminInviteUser OrgAdminImportUsers, OrgAdminInviteUser
from .api.admin.user_set_password import OrgAdminUserSetPassword from .api.admin.user_set_password import OrgAdminUserSetPassword
from .api.admin.groups import OrgAdminGroups, OrgAdminGroup, OrgAdminSearchGroup, OrgAdminDepartments from .api.admin.groups import OrgAdminGroups, OrgAdminGroup, OrgAdminSearchGroup, \
OrgAdminDepartments, OrgAdminGroupToDeptView
from .api.admin.repos import OrgAdminRepos, OrgAdminRepo from .api.admin.repos import OrgAdminRepos, OrgAdminRepo
from .api.admin.trash_libraries import OrgAdminTrashLibraries, OrgAdminTrashLibrary from .api.admin.trash_libraries import OrgAdminTrashLibraries, OrgAdminTrashLibrary
from .api.admin.info import OrgAdminInfo from .api.admin.info import OrgAdminInfo
@@ -72,6 +73,7 @@ urlpatterns = [
path('<int:org_id>/admin/search-group/', OrgAdminSearchGroup.as_view(), name='api-v2.1-org-admin-search-group'), path('<int:org_id>/admin/search-group/', OrgAdminSearchGroup.as_view(), name='api-v2.1-org-admin-search-group'),
path('<int:org_id>/admin/groups/<int:group_id>/', OrgAdminGroup.as_view(), name='api-admin-group'), path('<int:org_id>/admin/groups/<int:group_id>/', OrgAdminGroup.as_view(), name='api-admin-group'),
path('<int:org_id>/admin/groups/<int:group_id>/libraries/', AdminGroupLibraries.as_view(), name='api-admin-group-libraries'), path('<int:org_id>/admin/groups/<int:group_id>/libraries/', AdminGroupLibraries.as_view(), name='api-admin-group-libraries'),
path('<int:org_id>/admin/groups/<int:group_id>/group-to-department/', OrgAdminGroupToDeptView.as_view(), name='api-admin-group-to-department'),
re_path(r'^(?P<org_id>\d+)/admin/groups/(?P<group_id>\d+)/libraries/(?P<repo_id>[-0-9a-f]{36})/$', AdminGroupLibrary.as_view(), name='api-admin-group-library'), re_path(r'^(?P<org_id>\d+)/admin/groups/(?P<group_id>\d+)/libraries/(?P<repo_id>[-0-9a-f]{36})/$', AdminGroupLibrary.as_view(), name='api-admin-group-library'),
path('<int:org_id>/admin/groups/<int:group_id>/group-owned-libraries/', AdminGroupOwnedLibraries.as_view(), name='api-admin-group-owned-libraries'), path('<int:org_id>/admin/groups/<int:group_id>/group-owned-libraries/', AdminGroupOwnedLibraries.as_view(), name='api-admin-group-owned-libraries'),

View File

@@ -151,7 +151,8 @@ from seahub.api2.endpoints.admin.system_library import AdminSystemLibrary, \
AdminSystemLibraryUploadLink AdminSystemLibraryUploadLink
from seahub.api2.endpoints.admin.default_library import AdminDefaultLibrary from seahub.api2.endpoints.admin.default_library import AdminDefaultLibrary
from seahub.api2.endpoints.admin.trash_libraries import AdminTrashLibraries, AdminTrashLibrary from seahub.api2.endpoints.admin.trash_libraries import AdminTrashLibraries, AdminTrashLibrary
from seahub.api2.endpoints.admin.groups import AdminGroups, AdminGroup, AdminSearchGroup, AdminDepartments from seahub.api2.endpoints.admin.groups import AdminGroups, AdminGroup, AdminSearchGroup, \
AdminDepartments, AdminGroupToDeptView
from seahub.api2.endpoints.admin.group_libraries import AdminGroupLibraries, AdminGroupLibrary from seahub.api2.endpoints.admin.group_libraries import AdminGroupLibraries, AdminGroupLibrary
from seahub.api2.endpoints.admin.group_members import AdminGroupMembers, AdminGroupMember from seahub.api2.endpoints.admin.group_members import AdminGroupMembers, AdminGroupMember
from seahub.api2.endpoints.admin.shares import AdminShares from seahub.api2.endpoints.admin.shares import AdminShares
@@ -655,6 +656,7 @@ urlpatterns = [
re_path(r'^api/v2.1/admin/groups/(?P<group_id>\d+)/members/(?P<email>[^/]+)/$', AdminGroupMember.as_view(), name='api-v2.1-admin-group-member'), re_path(r'^api/v2.1/admin/groups/(?P<group_id>\d+)/members/(?P<email>[^/]+)/$', AdminGroupMember.as_view(), name='api-v2.1-admin-group-member'),
re_path(r'^api/v2.1/admin/groups/(?P<group_id>\d+)/group-owned-libraries/$', AdminGroupOwnedLibraries.as_view(), name='api-v2.1-admin-group-owned-libraries'), re_path(r'^api/v2.1/admin/groups/(?P<group_id>\d+)/group-owned-libraries/$', AdminGroupOwnedLibraries.as_view(), name='api-v2.1-admin-group-owned-libraries'),
re_path(r'^api/v2.1/admin/groups/(?P<group_id>\d+)/group-owned-libraries/(?P<repo_id>[-0-9a-f]{36})/$', AdminGroupOwnedLibrary.as_view(), name='api-v2.1-admin-owned-group-library'), re_path(r'^api/v2.1/admin/groups/(?P<group_id>\d+)/group-owned-libraries/(?P<repo_id>[-0-9a-f]{36})/$', AdminGroupOwnedLibrary.as_view(), name='api-v2.1-admin-owned-group-library'),
re_path(r'^api/v2.1/admin/groups/(?P<group_id>\d+)/group-to-department/', AdminGroupToDeptView.as_view(), name='api-v2.1-admin-group-to-department'),
## admin::departments ## admin::departments
re_path(r'api/v2.1/admin/departments/$', AdminDepartments.as_view(), name='api-v2.1-admin-departments'), re_path(r'api/v2.1/admin/departments/$', AdminDepartments.as_view(), name='api-v2.1-admin-departments'),

View File

@@ -163,7 +163,6 @@ class CcnetDB:
return users, total_count return users, total_count
def get_group_ids_admins_map(self, group_ids): def get_group_ids_admins_map(self, group_ids):
group_admins = {} group_admins = {}
group_ids_str = ','.join(str(id) for id in group_ids) group_ids_str = ','.join(str(id) for id in group_ids)
@@ -183,3 +182,21 @@ class CcnetDB:
else: else:
group_admins[group_id] = [user] group_admins[group_id] = [user]
return group_admins return group_admins
def change_groups_into_departments(self, group_id):
sql = f"""
UPDATE `{self.db_name}`.`Group` g
SET
g.creator_name = 'system admin',
g.parent_group_id = -1
WHERE
g.group_id = {group_id}
"""
structure_sql = f"""
INSERT INTO `{self.db_name}`.`GroupStructure` (group_id, path)
VALUES ('{group_id}', '{group_id}')
"""
with connection.cursor() as cursor:
cursor.execute(sql)
cursor.execute(structure_sql)