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

[BD-24] [TNL-7318] BB-2355: Move LTI configuration to models. #93

Conversation

giovannicimolin
Copy link
Contributor

@giovannicimolin giovannicimolin commented Jul 23, 2020

This PR moves the LTI configuration handling to a django model. All the settings are still stored in the XBlock, but the retrieving and instancing of LTI config is done through a Python API now.

Testing instructions:

  1. Checkout and install this branch.
  2. Set up a LTI 1.1 and a LTI 1.3 blocks in a course (follow the guide on https://github.com/edx/xblock-lti-consumer#testing-against-an-lti-provider).
  3. Test that LTI 1.1 works from the LMS and Studio.
  4. Test that LTI 1.3 launch works from LMS.
  5. Check on the LTI Configuration on Django admin.

Notes:
There's no new "features" here, and this is just laying the groundwork to support LTI Advantage extensions.
This is the first implementation step of #92.

Reviewers:

@openedx-webhooks
Copy link

Thanks for the pull request, @giovannicimolin! I've created BLENDED-504 to keep track of it in Jira. More details are on the BD-24 project page.

When this pull request is ready, tag your edX technical lead.

@openedx-webhooks openedx-webhooks added blended PR is managed through 2U's blended developmnt program needs triage labels Jul 23, 2020
@coveralls
Copy link

coveralls commented Jul 23, 2020

Coverage Status

Coverage decreased (-2.5%) to 95.194% when pulling 4a70705 on open-craft:giovanni/bb-2355-change-config-to-model into f0785c5 on edx:master.

@viadanna
Copy link
Contributor

@giovannicimolin I'm trying to test this PR on a master devstack but the XBlocks fails to load correctly after running migrations:

edx.devstack-master.studio |   File "/edx/app/edxapp/edx-platform/xblock-lti-consumer/lti_consumer/models.py", line 92, in _get_lti_1p1_consumer
edx.devstack-master.studio |     key, secret = block.lti_provider_key_secret
edx.devstack-master.studio |   File "/edx/app/edxapp/edx-platform/xblock-lti-consumer/lti_consumer/lti_xblock.py", line 657, in lti_provider_key_secret
edx.devstack-master.studio |     for lti_passport in self.course.lti_passports:
edx.devstack-master.studio |   File "/edx/app/edxapp/edx-platform/xblock-lti-consumer/lti_consumer/lti_xblock.py", line 650, in course
edx.devstack-master.studio |     return self.runtime.descriptor_runtime.modulestore.get_course(self.course_id)  # pylint: disable=no-member
edx.devstack-master.studio |   File "/edx/app/edxapp/edx-platform/common/lib/xmodule/xmodule/x_module.py", line 2025, in __getattr__
edx.devstack-master.studio |     return getattr(self._descriptor_system, name)
edx.devstack-master.studio | AttributeError: 'CachingDescriptorSystem' object has no attribute 'descriptor_runtime'

Any ideas what I'm doing wrong?

@giovannicimolin
Copy link
Contributor Author

@viadanna I've hit that issue too at first, then I reinstalled the block and cleaned up all pyc files and it started working again.

Copy link
Contributor

@viadanna viadanna left a comment

Choose a reason for hiding this comment

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

Good to go 👍

  • I tested this on my devstack and a sandbox for LTI1p3
  • I read through the code.

lti_consumer/api.py Show resolved Hide resolved
@giovannicimolin giovannicimolin force-pushed the giovanni/bb-2355-change-config-to-model branch 2 times, most recently from 8605ed4 to ac52bf2 Compare August 20, 2020 17:39
@giovannicimolin
Copy link
Contributor Author

@davestgermain @davidjoy I've rebased the PR bumped the version and squashed the commits. This is good to do.

Note that this will require running migrations on stage/production, so I'm not sure how we should roll-out this feature.

# In the future, the LTI configuration will be
# stored in this model in a JSON field.
# This field stores a UsageKey.
location = models.CharField(
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not use a UsageKeyField?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Much better! I though that this was part of the core, but it seems that I was wrong. I'll implement it.

(CONFIG_ON_XBLOCK, 'Configuration Stored on XBlock fields'),
]
config_store = models.CharField(
max_length=25,
Copy link
Contributor

Choose a reason for hiding this comment

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

As far as I know, there isn't any space advantage to making this field small.

"""
Return a class of LTI 1.1 consumer.

Not implemented yet.
Copy link
Contributor

Choose a reason for hiding this comment

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

It is implemented

get_lti_consumer
)

lti_config_id = get_or_create_local_lti_config(
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of having to get/create the lti_config_id and then immediately looking up the model by id, how about having something like get_lti_consumer(config_id=None, block=self), which will get_or_create the config and return the consumer? And since configuration is only on the block for now, you can avoid having to load the block again (in _load_block), since it's already being passed in.

blank=True,
)

def _load_block(self): # pragma: no cover
Copy link
Contributor

Choose a reason for hiding this comment

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

How about this instead? This way, you can set the block on the config if it's passed in to get_lti_consumer, otherwise it'll load the block.

@property
def block(self):
    block = getattr(self, '_block', None)
    if block is None:
        from xmodule.modulestore.django import modulestore
        block = self._block = modulestore().get_item(self.location)
    return block

@block.setter
def block(self, block):
    self._block = block

@giovannicimolin
Copy link
Contributor Author

@davestgermain I've implemented your review suggestions and added a few more tests, can you take a look again?

@davestgermain
Copy link
Contributor

@giovannicimolin looks good to me! Squash and merge 👍

This change moves the LTI configuration retrieval to
a Django model that will LTI configuration.
The current model proxies back the to blocks to keep
backwards compatibility.

See reasoning for change at:
https://github.com/edx/xblock-lti-consumer/blob/master/docs/decisions/0001-lti-extensions-plugin.rst
@giovannicimolin giovannicimolin force-pushed the giovanni/bb-2355-change-config-to-model branch from 08dfee6 to 4a70705 Compare August 26, 2020 20:39
@giovannicimolin
Copy link
Contributor Author

@davestgermain Done!

@davestgermain davestgermain merged commit 35cdddc into openedx:master Aug 27, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blended PR is managed through 2U's blended developmnt program merged
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants