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
Add translator role for the exploration (M1.1 Lesson translation dashboard) #4959
Conversation
a5ee46c
to
486c962
Compare
486c962
to
2346d04
Compare
Codecov Report
@@ Coverage Diff @@
## develop #4959 +/- ##
===========================================
+ Coverage 44.48% 44.56% +0.07%
===========================================
Files 386 387 +1
Lines 23306 23345 +39
Branches 3790 3800 +10
===========================================
+ Hits 10367 10403 +36
- Misses 12939 12942 +3
Continue to review full report at Codecov.
|
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.
Thanks @DubeySandeep , sorry for the delay. I think this looks great, though it'd be best if @seanlip also takes a look since this PR's predecessor was originally rejected, and I'm not all that familiar with the ACL infrastructure.
Also, I'm not sure if this is complete since the ACL decorator isn't applied? Or is that to be done later?
@@ -438,6 +438,34 @@ def test_can_edit(self, exploration_id, **kwargs): | |||
return test_can_edit | |||
|
|||
|
|||
def can_translate_exploration(handler): |
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.
Just checking, where is this decorator going to be eventually placed (since it doesn't seem to be used in this PR other than in tests)?
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 will be used for translator's controllers (for uploading audio, making audio related changes in exploration). This is similar to can_edit_exploration
which is used in ExplorationHandler
of editor.py
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 good in general. I spotted some small things but nothing serious.
I assume the actions assigned to the role will go in a separate PR, with the migration of the exploration to split out the translatable components into a separate substructure?
core/domain/acl_decorators_test.py
Outdated
self.assertEqual(response.status_int, 401) | ||
self.logout() | ||
|
||
def test_admin_can_edit_private_exploration(self): |
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 translate?
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.
Done!
core/domain/acl_decorators_test.py
Outdated
self.assertEqual(response.status_int, 200) | ||
self.logout() | ||
|
||
def test_translator_can_translate_assigned_exploration(self): |
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.
maybe add another test to check they can't translate an exp that they aren't assigned to
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 to add "test_user_without_translator_role_of_exploration_cannot_translate_exploration"?
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
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.
Done!
if owner_viewer: | ||
raise utils.ValidationError( | ||
'A user cannot be both an owner and a viewer: %s' % | ||
owner_viewer) | ||
if editor_translator: |
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 forgot viewer_translator; there should be 4-choose-2 checks.
core/domain/rights_manager.py
Outdated
user_id: str or None. Id of the user. | ||
|
||
Returns: | ||
bool. Whether user is in activity translator. |
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.
in --> an
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.
Done! (similar changes in above docstrings)
if activity_rights is None: | ||
return False | ||
|
||
if role_services.ACTION_EDIT_OWNED_ACTIVITY not in user.actions: |
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 flow here seems a bit off to me. It assumes that it's impossible for a user to have ACTION_EDIT_ANY_ACTIVITY but not ACTION_EDIT_OWNED_ACTIVITY. While currently true, this is an implicit assumption.
So perhaps you should check the last couple of things (any activity, any public activity) first, so that you don't erroneously exit early.
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 found a similar flow for can_edit_activity
in the above definition, should I change that function too?
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 so.
Adding @nithusha21 for reviewing |
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 looks good except the missing test I mentioned. I defer to @nithusha21 on the get_json part of the review.
Thanks!
core/domain/rights_manager.py
Outdated
@@ -169,7 +175,7 @@ def is_owner(self, user_id): | |||
user_id: str or None. Id of the user. | |||
|
|||
Returns: | |||
bool. Whether user is in activity owners. | |||
bool. Whether user is an activity owners. |
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.
owners --> owner, ditto below.
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.
Done!
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 acl_decorator tests in general LGTM. Just one comment I had.
core/domain/acl_decorators_test.py
Outdated
@@ -206,43 +216,46 @@ def setUp(self): | |||
rights_manager.publish_collection(self.owner, self.published_col_id) | |||
|
|||
def test_guest_is_redirected_to_login_page(self): | |||
response = self.testapp.get( | |||
'/mock/%s' % self.published_col_id, expect_errors=True) | |||
with self.swap(self, 'testapp', self.mock_testapp): |
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 only need to swap when calling get_json. Here there is no need to swap. (ditto at other 302 responses)
Also just to note, @seanlip only 302 responses cannot be tested using get_json because it's a redirect and returns a html. So for now I think let's test 302 by directly calling self.testapp.get (or mock_testapp).
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 don't think I understand (conceptually, at least). If we make a GET JSON request, and it redirects, it seems to me that it should redirect to a JSON handler. Unless it redirects because the user doesn't have permission or something (maybe they aren't logged in)? Then in such cases I guess we should 404...
If this is the case, can we update the "check logged in" decorator to do different things based on whether the handler has json return type or not?
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.
@nithusha21& @seanlip, I found this:
here it says it will raise 401
oppia/core/controllers/base.py
Lines 102 to 103 in f11089b
class NotLoggedInException(Exception): | |
"""Error class for users that are not logged in (error code 401).""" |
but here it says it will send a redirect uri
oppia/core/controllers/base.py
Lines 447 to 450 in f11089b
if isinstance(exception, self.NotLoggedInException): | |
self.redirect( | |
current_user_services.create_login_url(self.request.uri)) | |
return |
The added test looks good to me, thanks @DubeySandeep. LGTM from my perspective. I think you just need to get confirmation from @nithusha21 on the get_json stuff. @nithusha21 can we file an issue to ensure 302 behaves correctly for json responses (see my note above)? |
The get_json parts LGTM. I'll file an issue regarding 302 responses. I think your point is valid about sending some other response codes for not logged in situations. |
Explanation
translator_ids
in ExplorationSummaryModel and ExplorationRightsModel.Checklist
python scripts/pre_commit_linter.py
andbash scripts/run_frontend_tests.sh
.