def test_invalid_request_already_submitted( self, fake_new_account_request, fake_credentials, mock_valid_calnet_uid, session, ): # test where username has already been requested with mock.patch('ocflib.account.submission.username_pending', return_value=True): errors, warnings = validate_request( fake_new_account_request, fake_credentials, session, ) assert errors # test where this user (calnet/callink oid) has already submitted a request with mock.patch('ocflib.account.submission.user_has_request_pending', return_value=True): errors, warnings = validate_request( fake_new_account_request, fake_credentials, session, ) assert errors
def test_invalid_request_already_submitted( self, fake_new_account_request, fake_credentials, mock_valid_calnet_uid, session ): # test where username has already been requested with mock.patch("ocflib.account.submission.username_pending", return_value=True): errors, warnings = validate_request(fake_new_account_request, fake_credentials, session) assert errors # test where this user (calnet/callink oid) has already submitted a request with mock.patch("ocflib.account.submission.user_has_request_pending", return_value=True): errors, warnings = validate_request(fake_new_account_request, fake_credentials, session) assert errors
def create_account(request): # TODO: docstring # lock account creation for up to 5 minutes r = redis.from_url(credentials.redis_uri) lock = r.lock('ocflib.account.submission.create_account', timeout=60 * 5) try: if not lock.acquire(blocking=True, blocking_timeout=60 * 5): raise RuntimeError('Couldn\'t lock account creation, abandoning.') # status reporting status = [] class report_status: def __init__(self, *args): if len(args) == 1: self(*args) else: self.start, self.stop, self.task = args def __call__(self, line): status.append(line) create_account.update_state(meta={'status': status}) def __enter__(self, *args): self(self.start + ' ' + self.task) def __exit__(self, *args): self(self.stop + ' ' + self.task) with report_status('Validating', 'Validated', 'request'), \ get_session() as session: errors, warnings = validate_request(request, credentials, session) if errors: send_rejected_mail(request, str(errors)) return NewAccountResponse( status=NewAccountResponse.REJECTED, errors=(errors + warnings), ) # actual account creation kwargs = {} known_uid = r.get('known_uid') if known_uid: kwargs['known_uid'] = int(known_uid) new_uid = real_create_account(request, credentials, report_status, **kwargs) r.set('known_uid', new_uid) dispatch_event('ocflib.account_created', request=request.to_dict()) return NewAccountResponse( status=NewAccountResponse.CREATED, errors=[], ) finally: try: lock.release() except LockError: pass
def validate_then_create_account(request): """First run validation, then create. This is handy because this task runs quickly, so you can wait for it to finish (unlike create_account, which is slow and uses a global lock). If this task succeeds, it will launch create_account, and returns you the new task ID. Assuming this task succeeds, it is almost certain that create_account will succeed. However, create_account runs validation again, so it is possible for it to fail (just exceedingly unlikely). """ # TODO: docstring is not 100% correct with get_session() as session: errors, warnings = validate_request(request, credentials, session) if errors: # Fatal errors; cannot be bypassed, even with staff approval return NewAccountResponse( status=NewAccountResponse.REJECTED, errors=(errors + warnings), ) elif warnings: # Non-fatal errors; the frontend can choose to create the account # anyway, submit the account for staff approval, or get a response # with a list of warnings for further inspection. if request.handle_warnings == NewAccountRequest.WARNINGS_SUBMIT: stored_request = StoredNewAccountRequest.from_request( request, str(warnings)) try: with get_session() as session: session.add(stored_request) # TODO: error handling session.commit() except sqlalchemy.exc.IntegrityError: # If there's an integrity constraint, it's okay -- the # account was already submitted, so we can still return a # "pending" response. pass else: dispatch_event( 'ocflib.account_submitted', request=dict(request.to_dict(), reasons=warnings), ) return NewAccountResponse( status=NewAccountResponse.PENDING, errors=warnings, ) elif request.handle_warnings == NewAccountRequest.WARNINGS_WARN: return NewAccountResponse( status=NewAccountResponse.FLAGGED, errors=warnings, ) return create_account.delay(request).id
def test_valid_request( self, fake_new_account_request, fake_credentials, mock_valid_calnet_uid, session, ): assert validate_request( fake_new_account_request, fake_credentials, session, ) == ([], [])
def test_invalid_request_error( self, fake_new_account_request, fake_credentials, mock_valid_calnet_uid, attrs, session, ): errors, warnings = validate_request( fake_new_account_request._replace(**attrs), fake_credentials, session, ) assert errors
def validate_then_create_account(request): """First run validation, then create. This is handy because this task runs quickly, so you can wait for it to finish (unlike create_account, which is slow and uses a global lock). If this task succeeds, it will launch create_account, and returns you the new task ID. Assuming this task succeeds, it is almost certain that create_account will succeed. However, create_account runs validation again, so it is possible for it to fail (just exceedingly unlikely). """ # TODO: docstring is not 100% correct with get_session() as session: errors, warnings = validate_request(request, credentials, session) if errors: # Fatal errors; cannot be bypassed, even with staff approval return NewAccountResponse( status=NewAccountResponse.REJECTED, errors=(errors + warnings), ) elif warnings: # Non-fatal errors; the frontend can choose to create the account # anyway, submit the account for staff approval, or get a response # with a list of warnings for further inspection. if request.handle_warnings == NewAccountRequest.WARNINGS_SUBMIT: stored_request = StoredNewAccountRequest.from_request(request, str(warnings)) with get_session() as session: session.add(stored_request) # TODO: error handling session.commit() dispatch_event( 'ocflib.account_submitted', request=dict(request.to_dict(), reasons=warnings), ) return NewAccountResponse( status=NewAccountResponse.PENDING, errors=warnings, ) elif request.handle_warnings == NewAccountRequest.WARNINGS_WARN: return NewAccountResponse( status=NewAccountResponse.FLAGGED, errors=warnings, ) return create_account.delay(request).id
def create_account(request): # TODO: docstring # lock account creation for up to 5 minutes r = redis.from_url(credentials.redis_uri) lock = r.lock('ocflib.account.submission.create_account', timeout=60 * 5) try: if not lock.acquire(blocking=True, blocking_timeout=60 * 5): raise RuntimeError('Couldn\'t lock account creation, abandoning.') # status reporting status = [] def _report_status(line): """Update task status by adding the given line.""" status.append(line) create_account.update_state(meta={'status': status}) @contextmanager def report_status(start, stop, task): _report_status(start + ' ' + task) yield _report_status(stop + ' ' + task) with report_status('Validating', 'Validated', 'request'), \ get_session() as session: errors, warnings = validate_request(request, credentials, session) if errors: send_rejected_mail(request, str(errors)) return NewAccountResponse( status=NewAccountResponse.REJECTED, errors=(errors + warnings), ) # actual account creation real_create_account(request, credentials, report_status) dispatch_event('ocflib.account_created', request=request.to_dict()) return NewAccountResponse( status=NewAccountResponse.CREATED, errors=[], ) finally: try: lock.release() except LockError: pass