mirror of
https://github.com/haiwen/seahub.git
synced 2025-08-16 06:03:35 +00:00
Merge branch '7.0'
This commit is contained in:
commit
7f49eab2c7
@ -77,6 +77,7 @@ class Account extends Component {
|
|||||||
quotaUsage: Utils.bytesToSize(resp.data.usage),
|
quotaUsage: Utils.bytesToSize(resp.data.usage),
|
||||||
quotaTotal: Utils.bytesToSize(resp.data.total),
|
quotaTotal: Utils.bytesToSize(resp.data.total),
|
||||||
isStaff: resp.data.is_staff,
|
isStaff: resp.data.is_staff,
|
||||||
|
isInstAdmin: resp.data.is_inst_admin,
|
||||||
isOrgStaff: resp.data.is_org_staff === 1 ? true : false,
|
isOrgStaff: resp.data.is_org_staff === 1 ? true : false,
|
||||||
showInfo: !this.state.showInfo,
|
showInfo: !this.state.showInfo,
|
||||||
});
|
});
|
||||||
@ -91,29 +92,47 @@ class Account extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderMenu = () => {
|
renderMenu = () => {
|
||||||
if (this.state.isStaff && this.props.isAdminPanel) {
|
let data;
|
||||||
return (
|
const { isStaff, isOrgStaff, isInstAdmin } = this.state;
|
||||||
<a href={siteRoot} title={gettext('Exit Admin Panel')} className="item">{gettext('Exit Admin Panel')}</a>
|
|
||||||
);
|
if (this.props.isAdminPanel) {
|
||||||
|
if (isStaff) {
|
||||||
|
data = {
|
||||||
|
url: siteRoot,
|
||||||
|
text: gettext('Exit System Admin')
|
||||||
|
};
|
||||||
|
} else if (isOrgStaff) {
|
||||||
|
data = {
|
||||||
|
url: siteRoot,
|
||||||
|
text: gettext('Exit Organization Admin')
|
||||||
|
};
|
||||||
|
} else if (isInstAdmin) {
|
||||||
|
data = {
|
||||||
|
url: siteRoot,
|
||||||
|
text: gettext('Exit Institution Admin')
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (isStaff) {
|
||||||
|
data = {
|
||||||
|
url: `${siteRoot}sys/useradmin/`,
|
||||||
|
text: gettext('System Admin')
|
||||||
|
};
|
||||||
|
} else if (isOrgStaff) {
|
||||||
|
data = {
|
||||||
|
url: `${siteRoot}org/useradmin/`,
|
||||||
|
text: gettext('Organization Admin')
|
||||||
|
};
|
||||||
|
} else if (isInstAdmin) {
|
||||||
|
data = {
|
||||||
|
url: `${siteRoot}inst/useradmin/`,
|
||||||
|
text: gettext('Institution Admin')
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state.isOrgStaff && this.props.isAdminPanel) {
|
return data && <a href={data.url} title={data.text} className="item">{data.text}</a>;
|
||||||
return (
|
|
||||||
<a href={siteRoot} title={gettext('Exit Organization Admin')} className="item">{gettext('Exit Organization Admin')}</a>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.state.isStaff) {
|
|
||||||
return (
|
|
||||||
<a href={siteRoot + 'sys/useradmin/'} title={gettext('System Admin')} className="item">{gettext('System Admin')}</a>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.state.isOrgStaff) {
|
|
||||||
return (
|
|
||||||
<a href={siteRoot + 'org/useradmin/'} title={gettext('Organization Admin')} className="item">{gettext('Organization Admin')}</a>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderAvatar = () => {
|
renderAvatar = () => {
|
||||||
|
@ -8,7 +8,7 @@ import { Utils } from '../utils/utils';
|
|||||||
import toaster from './toast';
|
import toaster from './toast';
|
||||||
import Group from '../models/group';
|
import Group from '../models/group';
|
||||||
|
|
||||||
import { canViewOrg, isDocs, isPro } from '../utils/constants';
|
import { canViewOrg, isDocs, isPro, customNavItems } from '../utils/constants';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
currentTab: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
currentTab: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
||||||
@ -164,6 +164,21 @@ class MainSideNav extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderCustomNavItems() {
|
||||||
|
return (
|
||||||
|
customNavItems.map((item, idx) => {
|
||||||
|
return (
|
||||||
|
<li key={idx} className="nav-item">
|
||||||
|
<a href={item.link} className="nav-link ellipsis" title={item.desc}>
|
||||||
|
<span className={item.icon} aria-hidden="true"></span>
|
||||||
|
<span className="nav-text">{item.desc}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let showActivity = isDocs || isPro;
|
let showActivity = isDocs || isPro;
|
||||||
return (
|
return (
|
||||||
@ -261,6 +276,7 @@ class MainSideNav extends React.Component {
|
|||||||
</a>
|
</a>
|
||||||
{this.renderSharedAdmin()}
|
{this.renderSharedAdmin()}
|
||||||
</li>
|
</li>
|
||||||
|
{customNavItems && this.renderCustomNavItems()}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ export const repoPasswordMinLength = window.app.pageOptions.repoPasswordMinLengt
|
|||||||
export const canAddPublicRepo = window.app.pageOptions.canAddPublicRepo;
|
export const canAddPublicRepo = window.app.pageOptions.canAddPublicRepo;
|
||||||
export const canInvitePeople = window.app.pageOptions.canInvitePeople;
|
export const canInvitePeople = window.app.pageOptions.canInvitePeople;
|
||||||
export const canLockUnlockFile = window.app.pageOptions.canLockUnlockFile;
|
export const canLockUnlockFile = window.app.pageOptions.canLockUnlockFile;
|
||||||
|
export const customNavItems = window.app.pageOptions.customNavItems;
|
||||||
|
|
||||||
export const curNoteMsg = window.app.pageOptions.curNoteMsg;
|
export const curNoteMsg = window.app.pageOptions.curNoteMsg;
|
||||||
export const curNoteID = window.app.pageOptions.curNoteID;
|
export const curNoteID = window.app.pageOptions.curNoteID;
|
||||||
|
Binary file not shown.
@ -351,8 +351,17 @@ class RepoView(APIView):
|
|||||||
|
|
||||||
repo = seafile_api.get_repo(repo_id)
|
repo = seafile_api.get_repo(repo_id)
|
||||||
if not repo:
|
if not repo:
|
||||||
error_msg = 'Library %s not found.' % repo_id
|
# for case of `seafile-data` has been damaged
|
||||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
# no `repo object` will be returned from seafile api
|
||||||
|
# delete the database record anyway
|
||||||
|
try:
|
||||||
|
seafile_api.remove_repo(repo_id)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
error_msg = 'Internal Server Error'
|
||||||
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||||
|
|
||||||
|
return Response({'success': True})
|
||||||
|
|
||||||
# check permission
|
# check permission
|
||||||
username = request.user.username
|
username = request.user.username
|
||||||
|
@ -329,6 +329,9 @@ class AccountInfo(APIView):
|
|||||||
info['institution'] = p.institution if p and p.institution else ""
|
info['institution'] = p.institution if p and p.institution else ""
|
||||||
info['is_staff'] = request.user.is_staff
|
info['is_staff'] = request.user.is_staff
|
||||||
|
|
||||||
|
if getattr(settings, 'MULTI_INSTITUTION', False):
|
||||||
|
info['is_inst_admin'] = request.user.inst_admin
|
||||||
|
|
||||||
interval = UserOptions.objects.get_file_updates_email_interval(email)
|
interval = UserOptions.objects.get_file_updates_email_interval(email)
|
||||||
info['email_notification_interval'] = 0 if interval is None else interval
|
info['email_notification_interval'] = 0 if interval is None else interval
|
||||||
return info
|
return info
|
||||||
|
@ -16,6 +16,7 @@ class InstitutionMiddleware(object):
|
|||||||
try:
|
try:
|
||||||
inst_admin = InstitutionAdmin.objects.get(user=username)
|
inst_admin = InstitutionAdmin.objects.get(user=username)
|
||||||
except InstitutionAdmin.DoesNotExist:
|
except InstitutionAdmin.DoesNotExist:
|
||||||
|
request.user.inst_admin = False
|
||||||
return None
|
return None
|
||||||
|
|
||||||
request.user.institution = inst_admin.institution
|
request.user.institution = inst_admin.institution
|
||||||
|
@ -63,8 +63,10 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
logger.debug('Start sending file updates emails...')
|
logger.debug('Start sending file updates emails...')
|
||||||
|
self.stdout.write('[%s] Start sending file updates emails...' % str(datetime.now()))
|
||||||
self.do_action()
|
self.do_action()
|
||||||
logger.debug('Finish sending file updates emails.\n')
|
logger.debug('Finish sending file updates emails.\n')
|
||||||
|
self.stdout.write('[%s] Finish sending file updates emails.\n\n' % str(datetime.now()))
|
||||||
|
|
||||||
def get_avatar(self, username, default_size=32):
|
def get_avatar(self, username, default_size=32):
|
||||||
img_tag = avatar(username, default_size)
|
img_tag = avatar(username, default_size)
|
||||||
@ -176,9 +178,6 @@ class Command(BaseCommand):
|
|||||||
return (op, details)
|
return (op, details)
|
||||||
|
|
||||||
def do_action(self):
|
def do_action(self):
|
||||||
today = datetime.utcnow().replace(hour=0).replace(minute=0).replace(
|
|
||||||
second=0).replace(microsecond=0)
|
|
||||||
|
|
||||||
emails = []
|
emails = []
|
||||||
user_file_updates_email_intervals = []
|
user_file_updates_email_intervals = []
|
||||||
for ele in UserOptions.objects.filter(
|
for ele in UserOptions.objects.filter(
|
||||||
@ -190,6 +189,7 @@ class Command(BaseCommand):
|
|||||||
emails.append(ele.email)
|
emails.append(ele.email)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
|
self.stderr.write('[%s]: %s' % (str(datetime.now()), e))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
user_last_emailed_time_dict = {}
|
user_last_emailed_time_dict = {}
|
||||||
@ -201,6 +201,7 @@ class Command(BaseCommand):
|
|||||||
ele.option_val, "%Y-%m-%d %H:%M:%S")
|
ele.option_val, "%Y-%m-%d %H:%M:%S")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
|
self.stderr.write('[%s]: %s' % (str(datetime.now()), e))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for (username, interval_val) in user_file_updates_email_intervals:
|
for (username, interval_val) in user_file_updates_email_intervals:
|
||||||
@ -212,14 +213,18 @@ class Command(BaseCommand):
|
|||||||
translation.activate(user_language)
|
translation.activate(user_language)
|
||||||
logger.debug('Set language code to %s for user: %s' % (
|
logger.debug('Set language code to %s for user: %s' % (
|
||||||
user_language, username))
|
user_language, username))
|
||||||
self.stdout.write('[%s] Set language code to %s' % (
|
self.stdout.write('[%s] Set language code to %s for user: %s' % (
|
||||||
str(datetime.now()), user_language))
|
str(datetime.now()), user_language, username))
|
||||||
|
|
||||||
# get last_emailed_time if any, defaults to today
|
# get last_emailed_time if any, defaults to today 00:00:00.0
|
||||||
last_emailed_time = user_last_emailed_time_dict.get(username, today)
|
last_emailed_time = user_last_emailed_time_dict.get(username, None)
|
||||||
now = datetime.utcnow().replace(microsecond=0)
|
now = datetime.utcnow().replace(microsecond=0)
|
||||||
if (now - last_emailed_time).seconds < interval_val:
|
if not last_emailed_time:
|
||||||
continue
|
last_emailed_time = datetime.utcnow().replace(hour=0).replace(
|
||||||
|
minute=0).replace(second=0).replace(microsecond=0)
|
||||||
|
else:
|
||||||
|
if (now - last_emailed_time).total_seconds() < interval_val:
|
||||||
|
continue
|
||||||
|
|
||||||
# get file updates(from: last_emailed_time, to: now) for repos
|
# get file updates(from: last_emailed_time, to: now) for repos
|
||||||
# user can access
|
# user can access
|
||||||
@ -245,6 +250,9 @@ class Command(BaseCommand):
|
|||||||
logger.error('Failed to format mail content for user: %s' %
|
logger.error('Failed to format mail content for user: %s' %
|
||||||
username)
|
username)
|
||||||
logger.error(e, exc_info=True)
|
logger.error(e, exc_info=True)
|
||||||
|
self.stderr.write('[%s] Failed to format mail content for user: %s' %
|
||||||
|
(str(datetime.now()), username))
|
||||||
|
self.stderr.write('[%s]: %s' % (str(datetime.now()), e))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
nickname = email2nickname(username)
|
nickname = email2nickname(username)
|
||||||
@ -263,11 +271,13 @@ class Command(BaseCommand):
|
|||||||
# set new last_emailed_time
|
# set new last_emailed_time
|
||||||
UserOptions.objects.set_file_updates_last_emailed_time(
|
UserOptions.objects.set_file_updates_last_emailed_time(
|
||||||
username, now)
|
username, now)
|
||||||
|
self.stdout.write('[%s] Successful to send email to %s' %
|
||||||
|
(str(datetime.now()), contact_email))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error('Failed to send email to %s, error detail: %s' %
|
logger.error('Failed to send email to %s, error detail: %s' %
|
||||||
(contact_email, e))
|
(contact_email, e))
|
||||||
self.stderr.write('[%s] Failed to send email to %s, error '
|
self.stderr.write('[%s] Failed to send email to %s, error '
|
||||||
'detail: %s' % (str(now), contact_email, e))
|
'detail: %s' % (str(datetime.now()), contact_email, e))
|
||||||
finally:
|
finally:
|
||||||
# reset lang
|
# reset lang
|
||||||
translation.activate(cur_language)
|
translation.activate(cur_language)
|
||||||
|
@ -902,3 +902,14 @@ if ENABLE_REMOTE_USER_AUTHENTICATION:
|
|||||||
|
|
||||||
if ENABLE_OAUTH or ENABLE_WORK_WEIXIN:
|
if ENABLE_OAUTH or ENABLE_WORK_WEIXIN:
|
||||||
AUTHENTICATION_BACKENDS += ('seahub.oauth.backends.OauthRemoteUserBackend',)
|
AUTHENTICATION_BACKENDS += ('seahub.oauth.backends.OauthRemoteUserBackend',)
|
||||||
|
|
||||||
|
#####################
|
||||||
|
# Custom Nav Items #
|
||||||
|
#####################
|
||||||
|
# an example:
|
||||||
|
# CUSTOM_NAV_ITEMS = [
|
||||||
|
# {'icon': 'sf2-icon-star',
|
||||||
|
# 'desc': 'test custom name',
|
||||||
|
# 'link': 'http://127.0.0.1:8000/shared-libs/',
|
||||||
|
# },
|
||||||
|
# ]
|
||||||
|
@ -91,9 +91,10 @@
|
|||||||
repoPasswordMinLength: {{repo_password_min_length}},
|
repoPasswordMinLength: {{repo_password_min_length}},
|
||||||
canAddPublicRepo: {% if can_add_public_repo %} true {% else %} false {% endif %},
|
canAddPublicRepo: {% if can_add_public_repo %} true {% else %} false {% endif %},
|
||||||
canInvitePeople: {% if enable_guest_invitation and user.permissions.can_invite_guest %} true {% else %} false {% endif %},
|
canInvitePeople: {% if enable_guest_invitation and user.permissions.can_invite_guest %} true {% else %} false {% endif %},
|
||||||
|
customNavItems: {% if custom_nav_items %} JSON.parse('{{ custom_nav_items | escapejs }}') {% else %} {{'[]'}} {% endif %},
|
||||||
|
|
||||||
{% if request.user.is_authenticated and request.cur_note %}
|
{% if request.user.is_authenticated and request.cur_note %}
|
||||||
curNoteMsg: '{{ request.cur_note.message|urlize }}',
|
curNoteMsg: '{{ request.cur_note.message|urlize|escapejs }}',
|
||||||
curNoteID: '{{ request.cur_note.id }}',
|
curNoteID: '{{ request.cur_note.id }}',
|
||||||
{% endif %}
|
{% endif %}
|
||||||
}
|
}
|
||||||
|
@ -63,6 +63,7 @@ from seahub.onlyoffice.settings import ENABLE_ONLYOFFICE
|
|||||||
from seahub.constants import HASH_URLS, PERMISSION_READ
|
from seahub.constants import HASH_URLS, PERMISSION_READ
|
||||||
|
|
||||||
LIBRARY_TEMPLATES = getattr(settings, 'LIBRARY_TEMPLATES', {})
|
LIBRARY_TEMPLATES = getattr(settings, 'LIBRARY_TEMPLATES', {})
|
||||||
|
CUSTOM_NAV_ITEMS = getattr(settings, 'CUSTOM_NAV_ITEMS', '')
|
||||||
|
|
||||||
from constance import config
|
from constance import config
|
||||||
|
|
||||||
@ -1267,7 +1268,8 @@ def react_fake_view(request, **kwargs):
|
|||||||
'is_email_configured': IS_EMAIL_CONFIGURED,
|
'is_email_configured': IS_EMAIL_CONFIGURED,
|
||||||
'can_add_public_repo': request.user.permissions.can_add_public_repo(),
|
'can_add_public_repo': request.user.permissions.can_add_public_repo(),
|
||||||
'folder_perm_enabled': folder_perm_enabled,
|
'folder_perm_enabled': folder_perm_enabled,
|
||||||
'file_audit_enabled' : FILE_AUDIT_ENABLED
|
'file_audit_enabled' : FILE_AUDIT_ENABLED,
|
||||||
|
'custom_nav_items' : json.dumps(CUSTOM_NAV_ITEMS),
|
||||||
})
|
})
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
Loading…
Reference in New Issue
Block a user