Exemplo n.º 1
0
    def post_replace_result(self, score, result_data=None):
        '''
        POSTs the given score to the Tool Consumer with a replaceResult.

        OPTIONAL:
            result_data must be a dictionary
            Note: ONLY ONE of these values can be in the dict at a time,
            due to the Canvas specification.

            'text' : str text
            'url' : str url
        '''
        self.operation = REPLACE_REQUEST
        self.score = score
        self.result_data = result_data
        if result_data is not None:
            if len(result_data) > 1:
                error_msg = ('Dictionary result_data can only have one entry. '
                             '{0} entries were found.'.format(
                                 len(result_data)))
                raise InvalidLTIConfigError(error_msg)
            elif 'text' not in result_data and 'url' not in result_data:
                error_msg = ('Dictionary result_data can only have the key '
                             '"text" or the key "url".')
                raise InvalidLTIConfigError(error_msg)
            else:
                return self.post_outcome_request()
        else:
            return self.post_outcome_request()
Exemplo n.º 2
0
    def __init__(self, **kwargs):
        # Initialize all class accessors to None
        for attr in VALID_ATTRIBUTES:
            setattr(self, attr, None)

        # Store specified options in our options member
        for (key, val) in kwargs.iteritems():
            if key in VALID_ATTRIBUTES:
                setattr(self, key, val)
            else:
                raise InvalidLTIConfigError(
                    "Invalid outcome response option: {}".format(key))
Exemplo n.º 3
0
    def __init__(self, opts=defaultdict(lambda: None)):
        # Initialize all our accessors to None
        for attr in VALID_ATTRIBUTES:
            setattr(self, attr, None)

        # Store specified options in our accessors
        for (key, val) in opts.iteritems():
            if key in VALID_ATTRIBUTES:
                setattr(self, key, val)
            else:
                raise InvalidLTIConfigError(
                    "Invalid outcome request option: {}".format(key))
Exemplo n.º 4
0
    def generate_launch_data(self):
        # Validate params
        if not self.has_required_params():
            raise InvalidLTIConfigError(
                'ToolConsumer does not have all required attributes: consumer_key = %s, consumer_secret = %s, resource_link_id = %s, launch_url = %s'
                % (self.consumer_key, self.consumer_secret,
                   self.resource_link_id, self.launch_url))

        params = self.to_params()

        if not params.get('lit_version', None):
            params['lti_version'] = 'LTI-1.0'

        params['lti_message_type'] = 'basic-lti-launch-request'

        # Get new OAuth consumer
        consumer = oauth2.Consumer(key = self.consumer_key,\
                secret = self.consumer_secret)

        params.update({
            'oauth_nonce': str(generate_identifier()),
            'oauth_timestamp': str(int(time.time())),
            'oauth_scheme': 'body',
            'oauth_consumer_key': consumer.key
        })

        uri = urlparse.urlparse(self.launch_url)
        if uri.query != '':
            for param in uri.query.split('&'):
                key, val = param.split('=')
                if params.get(key) == None:
                    params[key] = str(val)

        request = oauth2.Request(method='POST',
                                 url=self.launch_url,
                                 parameters=params)

        signature_method = oauth2.SignatureMethod_HMAC_SHA1()
        request.sign_request(signature_method, consumer, None)

        # Request was made by an HTML form in the user's browser.
        # Return the dict of post parameters ready for embedding
        # in an html view.
        return_params = {}
        for key in request:
            if request[key] == None:
                return_params[key] = None
            elif isinstance(request[key], list):
                return_params[key] = request.get_parameter(key)
            else:
                return_params[key] = unquote(request.get_parameter(key))
        return return_params
Exemplo n.º 5
0
    def post_outcome_request(self):
        '''
        POST an OAuth signed request to the Tool Consumer.
        '''
        if not self.has_required_attributes():
            raise InvalidLTIConfigError(
                'OutcomeRequest does not have all required attributes')

        consumer = oauth2.Consumer(key=self.consumer_key,
                                   secret=self.consumer_secret)

        client = oauth2.Client(consumer)
        # monkey_patch_headers ensures that Authorization
        # header is NOT lower cased
        monkey_patch_headers = True
        monkey_patch_function = None
        if monkey_patch_headers:
            import httplib2
            http = httplib2.Http

            normalize = http._normalize_headers

            def my_normalize(self, headers):
                print("My Normalize", headers)
                ret = normalize(self, headers)
                if 'authorization' in ret:
                    ret['Authorization'] = ret.pop('authorization')
                print("My Normalize", ret)
                return ret

            http._normalize_headers = my_normalize
            monkey_patch_function = normalize

        response, content = client.request(
            self.lis_outcome_service_url,
            'POST',
            body=self.generate_request_xml(),
            headers={'Content-Type': 'application/xml'})

        if monkey_patch_headers and monkey_patch_function:
            import httplib2
            http = httplib2.Http
            http._normalize_headers = monkey_patch_function

        self.outcome_response = OutcomeResponse.from_post_response(
            response, content)
        return self.outcome_response
Exemplo n.º 6
0
    def generate_launch_request(self, **kwargs):
        """
        returns a Oauth v1 "signed" requests.PreparedRequest instance
        """

        if not self.has_required_params():
            raise InvalidLTIConfigError(
                'Consumer\'s launch params missing one of ' \
                + str(LAUNCH_PARAMS_REQUIRED)
            )

#        if 'oauth_consumer_key' not in self.launch_params:
#            self.launch_params['oauth_consumer_key'] = self.consumer_key

        params = self.to_params()
        r = Request('POST', self.launch_url, data=params).prepare()
        sign = OAuth1(self.consumer_key,
                      self.consumer_secret,
                      signature_type=SIGNATURE_TYPE_BODY,
                      **kwargs)
        return sign(r)
Exemplo n.º 7
0
    def __init__(self,
                 consumer_key,
                 consumer_secret,
                 params=None,
                 launch_url=None):
        '''
        Create new ToolConsumer.
        '''
        # allow launch_url to be specified in launch_params for
        # backwards compatibility
        if launch_url is None:
            if 'launch_url' not in params:
                raise InvalidLTIConfigError('missing \'launch_url\' arg!')
            else:
                launch_url = params['launch_url']
                del params['launch_url']
        self.launch_url = launch_url

        super(ToolConsumer, self).__init__(consumer_key,
                                           consumer_secret,
                                           params=params)
Exemplo n.º 8
0
    def post_outcome_request(self):
        '''
        POST an OAuth signed request to the Tool Consumer.
        '''
        if not self.has_required_attributes():
            raise InvalidLTIConfigError(
                'OutcomeRequest does not have all required attributes')

        consumer = oauth2.Consumer(key=self.consumer_key,
                                   secret=self.consumer_secret)

        client = oauth2.Client(consumer)

        response, content = client.request(
            self.lis_outcome_service_url,
            'POST',
            body=self.generate_request_xml(),
            headers={'Content-Type': 'application/xml'})

        self.outcome_response = OutcomeResponse.from_post_response(
            response, content)
        return self.outcome_response
Exemplo n.º 9
0
    def post_outcome_request(self, **kwargs):
        '''
        POST an OAuth signed request to the Tool Consumer.
        '''
        if not self.has_required_attributes():
            raise InvalidLTIConfigError(
                'OutcomeRequest does not have all required attributes')

        header_oauth = OAuth1(self.consumer_key,
                              self.consumer_secret,
                              signature_type=SIGNATURE_TYPE_AUTH_HEADER,
                              force_include_body=True,
                              **kwargs)

        headers = {'Content-type': 'application/xml'}
        resp = requests.post(self.lis_outcome_service_url,
                             auth=header_oauth,
                             data=self.generate_request_xml(),
                             headers=headers)
        outcome_resp = OutcomeResponse.from_post_response(resp, resp.content)
        self.outcome_response = outcome_resp
        return self.outcome_response
Exemplo n.º 10
0
    def __init__(self, **kwargs):
        '''
        Create a new ToolConfig with the given options.
        '''
        # Initialize all class accessors to None
        for attr in VALID_ATTRIBUTES:
            setattr(self, attr, None)

        for attr in ['custom_params', 'extensions']:
            if attr in kwargs:
                attr_val = kwargs.pop(attr)
            else:
                attr_val = defaultdict(lambda: None)
            setattr(self, attr, attr_val)

        # Iterate over all provided options and save to class instance members
        for (key, val) in kwargs.iteritems():
            if key in VALID_ATTRIBUTES:
                setattr(self, key, val)
            else:
                raise InvalidLTIConfigError(
                    "Invalid outcome request option: {}".format(key)
                )
Exemplo n.º 11
0
    def to_xml(self, opts=defaultdict(lambda: None)):
        '''
        Generate XML from the current settings.
        '''
        if not self.launch_url or not self.secure_launch_url:
            raise InvalidLTIConfigError('Invalid LTI configuration')

        NSMAP = {
            'blti': 'http://www.imsglobal.org/xsd/imsbasiclti_v1p0',
            'xsi': "http://www.w3.org/2001/XMLSchema-instance",
            'lticp': 'http://www.imsglobal.org/xsd/imslticp_v1p0',
            'lticm': 'http://www.imsglobal.org/xsd/imslticm_v1p0',
        }

        root = etree.Element(
            'cartridge_basiclti_link',
            attrib={
                '{%s}%s' % (NSMAP['xsi'], 'schemaLocation'):
                'http://www.imsglobal.org/xsd/imslticc_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticc_v1p0.xsd http://www.imsglobal.org/xsd/imsbasiclti_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imsbasiclti_v1p0p1.xsd http://www.imsglobal.org/xsd/imslticm_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticm_v1p0.xsd http://www.imsglobal.org/xsd/imslticp_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticp_v1p0.xsd',
                'xmlns': 'http://www.imsglobal.org/xsd/imslticc_v1p0'
            },
            nsmap=NSMAP)

        for key in ['title', 'description', 'launch_url', 'secure_launch_url']:
            option = etree.SubElement(root, '{%s}%s' % (NSMAP['blti'], key))
            option.text = getattr(self, key)

        vendor_keys = ['name', 'code', 'description', 'url']
        if any('vendor_' + key for key in vendor_keys) or\
                self.vendor_contact_email:
            vendor_node = etree.SubElement(
                root, '{%s}%s' % (NSMAP['blti'], 'vendor'))
            for key in vendor_keys:
                if getattr(self, 'vendor_' + key) != None:
                    v_node = etree.SubElement(vendor_node,
                                              '{%s}%s' % (NSMAP['lticp'], key))
                    v_node.text = getattr(self, 'vendor_' + key)
            if getattr(self, 'vendor_contact_email'):
                v_node = etree.SubElement(
                    vendor_node, '{%s}%s' % (NSMAP['lticp'], 'contact'))
                c_name = etree.SubElement(v_node,
                                          '{%s}%s' % (NSMAP['lticp'], 'name'))
                c_name.text = self.vendor_contact_name
                c_email = etree.SubElement(
                    v_node, '{%s}%s' % (NSMAP['lticp'], 'email'))
                c_email.text = self.vendor_contact_email

        # Custom params
        if len(self.custom_params) != 0:
            custom_node = etree.SubElement(
                root, '{%s}%s' % (NSMAP['blti'], 'custom'))
            for (key, val) in sorted(self.custom_params.items()):
                c_node = etree.SubElement(
                    custom_node, '{%s}%s' % (NSMAP['lticm'], 'property'))
                c_node.set('name', key)
                c_node.text = val

        # Extension params
        if len(self.extensions) != 0:
            for (key, params) in sorted(self.extensions.items()):
                extension_node = etree.SubElement(
                    root,
                    '{%s}%s' % (NSMAP['blti'], 'extensions'),
                    platform=key)
                for key, val in params.iteritems():
                    if isinstance(val, dict):
                        options_node = etree.SubElement(
                            extension_node,
                            '{%s}%s' % (NSMAP['lticm'], 'options'),
                            name=key)
                        for key, val in val.iteritems():
                            property_node = etree.SubElement(
                                options_node,
                                '{%s}%s' % (NSMAP['lticm'], 'property'),
                                name=key)
                            property_node.text = val
                    else:
                        param_node = etree.SubElement(
                            extension_node,
                            '{%s}%s' % (NSMAP['lticm'], 'property'),
                            name=key)
                        param_node.text = val

        if getattr(self, 'cartridge_bundle'):
            identifierref = etree.SubElement(
                root, 'cartridge_bundle', identifierref=self.cartridge_bundle)

        if getattr(self, 'cartridge_icon'):
            identifierref = etree.SubElement(root,
                                             'cartridge_icon',
                                             identifierref=self.cartridge_icon)

        return '<?xml version="1.0" encoding="UTF-8"?>' + etree.tostring(root)