mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-01 23:20:51 +00:00
star repo (#2980)
* star repo * file_icon_url -> item_icon_url * add UserStarredFiles.objects.get_starred_repos_by_user()
This commit is contained in:
@@ -8,6 +8,7 @@ import { gettext, siteRoot, isPro, username, folderPermEnabled, isSystemStaff }
|
||||
import ModalPotal from '../../components/modal-portal';
|
||||
import ShareDialog from '../../components/dialog/share-dialog';
|
||||
import Rename from '../rename';
|
||||
import { seafileAPI } from '../../utils/seafile-api';
|
||||
|
||||
const propTypes = {
|
||||
currentGroup: PropTypes.object,
|
||||
@@ -31,6 +32,7 @@ class SharedRepoListItem extends React.Component {
|
||||
isItemMenuShow: false,
|
||||
isShowSharedDialog: false,
|
||||
isRenaming: false,
|
||||
isStarred: this.props.repo.starred,
|
||||
};
|
||||
this.isDeparementOnwerGroupMember = false;
|
||||
}
|
||||
@@ -323,6 +325,18 @@ class SharedRepoListItem extends React.Component {
|
||||
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 = () => {
|
||||
let { iconUrl, iconTitle, libPath } = this.getRepoComputeParams();
|
||||
let { repo } = this.props;
|
||||
@@ -332,6 +346,10 @@ class SharedRepoListItem extends React.Component {
|
||||
return (
|
||||
<Fragment>
|
||||
<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>
|
||||
{this.state.isRenaming ?
|
||||
|
@@ -104,8 +104,9 @@ class SharedRepoListView extends React.Component {
|
||||
<table className={isShowTableThread ? '' : 'table-thead-hidden'}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="4%"></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={'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>
|
||||
|
@@ -15,6 +15,7 @@ class Repo {
|
||||
this.modifier_email = object.modifier_email;
|
||||
this.modifier_name = object.modifier_name;
|
||||
this.type = object.type;
|
||||
this.starred = object.starred;
|
||||
if (object.is_admin != undefined) {
|
||||
this.is_admin = object.is_admin;
|
||||
}
|
||||
|
@@ -34,6 +34,7 @@ class MylibRepoListItem extends React.Component {
|
||||
super(props);
|
||||
this.state = {
|
||||
isOpIconShow: false,
|
||||
isStarred: this.props.repo.starred,
|
||||
isRenaming: false,
|
||||
isShareDialogShow: false,
|
||||
isDeleteDialogShow: false,
|
||||
@@ -103,6 +104,18 @@ class MylibRepoListItem extends React.Component {
|
||||
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 = () => {
|
||||
this.setState({isShareDialogShow: !this.state.isShareDialogShow});
|
||||
}
|
||||
@@ -185,6 +198,10 @@ class MylibRepoListItem extends React.Component {
|
||||
let repoURL = `${siteRoot}library/${repo.repo_id}/${Utils.encodePath(repo.repo_name)}/`;
|
||||
return (
|
||||
<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>
|
||||
{this.state.isRenaming && (
|
||||
|
@@ -77,8 +77,9 @@ class MylibRepoListView extends React.Component {
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="4%"></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={showStorageBackend ? '15%' : '20%'}>{gettext('Size')}</th>
|
||||
{showStorageBackend ? <th width="10%">{gettext('Storage backend')}</th> : null}
|
||||
|
@@ -49,8 +49,9 @@ class Content extends Component {
|
||||
const desktopThead = (
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="4%"></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="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>
|
||||
@@ -120,6 +121,7 @@ class Item extends Component {
|
||||
showOpIcon: false,
|
||||
unshared: false,
|
||||
isShowSharedDialog: false,
|
||||
isStarred: this.props.data.starred,
|
||||
};
|
||||
|
||||
this.handleMouseOver = this.handleMouseOver.bind(this);
|
||||
@@ -176,6 +178,18 @@ class Item extends Component {
|
||||
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() {
|
||||
if (this.state.unshared) {
|
||||
return null;
|
||||
@@ -194,6 +208,10 @@ class Item extends Component {
|
||||
const desktopItem = (
|
||||
<Fragment>
|
||||
<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><Link to={`${siteRoot}library/${data.repo_id}/${data.repo_name}/`}>{data.repo_name}</Link></td>
|
||||
<td>
|
||||
|
@@ -94,7 +94,12 @@ class TableBody extends Component {
|
||||
|
||||
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.thumbnail_url = item.encoded_thumbnail_src ? `${siteRoot}${item.encoded_thumbnail_src}` : '';
|
||||
@@ -165,7 +170,7 @@ class Item extends Component {
|
||||
{
|
||||
data.thumbnail_url ?
|
||||
<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>
|
||||
@@ -188,7 +193,7 @@ class Item extends Component {
|
||||
{
|
||||
data.thumbnail_url ?
|
||||
<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>
|
||||
|
@@ -229,6 +229,13 @@ export const Utils = {
|
||||
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) {
|
||||
let permission = repo.permission || repo.share_permission; //Compatible with regular repo and repo shared
|
||||
let size = Utils.isHiDPI() ? 48 : 24;
|
||||
|
@@ -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, \
|
||||
share_dir_to_group
|
||||
from seahub.constants import PERMISSION_READ
|
||||
from seahub.base.models import UserStarredFiles
|
||||
from seahub.base.templatetags.seahub_tags import email2nickname, \
|
||||
email2contact_email
|
||||
|
||||
@@ -69,6 +70,7 @@ class GroupLibraries(APIView):
|
||||
"""
|
||||
|
||||
# only group member can get group libraries
|
||||
username = request.user.username
|
||||
if not is_group_member(group_id, request.user.username):
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
@@ -113,6 +115,13 @@ class GroupLibraries(APIView):
|
||||
else:
|
||||
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 = []
|
||||
for group_repo in group_repos:
|
||||
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_contact_email'] = contact_email_dict.get(modifier, '')
|
||||
|
||||
group_repo_info['starred'] = group_repo.id in starred_repo_id_list
|
||||
|
||||
result.append(group_repo_info)
|
||||
|
||||
return Response(result)
|
||||
|
@@ -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, \
|
||||
group_id_to_name
|
||||
from seahub.group.views import remove_group_common
|
||||
from seahub.base.models import UserStarredFiles
|
||||
from seahub.base.templatetags.seahub_tags import email2nickname, \
|
||||
translate_seahub_time, email2contact_email
|
||||
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]
|
||||
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:
|
||||
group_info = get_group_info(request, g.id, avatar_size)
|
||||
|
||||
@@ -170,7 +178,8 @@ class Groups(APIView):
|
||||
"owner_email": repo_owner,
|
||||
"owner_name": name_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)
|
||||
|
||||
|
@@ -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.base.models import UserStarredFiles
|
||||
from seahub.base.templatetags.seahub_tags import email2nickname, \
|
||||
email2contact_email
|
||||
from seahub.signals import repo_deleted
|
||||
@@ -71,8 +72,16 @@ class ReposView(APIView):
|
||||
if is_org_context(request):
|
||||
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 = []
|
||||
if filter_by['mine']:
|
||||
|
||||
if org_id:
|
||||
owned_repos = seafile_api.get_org_owned_repo_list(org_id,
|
||||
email, ret_corrupted=True)
|
||||
@@ -109,6 +118,7 @@ class ReposView(APIView):
|
||||
"size": r.size,
|
||||
"encrypted": r.encrypted,
|
||||
"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:
|
||||
@@ -169,6 +179,7 @@ class ReposView(APIView):
|
||||
"size": r.size,
|
||||
"encrypted": r.encrypted,
|
||||
"permission": r.permission,
|
||||
"starred": r.repo_id in starred_repo_id_list,
|
||||
}
|
||||
|
||||
if r.repo_id in repos_with_admin_share_to:
|
||||
@@ -210,6 +221,7 @@ class ReposView(APIView):
|
||||
"size": r.size,
|
||||
"encrypted": r.encrypted,
|
||||
"permission": r.permission,
|
||||
"starred": r.repo_id in starred_repo_id_list,
|
||||
}
|
||||
repo_info_list.append(repo_info)
|
||||
|
||||
@@ -252,6 +264,7 @@ class ReposView(APIView):
|
||||
"size": r.size,
|
||||
"encrypted": r.encrypted,
|
||||
"permission": r.permission,
|
||||
"starred": r.repo_id in starred_repo_id_list,
|
||||
}
|
||||
repo_info_list.append(repo_info)
|
||||
|
||||
|
@@ -149,6 +149,11 @@ class StarredFile(object):
|
||||
|
||||
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):
|
||||
|
||||
path_list = [normalize_file_path(path), normalize_dir_path(path)]
|
||||
|
Reference in New Issue
Block a user