diff --git a/wagtail/wagtailadmin/forms.py b/wagtail/wagtailadmin/forms.py index 4f10de773..07a6eb7e1 100644 --- a/wagtail/wagtailadmin/forms.py +++ b/wagtail/wagtailadmin/forms.py @@ -128,7 +128,7 @@ class CopyForm(forms.Form): self.fields['new_parent_page'] = forms.ModelChoiceField( initial=self.page.get_parent(), queryset=Page.objects.all(), - widget=widgets.AdminPageChooser(can_choose_root=True), + widget=widgets.AdminPageChooser(can_choose_root=True, user_perms='copy_to'), label=_("New parent page"), help_text=_("This copy will be a child of this given parent page.") ) diff --git a/wagtail/wagtailadmin/static_src/wagtailadmin/js/page-chooser.js b/wagtail/wagtailadmin/static_src/wagtailadmin/js/page-chooser.js index e2919d3f3..4a496e62a 100644 --- a/wagtail/wagtailadmin/static_src/wagtailadmin/js/page-chooser.js +++ b/wagtail/wagtailadmin/static_src/wagtailadmin/js/page-chooser.js @@ -1,4 +1,4 @@ -function createPageChooser(id, pageTypes, openAtParentId, canChooseRoot) { +function createPageChooser(id, pageTypes, openAtParentId, canChooseRoot, userPerms) { var chooserElement = $('#' + id + '-chooser'); var pageTitle = chooserElement.find('.title'); var input = $('#' + id); @@ -14,6 +14,9 @@ function createPageChooser(id, pageTypes, openAtParentId, canChooseRoot) { if (canChooseRoot) { urlParams.can_choose_root = 'true'; } + if (userPerms) { + urlParams.user_perms = userPerms; + } ModalWorkflow({ url: initialUrl, diff --git a/wagtail/wagtailadmin/views/chooser.py b/wagtail/wagtailadmin/views/chooser.py index 1b21fad6b..42bd08971 100644 --- a/wagtail/wagtailadmin/views/chooser.py +++ b/wagtail/wagtailadmin/views/chooser.py @@ -9,7 +9,7 @@ from wagtail.utils.pagination import paginate from wagtail.wagtailadmin.forms import EmailLinkChooserForm, ExternalLinkChooserForm, SearchForm from wagtail.wagtailadmin.modal_workflow import render_modal_workflow from wagtail.wagtailcore import hooks -from wagtail.wagtailcore.models import Page +from wagtail.wagtailcore.models import Page, UserPagePermissionsProxy from wagtail.wagtailcore.utils import resolve_model_string @@ -51,10 +51,27 @@ def filter_page_type(queryset, page_models): return qs +def can_choose_page(page, permission_proxy, desired_classes, can_choose_root=True, user_perm=None): + """Returns boolean indicating of the user can choose page. + will check if the root page can be selected and if user permissions + should be checked. + """ + if not issubclass(page.specific_class or Page, desired_classes) and not desired_classes == (Page, ): + return False + elif not can_choose_root and page.is_root(): + return False + if user_perm == 'copy_to': + return permission_proxy.for_page(page).can_add_subpage() + + return True + + def browse(request, parent_page_id=None): # A missing or empty page_type parameter indicates 'all page types' # (i.e. descendants of wagtailcore.page) page_type_string = request.GET.get('page_type') or 'wagtailcore.page' + user_perm = request.GET.get('user_perms', False) + try: desired_classes = page_models_from_string(page_type_string) except (ValueError, LookupError): @@ -91,11 +108,12 @@ def browse(request, parent_page_id=None): can_choose_root = request.GET.get('can_choose_root', False) + # Do permission lookups for this user now, instead of for every page. + permission_proxy = UserPagePermissionsProxy(request.user) + # Parent page can be chosen if it is a instance of desired_classes - parent_page.can_choose = ( - issubclass(parent_page.specific_class or Page, desired_classes) and - (can_choose_root or not parent_page.is_root()) - ) + parent_page.can_choose = can_choose_page( + parent_page, permission_proxy, desired_classes, can_choose_root, user_perm) # Pagination # We apply pagination first so we don't need to walk the entire list @@ -104,11 +122,7 @@ def browse(request, parent_page_id=None): # Annotate each page with can_choose/can_decend flags for page in pages: - if desired_classes == (Page, ): - page.can_choose = True - else: - page.can_choose = issubclass(page.specific_class or Page, desired_classes) - + page.can_choose = can_choose_page(page, permission_proxy, desired_classes, can_choose_root, user_perm) page.can_descend = page.get_children_count() # Render diff --git a/wagtail/wagtailadmin/widgets.py b/wagtail/wagtailadmin/widgets.py index 8718dafe1..d3069e288 100644 --- a/wagtail/wagtailadmin/widgets.py +++ b/wagtail/wagtailadmin/widgets.py @@ -155,7 +155,7 @@ class AdminPageChooser(AdminChooser): choose_another_text = _('Choose another page') link_to_chosen_text = _('Edit this page') - def __init__(self, target_models=None, can_choose_root=False, **kwargs): + def __init__(self, target_models=None, can_choose_root=False, user_perms=None, **kwargs): super(AdminPageChooser, self).__init__(**kwargs) if target_models: @@ -163,6 +163,7 @@ class AdminPageChooser(AdminChooser): if models: self.choose_one_text += ' (' + models + ')' + self.user_perms = user_perms self.target_models = list(target_models or [Page]) self.can_choose_root = can_choose_root @@ -202,7 +203,7 @@ class AdminPageChooser(AdminChooser): parent = page.get_parent() if page else None - return "createPageChooser({id}, {model_names}, {parent}, {can_choose_root});".format( + return "createPageChooser({id}, {model_names}, {parent}, {can_choose_root}, {user_perms});".format( id=json.dumps(id_), model_names=json.dumps([ '{app}.{model}'.format( @@ -211,7 +212,8 @@ class AdminPageChooser(AdminChooser): for model in self.target_models ]), parent=json.dumps(parent.id if parent else None), - can_choose_root=('true' if self.can_choose_root else 'false') + can_choose_root=('true' if self.can_choose_root else 'false'), + user_perms=json.dumps(self.user_perms), )