def get_ecommerce_client(site_code=None): """ Get client for fetching data from ecommerce API Returns: EdxRestApiClient object """ ecommerce_api_root = get_configuration('ECOMMERCE_API_ROOT', site_code=site_code) signing_key = get_configuration('JWT_SECRET_KEY', site_code=site_code) issuer = get_configuration('JWT_ISSUER', site_code=site_code) service_username = get_configuration('ECOMMERCE_SERVICE_USERNAME', site_code=site_code) return EdxRestApiClient(ecommerce_api_root, signing_key=signing_key, issuer=issuer, username=service_username)
def create_video_pipeline_api_client(user, api_client_id, api_client_secret, api_url): """ Returns an API client which can be used to make Video Pipeline API requests. Arguments: user(User): A requesting user. api_client_id(unicode): Video pipeline client id. api_client_secret(unicode): Video pipeline client secret. api_url(unicode): It is video pipeline's API URL. """ jwt_token = create_jwt_for_user(user, secret=api_client_secret, aud=api_client_id) return EdxRestApiClient(api_url, jwt=jwt_token)
def create_catalog_api_client(user, site=None): """Returns an API client which can be used to make Catalog API requests.""" scopes = ['email', 'profile'] expires_in = settings.OAUTH_ID_TOKEN_EXPIRATION jwt = JwtBuilder(user).build_token(scopes, expires_in) if site: url = site.configuration.get_value('COURSE_CATALOG_API_URL') else: url = CatalogIntegration.current().get_internal_api_url() return EdxRestApiClient(url, jwt=jwt)
def enterprise_api_client(self): """ Constructs a Slumber-based REST API client for the provided site. Example: site.siteconfiguration.enterprise_api_client.enterprise-learner(learner.username).get() Returns: EdxRestApiClient: The client to access the Enterprise service. """ return EdxRestApiClient(self.enterprise_api_url, jwt=self.access_token)
def _hubspot_endpoint(self, hubspot_object, api_url, method, body=None, **kwargs): """ This function is responsible for all the calls of hubspot. """ client = EdxRestApiClient('/'.join([HUBSPOT_API_BASE_URL, api_url])) if method == "GET": return getattr(client, hubspot_object).get(**kwargs) if method == "POST": return getattr(client, hubspot_object).post(**kwargs) if method == "PUT": return getattr(client, hubspot_object).put(body, **kwargs) raise ValueError("Unexpected method {}".format(method))
def enterprise_catalog_api_client(self): """ Returns a REST API client for the provided enterprise catalog service Example: site.siteconfiguration.enterprise_catalog_api_client.enterprise-catalog.get() Returns: EdxRestApiClient: The client to access the Enterprise Catalog service. """ return EdxRestApiClient(self.enterprise_catalog_api_url, jwt=self.access_token)
def __init__(self): jwt, __ = EdxRestApiClient.get_oauth_access_token( f'{OIDC_URL}/access_token', OIDC_KEY, OIDC_SECRET, token_type='jwt' ) self.client = EdxRestApiClient(DISCOVERY_API_URL, jwt=jwt) self.deadline_empty_with_end = [] self.deadline_empty_without_end = [] self.deadline_after_end = []
def __init__(self, user): """ Initialize an authenticated Consent service API client by using the provided user. """ jwt = create_jwt_for_user(user) url = configuration_helpers.get_value('ENTERPRISE_CONSENT_API_URL', settings.ENTERPRISE_CONSENT_API_URL) self.client = EdxRestApiClient( url, jwt=jwt, append_slash=False, ) self.consent_endpoint = self.client.data_sharing_consent
def ecommerce_api_client(user): """ Returns an E-Commerce API client setup with authentication for the specified user. """ jwt_auth = configuration_helpers.get_value("JWT_AUTH", settings.JWT_AUTH) return EdxRestApiClient( configuration_helpers.get_value("ECOMMERCE_API_URL", settings.ECOMMERCE_API_URL), configuration_helpers.get_value("ECOMMERCE_API_SIGNING_KEY", settings.ECOMMERCE_API_SIGNING_KEY), user.username, user.profile.name if hasattr(user, 'profile') else None, user.email, tracking_context=create_tracking_context(user), issuer=jwt_auth['JWT_ISSUER'], expires_in=jwt_auth['JWT_EXPIRATION'] )
def __init__(self): """ Initialize a consent service API client, authenticated using the Enterprise worker username. """ self.user = User.objects.get(username=settings.ENTERPRISE_SERVICE_WORKER_USERNAME) jwt = JwtBuilder(self.user).build_token([]) url = configuration_helpers.get_value('ENTERPRISE_CONSENT_API_URL', settings.ENTERPRISE_CONSENT_API_URL) self.client = EdxRestApiClient( url, jwt=jwt, append_slash=False, ) self.consent_endpoint = self.client.data_sharing_consent
def connect(self): """ Connect to the REST API, authenticating with an access token retrieved with our client credentials. """ access_token, expires_at = EdxRestApiClient.get_oauth_access_token( self.LMS_OAUTH_HOST + '/oauth2/access_token', self.client_id, self.client_secret, 'jwt') self.client = EdxRestApiClient( self.API_BASE_URL, append_slash=self.APPEND_SLASH, jwt=access_token, ) self.expires_at = expires_at
def course_discovery_api_client(user): """ Return a Course Discovery API client setup with authentication for the specified user. """ if JwtBuilder is None: raise NotConnectedToOpenEdX( _("To get a Catalog API client, this package must be " "installed in an Open edX environment.")) scopes = ['email', 'profile'] expires_in = settings.OAUTH_ID_TOKEN_EXPIRATION jwt = JwtBuilder(user).build_token(scopes, expires_in) return EdxRestApiClient(settings.COURSE_CATALOG_API_URL, jwt=jwt)
def _get_basket(self, basket_id): if not basket_id: return None try: basket_id = int(basket_id) basket = Basket.objects.get(id=basket_id) basket.strategy = strategy.Default() # TODO: Remove as a part of REVMI-124 as this is a hacky solution # The problem is that orders are being created after payment processing, and the discount is not # saved in the database, so it needs to be calculated again in order to save the correct info to the # order. REVMI-124 will create the order before payment processing, when we have the discount context. if waffle.flag_is_active(self.request, DYNAMIC_DISCOUNT_FLAG) and basket.lines.count() == 1: # pragma: no cover pylint: disable=line-too-long discount_lms_url = get_lms_url('/api/discounts/') lms_discount_client = EdxRestApiClient( discount_lms_url, jwt=self.request.site.siteconfiguration.access_token) ck = basket.lines.first().product.course_id user_id = basket.owner.lms_user_id try: response = lms_discount_client.user(user_id).course( ck).get() self.request.POST = self.request.POST.copy() self.request.POST['discount_jwt'] = response.get('jwt') logger.info( """Received discount jwt from LMS with url: [%s], user_id: [%s], course_id: [%s], and basket_id: [%s] returned [%s]""", discount_lms_url, str(user_id), ck, basket.id, response) except (SlumberHttpBaseException, requests.exceptions.Timeout) as error: logger.warning( """Failed to receive discount jwt from LMS with url: [%s], user_id: [%s], course_id: [%s], and basket_id: [%s] returned [%s]""", discount_lms_url, str(user_id), ck, basket.id, vars(error.response) if hasattr(error, 'response') else '') # End TODO Applicator().apply(basket, basket.owner, self.request) logger.info('Applicator applied, basket id: [%s]', basket.id) return basket except (ValueError, ObjectDoesNotExist) as error: logger.warning('Could not get basket--error: [%s]', str(error)) return None
def __init__(self, oauth_access_token_url, oauth_key, oauth_secret, api_url_root): try: self.access_token, expires = EdxRestApiClient.get_oauth_access_token( oauth_access_token_url, oauth_key, oauth_secret, token_type='jwt' ) except Exception: logger.exception('No access token acquired through client_credential flow.') raise logger.info('Retrieved access token.') self.api_client = EdxRestApiClient(api_url_root, jwt=self.access_token)
def get_api_client(api_config, student): """ Create and configure an API client for authenticated HTTP requests. Args: api_config: ProgramsApiConfig or CredentialsApiConfig object student: User object as whom to authenticate to the API Returns: EdxRestApiClient """ id_token = get_id_token(student, api_config.OAUTH2_CLIENT_NAME) return EdxRestApiClient(api_config.internal_api_url, jwt=id_token)
def journal_discovery_api_client(self): """ Returns an Journal API client to access the Discovery service. Returns: EdxRestApiClient: The client to access the Journal API in the Discovery service. """ split_url = urlsplit(self.discovery_api_url) journal_discovery_url = urlunsplit([ split_url.scheme, split_url.netloc, JOURNAL_DISCOVERY_API_PATH, split_url.query, split_url.fragment ]) return EdxRestApiClient(journal_discovery_url, jwt=self.access_token)
def _publish_creditcourse(self, course_id, access_token): """Creates or updates a CreditCourse object on the LMS.""" api = EdxRestApiClient( get_lms_url('api/credit/v1/'), oauth_access_token=access_token, timeout=self.timeout ) data = { 'course_key': course_id, 'enabled': True } api.courses(course_id).put(data)
def api_client(self): """ Returns an authenticated API client ready to call the API from which data is loaded. Returns: EdxRestApiClient """ kwargs = {} if self.token_type == 'jwt': kwargs['jwt'] = self.access_token else: kwargs['oauth_access_token'] = self.access_token return EdxRestApiClient(self.api_url, **kwargs)
def ecommerce_api_client(user, session=None): """ Returns an E-Commerce API client setup with authentication for the specified user. """ claims = {'tracking_context': create_tracking_context(user)} scopes = [ 'user_id', 'email', 'profile' ] jwt = create_jwt_for_user(user, additional_claims=claims, scopes=scopes) return EdxRestApiClient( configuration_helpers.get_value('ECOMMERCE_API_URL', settings.ECOMMERCE_API_URL), jwt=jwt, session=session )
def _get_courses_enrollment_info(self): """ Retrieve the enrollment information for all the courses. Returns: Dictionary representing the key-value pair (course_key, enrollment_end) of course. """ def _parse_response(api_response): response_data = api_response.get('results', []) # Map course_id with enrollment end date. courses_enrollment = dict( (course_info['course_id'], course_info['enrollment_end']) for course_info in response_data ) return courses_enrollment, api_response['pagination'].get('next', None) querystring = {'page_size': 50} api = EdxRestApiClient(get_lms_url('api/courses/v1/')) course_enrollments = {} page = 0 throttling_attempts = 0 next_page = True while next_page: page += 1 querystring['page'] = page try: response = api.courses().get(**querystring) throttling_attempts = 0 except HttpClientError as exc: # this is a known limitation; If we get HTTP429, we need to pause execution for a few seconds # before re-requesting the data. raise any other errors if exc.response.status_code == 429 and throttling_attempts < self.max_tries: logger.warning( 'API calls are being rate-limited. Waiting for [%d] seconds before retrying...', self.pause_time ) time.sleep(self.pause_time) page -= 1 throttling_attempts += 1 logger.info('Retrying [%d]...', throttling_attempts) continue else: raise enrollment_info, next_page = _parse_response(response) course_enrollments.update(enrollment_info) return course_enrollments
def get_programs(user): """Given a user, get programs from the Programs service. Returned value is cached depending on user permissions. Staff users making requests against Programs will receive unpublished programs, while regular users will only receive published programs. Arguments: user (User): The user to authenticate as when requesting programs. Returns: list of dict, representing programs returned by the Programs service. """ programs_config = ProgramsApiConfig.current() no_programs = [] # Bypass caching for staff users, who may be creating Programs and want to see them displayed immediately. use_cache = programs_config.is_cache_enabled and not user.is_staff if not programs_config.enabled: log.warning('Programs configuration is disabled.') return no_programs if use_cache: cached = cache.get(programs_config.CACHE_KEY) if cached is not None: return cached try: jwt = get_id_token(user, programs_config.OAUTH2_CLIENT_NAME) api = EdxRestApiClient(programs_config.internal_api_url, jwt=jwt) except Exception: # pylint: disable=broad-except log.exception('Failed to initialize the Programs API client.') return no_programs try: response = api.programs.get() except Exception: # pylint: disable=broad-except log.exception('Failed to retrieve programs from the Programs API.') return no_programs results = response.get('results', no_programs) if use_cache: cache.set(programs_config.CACHE_KEY, results, programs_config.cache_ttl) return results
def create_video_pipeline_api_client(user, api_client_id, api_client_secret, api_url): """ Returns an API client which can be used to make Video Pipeline API requests. Arguments: user(User): A requesting user. api_client_id(unicode): Video pipeline client id. api_client_secret(unicode): Video pipeline client secret. api_url(unicode): It is video pipeline's API URL. """ jwt_token = JwtBuilder(user, secret=api_client_secret).build_token( scopes=[], expires_in=settings.OAUTH_ID_TOKEN_EXPIRATION, aud=api_client_id ) return EdxRestApiClient(api_url, jwt=jwt_token)
def get_api_client(api_config, user): """ Create and configure an API client for authenticated HTTP requests. Args: api_config: CredentialsApiConfig object user: User object as whom to authenticate to the API Returns: EdxRestApiClient """ scopes = ['email', 'profile'] expires_in = settings.OAUTH_ID_TOKEN_EXPIRATION jwt = JwtBuilder(user).build_token(scopes, expires_in) return EdxRestApiClient(api_config.internal_api_url, jwt=jwt)
def connect(self): """ Connect to the REST API, authenticating with a JWT for the current user. """ if JwtBuilder is None: raise NotConnectedToOpenEdX( "This package must be installed in an OpenEdX environment.") now = int(time()) jwt = JwtBuilder.create_jwt_for_user(self.user) self.client = EdxRestApiClient( self.API_BASE_URL, append_slash=self.APPEND_SLASH, jwt=jwt, ) self.expires_at = now + self.expires_in
def get_credentials_api_client(user, org=None): """ Returns an authenticated Credentials API client. Arguments: user (User): The user to authenticate as when requesting credentials. org (str): Optional organization to look up the site config for, rather than the current request """ jwt = create_jwt_for_user(user) if org is None: url = CredentialsApiConfig.current().internal_api_url # by current request else: url = CredentialsApiConfig.get_internal_api_url_for_org(org) # by org return EdxRestApiClient(url, jwt=jwt)
def refresh(cls, course_id, access_token): """ Refresh the course data from the raw data sources. Args: course_id (str): Course ID access_token (str): OAuth access token Returns: Course """ client = EdxRestApiClient(settings.ECOMMERCE_API_URL, oauth_access_token=access_token) body = client.courses(course_id).get(include_products=True) course = Course(course_id, body) course.save() return course
def __init__(self): """ Initialize an authenticated Journals service API client by using the provided user. """ try: self.user = self.get_journals_worker() except ObjectDoesNotExist: error = 'Unable to retrieve {} service user'.format( JOURNAL_WORKER_USERNAME) LOGGER.error(error) raise ValueError(error) jwt = JwtBuilder(self.user).build_token(['email', 'profile'], 16000) self.client = EdxRestApiClient(configuration_helpers.get_value( 'JOURNALS_API_URL', settings.JOURNALS_API_URL), jwt=jwt)
def __init__(self): """ Create an LMS API client, authenticated with the OAuth2 token for client in settings """ # session = Session() # # session.headers = {"X-Edx-Api-Key": settings.OPENEDX_EDX_API_KEY} token = EdxRestApiClient.get_oauth_access_token( url="{}{}".format(settings.OPENEDX_PLATFORM_URI, constants.OPENEDX_OAUTH2_TOKEN_URL), client_id=settings.OPENEDX_OAUTH2_CLIENT_ID, client_secret=settings.OPENEDX_OAUTH2_CLIENT_SECRET) self.cache = False if settings.LMS_API_USE_MEMCACHED: self.cache = memcache.Client([settings.MEMCACHED_ADDRESS], debug=0) self.client = EdxRestApiClient(self.API_BASE_URL, append_slash=self.APPEND_SLASH, username="******", oauth_access_token=token[0])
def get_credit_provider_details(access_token, credit_provider_id, site_configuration): """ Returns the credit provider details from LMS. Args: access_token (str): JWT access token credit_provider_id (str): Identifier for the provider site_configuration (SiteConfiguration): Ecommerce Site Configuration Returns: dict """ try: return EdxRestApiClient( site_configuration.build_lms_url('api/credit/v1/'), oauth_access_token=access_token ).providers(credit_provider_id).get() except (ConnectionError, SlumberHttpBaseException, Timeout): logger.exception('Failed to retrieve credit provider details for provider [%s].', credit_provider_id) return None
def is_verified(self, site): """ Check if a user has verified his/her identity. Calls the LMS verification status API endpoint and returns the verification status information. The status information is stored in cache, if the user is verified, until the verification expires. Args: site (Site): The site object from which the LMS account API endpoint is created. Returns: True if the user is verified, false otherwise. Raises: ConnectionError, SlumberBaseException and Timeout for failures in establishing a connection with the LMS verification status API endpoint. """ try: cache_key = 'verification_status_{username}'.format( username=self.username) cache_key = hashlib.md5(cache_key).hexdigest() verification = cache.get(cache_key) if not verification: api = EdxRestApiClient( site.siteconfiguration.build_lms_url('api/user/v1/'), oauth_access_token=self.access_token) response = api.accounts( self.username).verification_status().get() verification = response.get('is_verified', False) if verification: cache_timeout = int( (parse(response.get('expiration_datetime')) - now()).total_seconds()) cache.set(cache_key, verification, cache_timeout) return verification except HttpNotFoundError: log.debug('No verification data found for [%s]', self.username) return False except (ConnectionError, SlumberBaseException, Timeout): msg = 'Failed to retrieve verification status details for [{username}]'.format( username=self.username) log.exception(msg) raise VerificationStatusError(msg)