Skip to content
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

Merged
merged 4 commits into from May 27, 2018

Conversation

DubeySandeep
Copy link
Member

Explanation

  • Milestone 1.1:
    • Adding “translator” role for the exploration.
    • Adding new entity translator_ids in ExplorationSummary and ActivityRights object.
    • Adding translator_ids in ExplorationSummaryModel and ExplorationRightsModel.
    • Writing @acl_decorators for can_translate_exploration.

Checklist

  • The PR title starts with "Fix #bugnum: ", followed by a short, clear summary of the changes.
  • The PR explanation includes the words "Fixes #bugnum: ...".
  • The linter/Karma presubmit checks have passed.
    • These should run automatically, but if not, you can manually trigger them locally using python scripts/pre_commit_linter.py and bash scripts/run_frontend_tests.sh.
  • The PR is made from a branch that's not called "develop".
  • The PR follows the style guide.
  • The PR is assigned to an appropriate reviewer.
    • If you're a new contributor, please ask on Gitter for someone to assign a reviewer.
    • If you're not sure who the appropriate reviewer is, please assign to the issue's "owner" -- see the "talk-to" label on the issue.

@codecov-io
Copy link

codecov-io commented May 20, 2018

Codecov Report

Merging #4959 into develop will increase coverage by 0.07%.
The diff coverage is n/a.

Impacted file tree graph

@@             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
Impacted Files Coverage Δ
...v/head/pages/learner_dashboard/LearnerDashboard.js 2.27% <0%> (-0.02%) ⬇️
...ev/head/domain/utilities/ImageFileObjectFactory.js 100% <0%> (ø)
...lates/dev/head/services/AssetsBackendApiService.js 69.56% <0%> (+9.56%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2a148f4...5562d02. Read the comment docs.

Copy link
Contributor

@tjiang11 tjiang11 left a 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):
Copy link
Contributor

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)?

Copy link
Member Author

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

@tjiang11 tjiang11 requested a review from seanlip May 23, 2018 05:54
Copy link
Member

@seanlip seanlip left a 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?

self.assertEqual(response.status_int, 401)
self.logout()

def test_admin_can_edit_private_exploration(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mean translate?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

self.assertEqual(response.status_int, 200)
self.logout()

def test_translator_can_translate_assigned_exploration(self):
Copy link
Member

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

Copy link
Member Author

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"?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

Copy link
Member Author

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:
Copy link
Member

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.

user_id: str or None. Id of the user.

Returns:
bool. Whether user is in activity translator.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in --> an

Copy link
Member Author

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:
Copy link
Member

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.

Copy link
Member Author

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?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think so.

@DubeySandeep
Copy link
Member Author

Adding @nithusha21 for reviewing acl_decorators_test.py files (for get_json usecase).

Copy link
Member

@seanlip seanlip left a 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!

@@ -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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

owners --> owner, ditto below.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Copy link
Contributor

@nithusha21 nithusha21 left a 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.

@@ -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):
Copy link
Contributor

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).

Copy link
Member

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?

Copy link
Member Author

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

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

if isinstance(exception, self.NotLoggedInException):
self.redirect(
current_user_services.create_login_url(self.request.uri))
return

@seanlip
Copy link
Member

seanlip commented May 24, 2018

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)?

@nithusha21
Copy link
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants