1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-02 07:27:04 +00:00
* star repo

* file_icon_url -> item_icon_url

* add UserStarredFiles.objects.get_starred_repos_by_user()
This commit is contained in:
lian
2019-02-26 14:14:00 +08:00
committed by Daniel Pan
parent ac989da25a
commit d22e600442
12 changed files with 141 additions and 35 deletions

View File

@@ -8,6 +8,7 @@ import { gettext, siteRoot, isPro, username, folderPermEnabled, isSystemStaff }
import ModalPotal from '../../components/modal-portal'; import ModalPotal from '../../components/modal-portal';
import ShareDialog from '../../components/dialog/share-dialog'; import ShareDialog from '../../components/dialog/share-dialog';
import Rename from '../rename'; import Rename from '../rename';
import { seafileAPI } from '../../utils/seafile-api';
const propTypes = { const propTypes = {
currentGroup: PropTypes.object, currentGroup: PropTypes.object,
@@ -31,6 +32,7 @@ class SharedRepoListItem extends React.Component {
isItemMenuShow: false, isItemMenuShow: false,
isShowSharedDialog: false, isShowSharedDialog: false,
isRenaming: false, isRenaming: false,
isStarred: this.props.repo.starred,
}; };
this.isDeparementOnwerGroupMember = false; this.isDeparementOnwerGroupMember = false;
} }
@@ -323,6 +325,18 @@ class SharedRepoListItem extends React.Component {
return null; return null;
} }
onStarRepo = () => {
if (this.state.isStarred) {
seafileAPI.unStarItem(this.props.repo.repo_id, '/').then(() => {
this.setState({isStarred: !this.state.isStarred});
});
} else {
seafileAPI.starItem(this.props.repo.repo_id, '/').then(() => {
this.setState({isStarred: !this.state.isStarred});
})
}
}
renderPCUI = () => { renderPCUI = () => {
let { iconUrl, iconTitle, libPath } = this.getRepoComputeParams(); let { iconUrl, iconTitle, libPath } = this.getRepoComputeParams();
let { repo } = this.props; let { repo } = this.props;
@@ -332,6 +346,10 @@ class SharedRepoListItem extends React.Component {
return ( return (
<Fragment> <Fragment>
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseOver={this.onMouseOver} onMouseLeave={this.onMouseLeave}> <tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseOver={this.onMouseOver} onMouseLeave={this.onMouseLeave}>
<td className="text-center">
{!this.state.isStarred && <i className="far fa-star star-empty cursor-pointer" onClick={this.onStarRepo}></i>}
{this.state.isStarred && <i className="fas fa-star cursor-pointer" onClick={this.onStarRepo}></i>}
</td>
<td><img src={iconUrl} title={repo.iconTitle} alt={iconTitle} width="24" /></td> <td><img src={iconUrl} title={repo.iconTitle} alt={iconTitle} width="24" /></td>
<td> <td>
{this.state.isRenaming ? {this.state.isRenaming ?

View File

@@ -104,8 +104,9 @@ class SharedRepoListView extends React.Component {
<table className={isShowTableThread ? '' : 'table-thead-hidden'}> <table className={isShowTableThread ? '' : 'table-thead-hidden'}>
<thead> <thead>
<tr> <tr>
<th width="4%"></th>
<th width="4%"><span className="sr-only">{gettext('Library Type')}</span></th> <th width="4%"><span className="sr-only">{gettext('Library Type')}</span></th>
<th width="40%"><a className="d-block table-sort-op" href="#" onClick={this.sortByName}>{gettext('Name')} {sortByName && sortIcon}</a></th> <th width="36%"><a className="d-block table-sort-op" href="#" onClick={this.sortByName}>{gettext('Name')} {sortByName && sortIcon}</a></th>
<th width="12%"><span className="sr-only">{gettext('Actions')}</span></th> <th width="12%"><span className="sr-only">{gettext('Actions')}</span></th>
<th width={'14%'}>{gettext('Size')}</th> <th width={'14%'}>{gettext('Size')}</th>
<th width={'14%'}><a className="d-block table-sort-op" href="#" onClick={this.sortByTime}>{gettext('Last Update')} {sortByTime && sortIcon}</a></th> <th width={'14%'}><a className="d-block table-sort-op" href="#" onClick={this.sortByTime}>{gettext('Last Update')} {sortByTime && sortIcon}</a></th>

View File

@@ -15,6 +15,7 @@ class Repo {
this.modifier_email = object.modifier_email; this.modifier_email = object.modifier_email;
this.modifier_name = object.modifier_name; this.modifier_name = object.modifier_name;
this.type = object.type; this.type = object.type;
this.starred = object.starred;
if (object.is_admin != undefined) { if (object.is_admin != undefined) {
this.is_admin = object.is_admin; this.is_admin = object.is_admin;
} }

View File

@@ -34,6 +34,7 @@ class MylibRepoListItem extends React.Component {
super(props); super(props);
this.state = { this.state = {
isOpIconShow: false, isOpIconShow: false,
isStarred: this.props.repo.starred,
isRenaming: false, isRenaming: false,
isShareDialogShow: false, isShareDialogShow: false,
isDeleteDialogShow: false, isDeleteDialogShow: false,
@@ -103,6 +104,18 @@ class MylibRepoListItem extends React.Component {
this.props.onRepoClick(this.props.repo); this.props.onRepoClick(this.props.repo);
} }
onStarRepo = () => {
if (this.state.isStarred) {
seafileAPI.unStarItem(this.props.repo.repo_id, '/').then(() => {
this.setState({isStarred: !this.state.isStarred});
});
} else {
seafileAPI.starItem(this.props.repo.repo_id, '/').then(() => {
this.setState({isStarred: !this.state.isStarred});
})
}
}
onShareToggle = () => { onShareToggle = () => {
this.setState({isShareDialogShow: !this.state.isShareDialogShow}); this.setState({isShareDialogShow: !this.state.isShareDialogShow});
} }
@@ -180,24 +193,28 @@ class MylibRepoListItem extends React.Component {
renderPCUI = () => { renderPCUI = () => {
let repo = this.props.repo; let repo = this.props.repo;
let iconUrl = Utils.getLibIconUrl(repo); let iconUrl = Utils.getLibIconUrl(repo);
let iconTitle = Utils.getLibIconTitle(repo); let iconTitle = Utils.getLibIconTitle(repo);
let repoURL = `${siteRoot}library/${repo.repo_id}/${Utils.encodePath(repo.repo_name)}/`; let repoURL = `${siteRoot}library/${repo.repo_id}/${Utils.encodePath(repo.repo_name)}/`;
return ( return (
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave} onClick={this.onRepoClick}> <tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave} onClick={this.onRepoClick}>
<td className="text-center">
{!this.state.isStarred && <i className="far fa-star star-empty cursor-pointer" onClick={this.onStarRepo}></i>}
{this.state.isStarred && <i className="fas fa-star cursor-pointer" onClick={this.onStarRepo}></i>}
</td>
<td><img src={iconUrl} title={iconTitle} alt={iconTitle} width="24" /></td> <td><img src={iconUrl} title={iconTitle} alt={iconTitle} width="24" /></td>
<td> <td>
{this.state.isRenaming && ( {this.state.isRenaming && (
<Rename <Rename
name={repo.repo_name} name={repo.repo_name}
onRenameConfirm={this.onRenameConfirm} onRenameConfirm={this.onRenameConfirm}
onRenameCancel={this.onRenameCancel} onRenameCancel={this.onRenameCancel}
/> />
)} )}
{!this.state.isRenaming && repo.repo_name && ( {!this.state.isRenaming && repo.repo_name && (
<Link to={repoURL}>{repo.repo_name}</Link> <Link to={repoURL}>{repo.repo_name}</Link>
)} )}
{!this.state.isRenaming && !repo.repo_name && {!this.state.isRenaming && !repo.repo_name &&
(gettext('Broken (please contact your administrator to fix this library)')) (gettext('Broken (please contact your administrator to fix this library)'))
} }
</td> </td>
@@ -206,9 +223,9 @@ class MylibRepoListItem extends React.Component {
<div> <div>
<a href="#" className="op-icon sf2-icon-share" title={gettext('Share')} onClick={this.onShareToggle}></a> <a href="#" className="op-icon sf2-icon-share" title={gettext('Share')} onClick={this.onShareToggle}></a>
<a href="#" className="op-icon sf2-icon-delete" title={gettext('Delete')} onClick={this.onDeleteToggle}></a> <a href="#" className="op-icon sf2-icon-delete" title={gettext('Delete')} onClick={this.onDeleteToggle}></a>
<MylibRepoMenu <MylibRepoMenu
isPC={true} isPC={true}
repo={this.props.repo} repo={this.props.repo}
onMenuItemClick={this.onMenuItemClick} onMenuItemClick={this.onMenuItemClick}
onFreezedItem={this.props.onFreezedItem} onFreezedItem={this.props.onFreezedItem}
onUnfreezedItem={this.onUnfreezedItem} onUnfreezedItem={this.onUnfreezedItem}
@@ -225,7 +242,7 @@ class MylibRepoListItem extends React.Component {
renderMobileUI = () => { renderMobileUI = () => {
let repo = this.props.repo; let repo = this.props.repo;
let iconUrl = Utils.getLibIconUrl(repo); let iconUrl = Utils.getLibIconUrl(repo);
let iconTitle = Utils.getLibIconTitle(repo); let iconTitle = Utils.getLibIconTitle(repo);
let repoURL = `${siteRoot}library/${repo.repo_id}/${Utils.encodePath(repo.repo_name)}/`; let repoURL = `${siteRoot}library/${repo.repo_id}/${Utils.encodePath(repo.repo_name)}/`;
@@ -234,16 +251,16 @@ class MylibRepoListItem extends React.Component {
<td><img src={iconUrl} title={iconTitle} alt={iconTitle} width="24" /></td> <td><img src={iconUrl} title={iconTitle} alt={iconTitle} width="24" /></td>
<td> <td>
{this.state.isRenaming && ( {this.state.isRenaming && (
<Rename <Rename
name={repo.repo_name} name={repo.repo_name}
onRenameConfirm={this.onRenameConfirm} onRenameConfirm={this.onRenameConfirm}
onRenameCancel={this.onRenameCancel} onRenameCancel={this.onRenameCancel}
/> />
)} )}
{!this.state.isRenaming && repo.repo_name && ( {!this.state.isRenaming && repo.repo_name && (
<div><Link to={repoURL}>{repo.repo_name}</Link></div> <div><Link to={repoURL}>{repo.repo_name}</Link></div>
)} )}
{!this.state.isRenaming && !repo.repo_name && {!this.state.isRenaming && !repo.repo_name &&
<div>(gettext('Broken (please contact your administrator to fix this library)'))</div> <div>(gettext('Broken (please contact your administrator to fix this library)'))</div>
} }
<span className="item-meta-info">{repo.size}</span> <span className="item-meta-info">{repo.size}</span>
@@ -251,8 +268,8 @@ class MylibRepoListItem extends React.Component {
</td> </td>
<td> <td>
{repo.repo_name && ( {repo.repo_name && (
<MylibRepoMenu <MylibRepoMenu
repo={this.props.repo} repo={this.props.repo}
onMenuItemClick={this.onMenuItemClick} onMenuItemClick={this.onMenuItemClick}
onFreezedItem={this.props.onFreezedItem} onFreezedItem={this.props.onFreezedItem}
onUnfreezedItem={this.onUnfreezedItem} onUnfreezedItem={this.onUnfreezedItem}
@@ -275,7 +292,7 @@ class MylibRepoListItem extends React.Component {
</MediaQuery> </MediaQuery>
{this.state.isShareDialogShow && ( {this.state.isShareDialogShow && (
<ModalPortal> <ModalPortal>
<ShareDialog <ShareDialog
itemType={'library'} itemType={'library'}
itemName={repo.repo_name} itemName={repo.repo_name}
itemPath={'/'} itemPath={'/'}
@@ -289,26 +306,26 @@ class MylibRepoListItem extends React.Component {
)} )}
{this.state.isDeleteDialogShow && ( {this.state.isDeleteDialogShow && (
<ModalPortal> <ModalPortal>
<DeleteRepoDialog <DeleteRepoDialog
repo={repo} repo={repo}
onDeleteRepo={this.onDeleteRepo} onDeleteRepo={this.onDeleteRepo}
toggle={this.onDeleteToggle} toggle={this.onDeleteToggle}
/> />
</ModalPortal> </ModalPortal>
)} )}
{this.state.isTransferDialogShow && ( {this.state.isTransferDialogShow && (
<ModalPortal> <ModalPortal>
<TransferDialog <TransferDialog
repoID={repo.repo_id} repoID={repo.repo_id}
itemName={repo.repo_name} itemName={repo.repo_name}
submit={this.onTransferRepo} submit={this.onTransferRepo}
toggleDialog={this.onTransferToggle} toggleDialog={this.onTransferToggle}
/> />
</ModalPortal> </ModalPortal>
)} )}
{this.state.isHistorySettingDialogShow && ( {this.state.isHistorySettingDialogShow && (
<ModalPortal> <ModalPortal>
<LibHistorySettingDialog <LibHistorySettingDialog
repoID={repo.repo_id} repoID={repo.repo_id}
itemName={repo.repo_name} itemName={repo.repo_name}
toggleDialog={this.onHistorySettingToggle} toggleDialog={this.onHistorySettingToggle}
@@ -317,7 +334,7 @@ class MylibRepoListItem extends React.Component {
)} )}
{this.state.isChangePasswordDialogShow && ( {this.state.isChangePasswordDialogShow && (
<ModalPortal> <ModalPortal>
<ChangeRepoPasswordDialog <ChangeRepoPasswordDialog
repoID={repo.repo_id} repoID={repo.repo_id}
repoName={repo.repo_name} repoName={repo.repo_name}
toggleDialog={this.onChangePasswordToggle} toggleDialog={this.onChangePasswordToggle}
@@ -326,7 +343,7 @@ class MylibRepoListItem extends React.Component {
)} )}
{this.state.isResetPasswordDialogShow && ( {this.state.isResetPasswordDialogShow && (
<ModalPortal> <ModalPortal>
<ResetEncryptedRepoPasswordDialog <ResetEncryptedRepoPasswordDialog
repoID={repo.repo_id} repoID={repo.repo_id}
toggleDialog={this.onResetPasswordToggle} toggleDialog={this.onResetPasswordToggle}
/> />

View File

@@ -77,8 +77,9 @@ class MylibRepoListView extends React.Component {
<table> <table>
<thead> <thead>
<tr> <tr>
<th width="4%"></th>
<th width="4%"><span className="sr-only">{gettext('Library Type')}</span></th> <th width="4%"><span className="sr-only">{gettext('Library Type')}</span></th>
<th width="42%"><a className="d-block table-sort-op" href="#" onClick={this.sortByName}>{gettext('Name')} {this.props.sortBy === 'name' && sortIcon}</a></th> <th width="38%"><a className="d-block table-sort-op" href="#" onClick={this.sortByName}>{gettext('Name')} {this.props.sortBy === 'name' && sortIcon}</a></th>
<th width="14%"><span className="sr-only">{gettext('Actions')}</span></th> <th width="14%"><span className="sr-only">{gettext('Actions')}</span></th>
<th width={showStorageBackend ? '15%' : '20%'}>{gettext('Size')}</th> <th width={showStorageBackend ? '15%' : '20%'}>{gettext('Size')}</th>
{showStorageBackend ? <th width="10%">{gettext('Storage backend')}</th> : null} {showStorageBackend ? <th width="10%">{gettext('Storage backend')}</th> : null}

View File

@@ -49,8 +49,9 @@ class Content extends Component {
const desktopThead = ( const desktopThead = (
<thead> <thead>
<tr> <tr>
<th width="4%"></th>
<th width="4%"><span className="sr-only">{gettext('Library Type')}</span></th> <th width="4%"><span className="sr-only">{gettext('Library Type')}</span></th>
<th width="38%"><a className="d-block table-sort-op" href="#" onClick={this.sortByName}>{gettext('Name')} {sortByName && sortIcon}</a></th> <th width="34%"><a className="d-block table-sort-op" href="#" onClick={this.sortByName}>{gettext('Name')} {sortByName && sortIcon}</a></th>
<th width="10%"><span className="sr-only">{gettext('Actions')}</span></th> <th width="10%"><span className="sr-only">{gettext('Actions')}</span></th>
<th width="14%">{gettext('Size')}</th> <th width="14%">{gettext('Size')}</th>
<th width="18%"><a className="d-block table-sort-op" href="#" onClick={this.sortByTime}>{gettext('Last Update')} {sortByTime && sortIcon}</a></th> <th width="18%"><a className="d-block table-sort-op" href="#" onClick={this.sortByTime}>{gettext('Last Update')} {sortByTime && sortIcon}</a></th>
@@ -120,6 +121,7 @@ class Item extends Component {
showOpIcon: false, showOpIcon: false,
unshared: false, unshared: false,
isShowSharedDialog: false, isShowSharedDialog: false,
isStarred: this.props.data.starred,
}; };
this.handleMouseOver = this.handleMouseOver.bind(this); this.handleMouseOver = this.handleMouseOver.bind(this);
@@ -176,6 +178,18 @@ class Item extends Component {
this.setState({isShowSharedDialog: false}); this.setState({isShowSharedDialog: false});
} }
onStarRepo = () => {
if (this.state.isStarred) {
seafileAPI.unStarItem(this.props.data.repo_id, '/').then(() => {
this.setState({isStarred: !this.state.isStarred});
});
} else {
seafileAPI.starItem(this.props.data.repo_id, '/').then(() => {
this.setState({isStarred: !this.state.isStarred});
})
}
}
render() { render() {
if (this.state.unshared) { if (this.state.unshared) {
return null; return null;
@@ -194,6 +208,10 @@ class Item extends Component {
const desktopItem = ( const desktopItem = (
<Fragment> <Fragment>
<tr onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut}> <tr onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut}>
<td className="text-center">
{!this.state.isStarred && <i className="far fa-star star-empty cursor-pointer" onClick={this.onStarRepo}></i>}
{this.state.isStarred && <i className="fas fa-star cursor-pointer" onClick={this.onStarRepo}></i>}
</td>
<td><img src={data.icon_url} title={data.icon_title} alt={data.icon_title} width="24" /></td> <td><img src={data.icon_url} title={data.icon_title} alt={data.icon_title} width="24" /></td>
<td><Link to={`${siteRoot}library/${data.repo_id}/${data.repo_name}/`}>{data.repo_name}</Link></td> <td><Link to={`${siteRoot}library/${data.repo_id}/${data.repo_name}/`}>{data.repo_name}</Link></td>
<td> <td>

View File

@@ -94,7 +94,12 @@ class TableBody extends Component {
let listFilesActivities = this.state.items.map(function(item, index) { let listFilesActivities = this.state.items.map(function(item, index) {
item.file_icon_url = item.is_dir ? Utils.getFolderIconUrl(false) : Utils.getFileIconUrl(item.obj_name); if (item.path === '/') {
item.item_icon_url = Utils.getDefaultLibIconUrl(false);
} else {
item.item_icon_url = item.is_dir ? Utils.getFolderIconUrl(false) : Utils.getFileIconUrl(item.obj_name);
}
item.encoded_path = Utils.encodePath(item.path); item.encoded_path = Utils.encodePath(item.path);
item.thumbnail_url = item.encoded_thumbnail_src ? `${siteRoot}${item.encoded_thumbnail_src}` : ''; item.thumbnail_url = item.encoded_thumbnail_src ? `${siteRoot}${item.encoded_thumbnail_src}` : '';
@@ -165,7 +170,7 @@ class Item extends Component {
{ {
data.thumbnail_url ? data.thumbnail_url ?
<img className="thumbnail" src={data.thumbnail_url} alt="" /> : <img className="thumbnail" src={data.thumbnail_url} alt="" /> :
<img src={data.file_icon_url} alt={gettext('icon')} width="24" /> <img src={data.item_icon_url} alt={gettext('icon')} width="24" />
} }
</td> </td>
<td> <td>
@@ -188,7 +193,7 @@ class Item extends Component {
{ {
data.thumbnail_url ? data.thumbnail_url ?
<img className="thumbnail" src={data.thumbnail_url} alt="" /> : <img className="thumbnail" src={data.thumbnail_url} alt="" /> :
<img src={data.file_icon_url} alt={gettext('icon')} width="24" /> <img src={data.item_icon_url} alt={gettext('icon')} width="24" />
} }
</td> </td>
<td> <td>

View File

@@ -229,6 +229,13 @@ export const Utils = {
navigator.userAgent.indexOf('Chrome') > -1; navigator.userAgent.indexOf('Chrome') > -1;
}, },
getDefaultLibIconUrl: function(isBig) {
let size = Utils.isHiDPI() ? 48 : 24;
size = isBig ? 256 : size;
let icon_name = 'lib.png';
return mediaUrl + 'img/lib/' + size + '/' + icon_name;
},
getLibIconUrl: function(repo, isBig) { getLibIconUrl: function(repo, isBig) {
let permission = repo.permission || repo.share_permission; //Compatible with regular repo and repo shared let permission = repo.permission || repo.share_permission; //Compatible with regular repo and repo shared
let size = Utils.isHiDPI() ? 48 : 24; let size = Utils.isHiDPI() ? 48 : 24;

View File

@@ -29,6 +29,7 @@ from seahub.share.signals import share_repo_to_group_successful
from seahub.share.utils import is_repo_admin, check_group_share_in_permission, \ from seahub.share.utils import is_repo_admin, check_group_share_in_permission, \
share_dir_to_group share_dir_to_group
from seahub.constants import PERMISSION_READ from seahub.constants import PERMISSION_READ
from seahub.base.models import UserStarredFiles
from seahub.base.templatetags.seahub_tags import email2nickname, \ from seahub.base.templatetags.seahub_tags import email2nickname, \
email2contact_email email2contact_email
@@ -69,6 +70,7 @@ class GroupLibraries(APIView):
""" """
# only group member can get group libraries # only group member can get group libraries
username = request.user.username
if not is_group_member(group_id, request.user.username): if not is_group_member(group_id, request.user.username):
error_msg = 'Permission denied.' error_msg = 'Permission denied.'
return api_error(status.HTTP_403_FORBIDDEN, error_msg) return api_error(status.HTTP_403_FORBIDDEN, error_msg)
@@ -113,6 +115,13 @@ class GroupLibraries(APIView):
else: else:
contact_email_dict[email] = email2contact_email(email) contact_email_dict[email] = email2contact_email(email)
try:
starred_repos = UserStarredFiles.objects.get_starred_repos_by_user(username)
starred_repo_id_list = [item.repo_id for item in starred_repos]
except Exception as e:
logger.error(e)
starred_repo_id_list = []
result = [] result = []
for group_repo in group_repos: for group_repo in group_repos:
group_repo_info = get_group_repo_info(request, group_repo) group_repo_info = get_group_repo_info(request, group_repo)
@@ -127,6 +136,8 @@ class GroupLibraries(APIView):
group_repo_info['modifier_name'] = name_dict.get(modifier, '') group_repo_info['modifier_name'] = name_dict.get(modifier, '')
group_repo_info['modifier_contact_email'] = contact_email_dict.get(modifier, '') group_repo_info['modifier_contact_email'] = contact_email_dict.get(modifier, '')
group_repo_info['starred'] = group_repo.id in starred_repo_id_list
result.append(group_repo_info) result.append(group_repo_info)
return Response(result) return Response(result)

View File

@@ -28,6 +28,7 @@ from seahub.group.utils import validate_group_name, check_group_name_conflict, \
is_group_member, is_group_admin, is_group_owner, is_group_admin_or_owner, \ is_group_member, is_group_admin, is_group_owner, is_group_admin_or_owner, \
group_id_to_name group_id_to_name
from seahub.group.views import remove_group_common from seahub.group.views import remove_group_common
from seahub.base.models import UserStarredFiles
from seahub.base.templatetags.seahub_tags import email2nickname, \ from seahub.base.templatetags.seahub_tags import email2nickname, \
translate_seahub_time, email2contact_email translate_seahub_time, email2contact_email
from seahub.views.modules import is_wiki_mod_enabled_for_group, \ from seahub.views.modules import is_wiki_mod_enabled_for_group, \
@@ -111,6 +112,13 @@ class Groups(APIView):
gids = [g.id for g in user_groups] gids = [g.id for g in user_groups]
admin_info = ExtraGroupsSharePermission.objects.batch_get_repos_with_admin_permission(gids) admin_info = ExtraGroupsSharePermission.objects.batch_get_repos_with_admin_permission(gids)
try:
starred_repos = UserStarredFiles.objects.get_starred_repos_by_user(username)
starred_repo_id_list = [item.repo_id for item in starred_repos]
except Exception as e:
logger.error(e)
starred_repo_id_list = []
for g in user_groups: for g in user_groups:
group_info = get_group_info(request, g.id, avatar_size) group_info = get_group_info(request, g.id, avatar_size)
@@ -170,7 +178,8 @@ class Groups(APIView):
"owner_email": repo_owner, "owner_email": repo_owner,
"owner_name": name_dict.get(repo_owner, ''), "owner_name": name_dict.get(repo_owner, ''),
"owner_contact_email": contact_email_dict.get(repo_owner, ''), "owner_contact_email": contact_email_dict.get(repo_owner, ''),
"is_admin": (r.id, g.id) in admin_info "is_admin": (r.id, g.id) in admin_info,
"starred": r.repo_id in starred_repo_id_list,
} }
repos.append(repo) repos.append(repo)

View File

@@ -14,6 +14,7 @@ from seahub.api2.utils import api_error
from seahub.api2.endpoints.group_owned_libraries import get_group_id_by_repo_owner from seahub.api2.endpoints.group_owned_libraries import get_group_id_by_repo_owner
from seahub.base.models import UserStarredFiles
from seahub.base.templatetags.seahub_tags import email2nickname, \ from seahub.base.templatetags.seahub_tags import email2nickname, \
email2contact_email email2contact_email
from seahub.signals import repo_deleted from seahub.signals import repo_deleted
@@ -71,8 +72,16 @@ class ReposView(APIView):
if is_org_context(request): if is_org_context(request):
org_id = request.user.org.org_id org_id = request.user.org.org_id
try:
starred_repos = UserStarredFiles.objects.get_starred_repos_by_user(email)
starred_repo_id_list = [item.repo_id for item in starred_repos]
except Exception as e:
logger.error(e)
starred_repo_id_list = []
repo_info_list = [] repo_info_list = []
if filter_by['mine']: if filter_by['mine']:
if org_id: if org_id:
owned_repos = seafile_api.get_org_owned_repo_list(org_id, owned_repos = seafile_api.get_org_owned_repo_list(org_id,
email, ret_corrupted=True) email, ret_corrupted=True)
@@ -109,6 +118,7 @@ class ReposView(APIView):
"size": r.size, "size": r.size,
"encrypted": r.encrypted, "encrypted": r.encrypted,
"permission": 'rw', # Always have read-write permission to owned repo "permission": 'rw', # Always have read-write permission to owned repo
"starred": r.repo_id in starred_repo_id_list,
} }
if is_pro_version() and ENABLE_STORAGE_CLASSES: if is_pro_version() and ENABLE_STORAGE_CLASSES:
@@ -169,6 +179,7 @@ class ReposView(APIView):
"size": r.size, "size": r.size,
"encrypted": r.encrypted, "encrypted": r.encrypted,
"permission": r.permission, "permission": r.permission,
"starred": r.repo_id in starred_repo_id_list,
} }
if r.repo_id in repos_with_admin_share_to: if r.repo_id in repos_with_admin_share_to:
@@ -210,6 +221,7 @@ class ReposView(APIView):
"size": r.size, "size": r.size,
"encrypted": r.encrypted, "encrypted": r.encrypted,
"permission": r.permission, "permission": r.permission,
"starred": r.repo_id in starred_repo_id_list,
} }
repo_info_list.append(repo_info) repo_info_list.append(repo_info)
@@ -252,6 +264,7 @@ class ReposView(APIView):
"size": r.size, "size": r.size,
"encrypted": r.encrypted, "encrypted": r.encrypted,
"permission": r.permission, "permission": r.permission,
"starred": r.repo_id in starred_repo_id_list,
} }
repo_info_list.append(repo_info) repo_info_list.append(repo_info)

View File

@@ -57,9 +57,9 @@ class FileDiscuss(models.Model):
class FileCommentManager(models.Manager): class FileCommentManager(models.Manager):
def add(self, repo_id, parent_path, item_name, author, comment, detail=''): def add(self, repo_id, parent_path, item_name, author, comment, detail=''):
fileuuidmap = FileUUIDMap.objects.get_or_create_fileuuidmap(repo_id, fileuuidmap = FileUUIDMap.objects.get_or_create_fileuuidmap(repo_id,
parent_path, parent_path,
item_name, item_name,
False) False)
c = self.model(uuid=fileuuidmap, author=author, comment=comment, detail=detail) c = self.model(uuid=fileuuidmap, author=author, comment=comment, detail=detail)
c.save(using=self._db) c.save(using=self._db)
@@ -75,7 +75,7 @@ class FileCommentManager(models.Manager):
def get_by_file_path(self, repo_id, file_path): def get_by_file_path(self, repo_id, file_path):
parent_path = os.path.dirname(file_path) parent_path = os.path.dirname(file_path)
item_name = os.path.basename(file_path) item_name = os.path.basename(file_path)
uuid = FileUUIDMap.objects.get_fileuuidmap_by_path(repo_id, parent_path, uuid = FileUUIDMap.objects.get_fileuuidmap_by_path(repo_id, parent_path,
item_name, False) item_name, False)
objs = super(FileCommentManager, self).filter( objs = super(FileCommentManager, self).filter(
@@ -84,7 +84,7 @@ class FileCommentManager(models.Manager):
return objs return objs
def get_by_parent_path(self, repo_id, parent_path): def get_by_parent_path(self, repo_id, parent_path):
uuids = FileUUIDMap.objects.get_fileuuidmaps_by_parent_path(repo_id, uuids = FileUUIDMap.objects.get_fileuuidmaps_by_parent_path(repo_id,
parent_path) parent_path)
objs = super(FileCommentManager, self).filter(uuid__in=uuids) objs = super(FileCommentManager, self).filter(uuid__in=uuids)
return objs return objs
@@ -149,6 +149,11 @@ class StarredFile(object):
class UserStarredFilesManager(models.Manager): class UserStarredFilesManager(models.Manager):
def get_starred_repos_by_user(self, email):
starred_repos = UserStarredFiles.objects.filter(email=email, path='/')
return starred_repos
def get_starred_item(self, email, repo_id, path): def get_starred_item(self, email, repo_id, path):
path_list = [normalize_file_path(path), normalize_dir_path(path)] path_list = [normalize_file_path(path), normalize_dir_path(path)]