null

Отправка результатов из LTI блока в edX.

Для отправки результатов в edX в соответствии с LTI 1.1 нам потребуется sourcedId - идентификатор задания, получаемый от edX, outcomeServiceUrl - URL, на который необходимо отправить результат (тоже получается от edX) и rating - сам результат для отправки. Кроме того, нам потребуются CONSUMER_KEY и CONSUMER_SECRET, которые задаются в LTI паспорте в формате

[
    "lti_id:consumer_key:consumer_secret"
]

Важно! lti_id необходимо также указать в настройках LTI блока

Всю чёрную магию по отправке данных в edX за нас делает

<dependency>
    <groupId>org.imsglobal</groupId>
    <artifactId>basiclti-util</artifactId>
    <version>1.2.0</version>
</dependency>

В своих кишках она использует следующий шаблон (он, и только он является истинно валидным):

<?xml version = "1.0" encoding = "UTF-8"?>
<imsx_POXEnvelopeRequest xmlns="http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0">
	<imsx_POXHeader>
		<imsx_POXRequestHeaderInfo>
			<imsx_version>"V1.0"</imsx_version>
			<imsx_messageIdentifier>"__СЛУЧАЙНОЕ_ЗНАЧЕНИЕ__"</imsx_messageIdentifier>
		</imsx_POXRequestHeaderInfo>
	</imsx_POXHeader>
	<imsx_POXBody>
		<replaceResultRequest>
			<resultRecord>
				<sourcedGUID>
					<sourcedId>"__sourcedId__"</sourcedId>
				</sourcedGUID>
				<result>
					<resultScore>
						<language>en</language>
						<textString>"__rating__"</textString>
					</resultScore>
				</result>
			</resultRecord>
		</replaceResultRequest>
	</imsx_POXBody>
</imsx_POXEnvelopeRequest>

Пример использования библиотеки:

public int push(String sourcedId, String outcomeServiceUrl, float rating) throws IOException {
        HttpPost request = null;

        try {
            request = IMSPOXRequest.buildReplaceResult(c, CLIENT_KEY, CLIENT_SECRET, sourcedId, rating + "", null, true);
        } catch (OAuthException | GeneralSecurityException e) {
            e.printStackTrace();
        }
        HttpClient client = HttpClientBuilder.create().build();
        HttpResponse httpResponse = client.execute(request);
        HttpEntity entity = httpResponse.getEntity();
        String responseString = EntityUtils.toString(entity, "UTF-8");
        log.debug("RESPONSE ENTITY:\n{}", responseString);
        return httpResponse.getStatusLine().getStatusCode();
    }

Если настройки LTI указаны верно, то всё должно пройти гладко, если же в ответе от edX мы видим XML с ошибкой о проваленной валидации OAuth подписи, можно воспользоваться следующим кодом:

from oauthlib.oauth1.rfc5849 import signature
import mock
import urllib

def validate():
        client_key, client_secret = ('__CONSUMER_KEY__', u'__CONSUMER__SECRET__')
        headers = {
           # Exmple Authoriztion HEADER
           # OAuth oauth_body_hash="8Di4lHOBZn3ztioYj1VqCsE7jNs%3D", oauth_consumer_key="__CONSUMER_KEY__", oauth_nonce="5089146837464679937", oauth_signature="DX9REUQvuAUbRWp0raTPdIYkZyo%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1553170389", oauth_version="1.0"
            'Authorization': unicode('''__AUTHORIZATION_HEADER__'''),
            'Content-Type': 'application/xml',
        }

        oauth_params = signature.collect_parameters(headers=headers, exclude_oauth_signature=False)
        oauth_headers = dict(oauth_params)
        oauth_signature = oauth_headers.pop('oauth_signature')
        print oauth_signature
        mock_request_lti_1 = mock.Mock(
            uri=unicode(urllib.unquote('__OUTCOME_URL__')),
            http_method=unicode('POST'),
            params=oauth_headers.items(),
            signature=oauth_signature
        )
        print 'Validation result: '+str(signature.verify_hmac_sha1(mock_request_lti_1, client_secret))

validate()

ВНИМАНИЕ!!!!: Для запуска этого кода необходимо использовать ВТОРОЙ питон, также надо установить следующие зависимости:

    pip2 install oauthlib
    pip2 install mock

Сохраняем этот код в файл .py и запускаем с помощью python2