def refresh_token(subject, session): """ :param str subject: :param Session session: """ user = UserQuery(session) \ .is_active() \ .has_sub(subject) \ .one() token = backend.refresh_token(user.refresh_token) user.access_token = token['access_token'] user.refresh_token = token['refresh_token'] user.token_expire = datetime \ .fromtimestamp(token['expires_at']) \ .replace(tzinfo=timezone.utc)
def get_user(self, subject, session): """ :param str subject: :param sqlalchemy.orm.Session session: :rtype: User """ return UserQuery(session) \ .is_active() \ .has_sub(subject) \ .one_or_none()
def get_soon_to_expire_tokens(session): """ :param Session session: """ users = UserQuery(session) \ .is_active() \ .should_refresh_token() tasks = [refresh_token.si(subject=user.sub) for user in users] group(*tasks).apply_async()
def handle_request(self, request, session): """ :param OnGgoReceivedWebhookRequest request: :param Session session: :rtype: bool """ user = UserQuery(session) \ .is_active() \ .has_sub(request.sub) \ .one_or_none() if user: start_handle_ggo_received_pipeline(request.ggo, user) return True else: return False
def handle_request(self, request, session): """ :param OnMeteringPointsAvailableWebhookRequest request: :param Session session: :rtype: bool """ user = UserQuery(session) \ .is_active() \ .has_sub(request.sub) \ .one_or_none() if user: start_import_meteringpoints_pipeline(user.sub) return True else: return False
def trigger_handle_ggo_received_pipeline(task, subject, begin, session): """ :param celery.Task task: :param str subject: :param str begin: :param Session session: """ __log_extra = { 'subject': subject, 'begin': begin, 'pipeline': 'handle_measurement_published', 'task': 'handle_measurement_published', } begin_dt = datetime.fromisoformat(begin) # Get User from database try: user = UserQuery(session) \ .is_active() \ .has_sub(subject) \ .one() except orm.exc.NoResultFound: raise except Exception as e: logger.exception('Failed to load User from database, retrying...', extra=__log_extra) raise task.retry(exc=e) # Get stored GGOs from AccountService try: stored_ggos = get_stored_ggos(user.access_token, begin_dt) except AccountServiceError as e: if e.status_code == 400: raise else: logger.exception('Failed to get GGO list, retrying...', extra=__log_extra) raise task.retry(exc=e) except Exception as e: logger.exception('Failed to get GGO list, retrying...', extra=__log_extra) raise task.retry(exc=e) # Trigger handle_ggo_received pipeline for each stored GGO for ggo in stored_ggos: start_handle_ggo_received_pipeline(ggo, user)
def handle_request(self, request, user, session): """ :param SubmitAgreementProposalRequest request: :param User user: :param Session session: :rtype: SubmitAgreementProposalResponse """ counterpart = UserQuery(session) \ .is_active() \ .has_public_id(request.counterpart_id) \ .exclude(user) \ .one_or_none() if not counterpart: return SubmitAgreementProposalResponse(success=False) if request.direction == AgreementDirection.INBOUND: user_from = counterpart user_to = user elif request.direction == AgreementDirection.OUTBOUND: user_from = user user_to = counterpart else: raise RuntimeError('This should NOT have happened!') agreement = self.create_pending_agreement( request=request, user=user, user_from=user_from, user_to=user_to, ) session.add(agreement) session.flush() logger.info(f'User submitted TradeAgreement proposal', extra={ 'subject': user.sub, 'target': counterpart.sub, 'agreement_id': agreement.id, }) # Send e-mail to recipient of proposal send_invitation_received_email(agreement) return SubmitAgreementProposalResponse(success=True)
def handle_request(self, request, session): """ :param OnMeasurementPublishedWebhookRequest request: :param Session session: :rtype: bool """ if request.measurement.type is MeasurementType.CONSUMPTION: user = UserQuery(session) \ .is_active() \ .has_sub(request.sub) \ .one_or_none() if user: start_handle_measurement_published_pipeline( request.measurement, user) return True
def handle_request(self, request, session): """ :param OnMeteringPointAvailableWebhookRequest request: :param sqlalchemy.orm.Session session: :rtype: bool """ user = UserQuery(session) \ .is_active() \ .has_sub(request.sub) \ .one_or_none() # User exists? if user is None: logger.error( f'Can not import MeteringPoint (user not found in DB)', extra={ 'subject': request.sub, 'gsrn': request.meteringpoint.gsrn, }) return False # MeteringPoint already present in database? if self.facility_exists(request.meteringpoint.gsrn, session): logger.info( f'MeteringPoint {request.meteringpoint.gsrn} already exists in DB, skipping...', extra={ 'subject': request.sub, 'gsrn': request.meteringpoint.gsrn, }) return True # Insert new MeteringPoint in to DB facility = self.create_facility(user, request.meteringpoint) logger.info(f'Imported MeteringPoint with GSRN: {facility.gsrn}', extra={ 'subject': user.sub, 'gsrn': facility.gsrn, 'type': facility.facility_type, 'facility_id': facility.id, }) return True
def consume_back_in_time(subject, begin_from, begin_to, session): """ TODO UNIQUE PER (ACCOUNT, BEGIN) :param str subject: :param str begin_from: :param str begin_to: :param Session session: """ user = UserQuery(session) \ .is_active() \ .has_sub(subject) \ .one() filters = GgoFilters( category=GgoCategory.STORED, begin_range=DateTimeRange( begin=datetime.fromisoformat(begin_from), end=datetime.fromisoformat(begin_to), ) ) response = service.get_ggo_list( token=user.access_token, request=GetGgoListRequest( filters=filters, ), ) tasks = [ handle_ggo_received.s( subject=user.sub, ggo_json=ggo_schema.dump(ggo), address=ggo.address, ) for ggo in response.results ] if tasks: group(*tasks).apply_async()
def handle_measurement_published(task, subject, measurement_json, session): """ :param celery.Task task: :param str subject: :param JSON measurement_json: :param Session session: """ __log_extra = { 'subject': subject, 'measurement_json': str(measurement_json), 'pipeline': 'handle_measurement_published', 'task': 'handle_measurement_published', } measurement = measurement_schema.load(measurement_json) subjects = set() # Get User from database try: user = UserQuery(session) \ .is_active() \ .has_sub(subject) \ .one() except orm.exc.NoResultFound: raise except Exception as e: logger.exception('Failed to load User from database, retrying...', extra=__log_extra) raise task.retry(exc=e) # Triggers handle_ggo_received for each GGO the user has stored (to retire) subjects.add(subject) # Get inbound agreements from database try: agreements = AgreementQuery(session) \ .is_inbound_to(user) \ .is_limited_to_consumption() \ .is_operating_at(measurement.begin) \ .is_active() \ .all() except Exception as e: logger.exception( 'Failed to load Agreements from database, retrying...', extra=__log_extra) raise task.retry(exc=e) # Triggers handle_ggo_received for each GGO the outbound user # has stored (to transfer) for agreement in agreements: subjects.add(agreement.user_from.sub) # Start tasks = [ trigger_handle_ggo_received_pipeline.si( subject=sub, begin=measurement.begin.isoformat(), ) for sub in subjects ] group(*tasks).apply_async()
def import_meteringpoints_and_insert_to_db(task, subject, session): """ :param celery.Task task: :param str subject: :param Session session: """ __log_extra = { 'subject': subject, 'pipeline': 'import_meteringpoints', 'task': 'import_meteringpoints_and_insert_to_db', } # Get User from DB try: user = UserQuery(session) \ .is_active() \ .has_sub(subject) \ .one() except orm.exc.NoResultFound: raise except Exception as e: logger.exception('Failed to load User from database, retrying...', extra=__log_extra) raise task.retry(exc=e) # Import MeteringPoints from DataHubService try: response = datahub_service.get_meteringpoints(user.access_token) except DataHubServiceConnectionError as e: logger.exception( f'Failed to establish connection to DataHubService, retrying...', extra=__log_extra) raise task.retry(exc=e) except DataHubServiceError as e: if e.status_code == 400: logger.exception('Got BAD REQUEST from DataHubService', extra=__log_extra) raise else: logger.exception('Failed to import MeteringPoints, retrying...', extra=__log_extra) raise task.retry(exc=e) # Save imported MeteringPoints to database try: facilities = save_imported_meteringpoints(user, response) except Exception as e: logger.exception( 'Failed to save imported Meteringpoints to database, retrying...', extra=__log_extra) raise task.retry(exc=e) # Logging logger.info( f'Imported {len(facilities)} new MeteringPoints from DataHubService', extra=__log_extra) for facility in facilities: logger.info(f'Imported meteringpoint with GSRN: {facility.gsrn}', extra={ 'gsrn': facility.gsrn, 'subject': user.sub, 'pipeline': 'import_meteringpoints', 'task': 'import_meteringpoints_and_insert_to_db', })
def handle_ggo_received(task, subject, address, ggo_json, session): """ :param celery.Task task: :param str subject: :param str address: :param JSON ggo_json: :param Session session: """ __log_extra = { 'subject': subject, 'address': address, 'ggo': str(ggo_json), 'pipeline': 'handle_ggo_received', 'task': 'handle_ggo_received', } ggo = ggo_schema.load(ggo_json) # Get User from database try: user = UserQuery(session) \ .is_active() \ .has_sub(subject) \ .one() except orm.exc.NoResultFound: raise except Exception as e: logger.exception('Failed to load User from database, retrying...', extra=__log_extra) raise task.retry(exc=e) # Affected subjects TODO # affected_subjects = controller.get_affected_subjects(user, ggo, session) # lock_keys = [get_lock_key(sub, ggo.begin) for sub in affected_subjects] lock_key = ggo.begin.strftime('%Y-%m-%d-%H-%M') # This lock is in place to avoid timing issues when executing multiple # tasks for the same account at the same time, which can cause # the transferred or retired amount to exceed the allowed amount with lock(lock_key, timeout=LOCK_TIMEOUT) as acquired: if not acquired: logger.info('Could not acquire lock(s), retrying...', extra=__log_extra) raise task.retry() try: if not ggo_is_available(user.access_token, ggo): logger.info('GGO is unavailable, skipping...', extra=__log_extra) return # Consume GGO controller.consume_ggo(user, ggo, session) except AccountServiceError as e: if e.status_code == 400: raise else: logger.exception('Failed to consume GGO, retrying...', extra=__log_extra) raise task.retry(exc=e) except Exception as e: logger.exception('Failed to consume GGO, retrying...', extra=__log_extra) raise task.retry(exc=e)