-
-
Notifications
You must be signed in to change notification settings - Fork 33.1k
Fixed #8936 -- Added view permissions and a read-only admin [rebased] #6734
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
3d73f7a
to
080b79b
Compare
docs/ref/contrib/admin/index.txt
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1.11
0069d56
to
efcefb1
Compare
d3a2d76
to
52bbd3d
Compare
52bbd3d
to
f57acae
Compare
The test failures are: |
Did you fix #5297 (comment)? |
Hi, It seems these tests fail because of a newline in the template (to comply with flake) :
while this appears in the template :
An easy fix is to add the line break in the test, but this will fail again if the template gets changed. I see there's the |
{% block links %} | ||
{% if can_change_related %} | ||
<a class="related-widget-wrapper-link change-related" id="change_id_{{ name }}" | ||
{% if can_change_related or can_view_related%} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing space before "%}"
I don't have a strong opinion about how to fix that. |
f57acae
to
f6a70e5
Compare
Hi, I made the changes :
I intend to squash those latter commits if they look good to you. I suggest closing #5297 to avoid having comments at different places. I removed the patch needs improvement flag on the ticket. Let me know if I can do anything more for this ! |
There's a failing build, but it looks like it's travis fault : |
Rebase so the patch merges cleanly and squash commits (in general, there's no need to push incremental commits for minor changes; just squash right away). Of course with a patch of this size, after someday reviews the patch the first time , it might be useful to push incremental changes so they don't have to recheck the entire patch again. |
This will be a nice addition to the Django Admin. Can't wait to see it! |
578a3de
to
40b0d3c
Compare
Ok I think the PR is ready ! |
We've been testing this in our own admin site and found a couple of things:
I'll try and write a couple of failing test cases. |
Hi. It's awesome PR and I tried it with my existing web app and existing database.. I tried recreating the database and tried this feature, It worked with my app. |
@hirokiky: I see no reason why old existing apps cannot use this feature - the note states that backwards compatibility is maintained by ensuring that having a change permission also implicitly means that the user has the view permission for the same model. This is to avoid loss of access to pages in the admin site when Django is upgraded because users would not have the new view permissions by default. After upgrade change permissions can be removed and view permissions added as required. (It also rarely makes sense to be able to change something but not view it!) |
@pope1ni Yes. Admin pages can be seen for existing users. But with migrated DB, I can't apply anyway thank you. my comment was not enough. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @olivierdalang.
A couple of issues from more complex manual testing of the admin:
When you have no permissions at all, the Admin homepage says:
You don't have permission to edit anything.
Arguably, this should be updated to say "view or edit" or such.
More serious: there is an issue with TabularInline
.
If my user does not have the add
permission for the inline model, TabularInline
leads to an error when rendering the empty form. (KeyError
on missing field.)
- This works as expected with
StackedInline
. (The empty form simply isn't rendered.) - It's a regression from
master
, whereTabularInline
renders (as expected) without the empty form when user does not have theadd
permission.
Other than that, it's looking really good: combinations of permissions for different models in a inline etc all seem to behave as expected. Good stuff!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @olivierdalang.
Right, final pass. Thank you again for your effort on this. (I'm exhausted. 😵)
- Manual testing is great.
- The non-test changes look fine to me.
- Maybe others have a comment or two?
I pushed a couple of small edits. Please check. We can squash at the end.
I've left comments on the test cases to be addressed.
To highlight one, it's important that the case for the view only user is added to test_add_view
and test_delete_view
.
In each of those cases we check that the other permissions don't allow the action, and just as you've added it to test_change_view
we need it in those other places.
Beyond that there's two possible refactorings:
- Pull out the tests for the redirect behaviour on row level permissions.
- The above mentioned changes in
admin_changelist/tests.py
(to create the authenticated request etc.)
Neither of these are blockers for this PR. (They can go in separate commits in this PR or in separate PRs, if at all.)
Beyond that there remains:
- The release note changes as per the discussion above. (Nick is 100% right that you might have an existing
view
permission that might now allow an access to the admin.) - The crash using TabularInline without the
add
permission.
If we can get all this resolved I'll feel happy asking Tim to have a look.
Good stuff! 👍
tests/admin_views/tests.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use """
for docstrings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok
tests/admin_views/tests.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see the old tests do this, but (AFAICS) there's no reason to to store post_data
on self
. (It's not accessed outside this test case.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same post_data is used across other tests that use the same change form. If this is OK for you I'll leave it like this (more consistent with other tests)
tests/admin_views/tests.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.all()[0]
-> .first()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok
tests/admin_views/tests.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's this block testing? We just added the Widget. We don't have change
permission so we can't update it. (That's testing in the block below) So what's the purpose of this POST
?
Is it worth adding an assert against the location for the 302
responses?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed this doesn't test much... I can't see why it's there neither. I'll remove it.
I think it's worth testing the 302 response, as it may be that the query is successful, but redirects to a wrong page (e.g. if you don't have view permission and were redirected to change page, you'd get a 403)
tests/admin_views/tests.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to wrap this. 118 chars is fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok
tests/admin_views/tests.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be part of test_login
, directly above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok
tests/admin_views/admin.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per comments on test_change_view
and test_history_view
, I don't think this is really behaving in the expected way, or really testing the desired behaviour.
(TODO: pull out the row-level permissions parts of those tests in a separate commit, and then this can be skipped.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean a separate commit but still in the PR ? (or take it out of the PR altogether and leave a TODO note in the code ?)
tests/admin_filters/tests.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
alfred
is part of the data set. I think a separate self.superuser
would be more consistent with the other tests here.
(Otherwise we see request.user = self.alfred
in each method and wonder "Who's alfred
?")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I'll do that, but this induce some changes in the expected results from the queries in the tests (the commit may be a bit confusing because of that). Let me know if you think it's worth the change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks OK on manual testing.
- I have a user with
add
andview
permissions on X - I add an X, using the "Save and continue" button.
- I'm redirected to the same page to view the object. Only option is "Close without saving".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Except the message displayed isn't quite right in this case:
The X "Great new X" was added successfully. You may edit it again below.
It's not true that it may be edited.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've had another pass through this and picked up a number of issue by inspection of the code.
django/contrib/admin/helpers.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we not just extend self.readonly_fields
and not add the extra self.viewonly_fields
?
Also, this line will likely result in duplicate column names - I'm not sure that necessarily matters here, but it's not very tidy...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't just extend it, because they are different depending on if we are in extra rows (with the add permission, where unless a field is explicitly readonly, you can still change it) or if we are in existing rows (where all fields are readonly if we don't have the change permission).
Still that's not very clear in the code isn't very clear and I'll refactor so it's more readable.
django/contrib/admin/options.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor rephrasing: ... and the user does not have permission ...
Also, typo: exlcude
→ exclude
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok
django/contrib/admin/options.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not necessary to pass None
here.
I think the comment is obsolete as the code is descriptive enough and this should probably just be rolled into the above if statement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok
django/contrib/admin/options.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename this variable to readonly_fields
. Let's not pollute the code with three things that mean the same thing, i.e. the uneditable_fields
here and the aforementioned viewonly_fields
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok
django/contrib/admin/options.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, it shouldn't be necessary to provide None
here? (I realise that the existing version of this line did so.)
Please fix all cases of this, but only for lines modified by this PR. Other cases can be dealt with by a separate PR some other time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this added?
Did you intend to remove line-height
(and other) properties with the same values from later rules?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's just so that the close button (which is an unlike other buttons that are ) displays the same way than the rest of the buttons
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You where right, it wasn't really needed... anyways I just refactored the css a little bit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this render as "Close without saving" if we only have view permissions and this cannot save anyway?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think it's better to be clear that there's no saving going on despite clicking a button that's located where the close buttons usually are.
I think it stays quite clear for the user, because that button only appears if there's no editable form on the page anyways.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thinking about this again, my point was that "Save and continue" doesn't make sense if you only have the add permission without view or change also.
Before you had to have the change permission. Now it ought to be change or view, but has been changed to use can_save
which allows just having the add permission.
This makes no sense. Either we then have to redirect somewhere else other than the change/view view making the behaviour different, i.e. the same as the "Save" button, or we redirect and get a permission denied error.
I haven't tested these scenarios, but just by inspection of the code, it is clear we are changing the expected behaviour here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please rephrase the comment to avoid personal pronouns.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
About the save and continue: I'll change it so that it only appears when the user can change, and to reword to "Save and view" if the user can only view (good catch !)
tests/admin_views/admin.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parentheses on this line are unnecessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok (that was copied from just above, I'm never sure if it's better to keep resemblance with existing code for consistency or do things right)
Thanks for the detailed review !! I'll try to find some time next week to deal with them. |
I made some progress on this. I still need to address the refactoring of the tests cases, and to address #6734 (comment) but for the rest, it should be good. I hope I didn't miss any comment, this whole PR is getting quite confusing :-) I left everything as separated commits to facilitate review but of course will squash. Thanks again for your excellent inputs !! |
Hi @olivierdalang. Thanks for the effort.
Yes. And there are so many comments now that it's taking (me at least) multiple refreshes to load. It looks to me as if there are a number of comments not yet addressed. Please take the time to make sure each one is handled. (I don't think we're far off now. 💃🏼) |
3ee7828
to
8211bc3
Compare
Another round done... I hope I didn't miss anything. Those may need some additional review (not always sure of the amendments, mostly about test case style) : Hehe I'll make sure to have a bottle of champagne ready for when this gets merged (if it gets merged) !! |
8211bc3
to
ab56fa3
Compare
5159d29
to
3d2e98d
Compare
Hi @olivierdalang. Thanks for the super effort here!
It should get merged. It works. And it's been a long-time on the wish list. We just have to cover all the bases. Thank you for all your edits. I'd gone through. It looks like you've addressed each point. As such I've squashed and rebased the PR. Of the outstanding points:
@pope1ni: I looked at the |
@carltongibson @pope1ni |
Hi @olivierdalang. Sorry for the delay: I was away. I squashed and rebased last week, so nothing to do there. I've marked this as Ready for checkin on the ticket. Tim will have a look next: it's a big patch, with potential security issues, so it justifies another review. Tim, with fresh eyes, will likely make a few more suggestions. I think we've gone over the main scenarios well enough (POSTing data, accessing inlines etc) so hopefully these will just be minor. On that assumption we should be able to get it in. 💃🏼 (But lets await Tim's review.) Thanks for your super effort here. This has been a long time on the wish-list! |
3d2e98d
to
326a76b
Compare
Great ! I just redid the commit so that it's properly attributed to @PetrDlouhy (original author) and me. |
d55c15d
to
54ba557
Compare
Will this get accepted for the feature freeze (which seems to be today)? |
Hi All. I tried this out and it seems to work as expected for me. One point of feedback, feel free to ignore if you want: I think the button "Close without saving" is a little confusing. It's not like you would ever have any changes that will get discarded, right? Maybe we could say "back to list page" (or have no button at all)? In any case. This is awesome. Thanks so much! |
I changed that to say "Close" in my edits that I haven't pushed yet.
… |
3ff0d40
to
1869ca2
Compare
Co-authored-by: Petr Dlouhy <[email protected]> Co-authored-by: Olivier Dalang <[email protected]>
1869ca2
to
825f0be
Compare
Yeaaah !!! Finally :D Thank you all !!! |
Do you have time to add additional tests as described on the ticket?
…On Wed, May 16, 2018 at 6:59 PM olivierdalang ***@***.***> wrote:
Yeaaah !!! Finally :D
Thank you all !!!
—
You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub
<#6734 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAZI3UoXP9AwxjAWfeK46a5dxmTR558-ks5tzK88gaJpZM4IvDfv>
.
|
Hi,
This is just a rebase of #5297
The only difference (besides fixing the merge conflicts) is that
ModelAdmin.declared_fieldsets
doesn't exist anymore and was replaced byget_fieldsets
.Thanks,
Olivier