<commit_before>import { ChangeDetectionStrategy, Component, Injector, OnDestroy, OnInit } from '@angular/core';
import { AbstractControl, AsyncValidatorFn, FormControl, FormGroup, ValidationErrors, ValidatorFn, Validators } from '@angular/forms';
import {
  AddressNew, AvailabilityEnum, Group, GroupForRegistration, GroupKind,
  IdentityProvider, IdentityProviderCallbackStatusEnum, Image, PhoneNew, RoleEnum, StoredFile,
  UserDataForNew, UserNew, UserRegistrationResult
} from 'app/api/models';
import { ImagesService, UsersService } from 'app/api/services';
import { AddressHelperService } from 'app/core/address-helper.service';
import { NextRequestState } from 'app/core/next-request-state';
import { UserHelperService } from 'app/core/user-helper.service';
import { ApiHelper } from 'app/shared/api-helper';
import { BasePageComponent } from 'app/shared/base-page.component';
import {
  blank, copyProperties, empty, focusFirstField, focusFirstInvalid,
  mergeValidity, scrollTop, setRootSpinnerVisible, validateBeforeSubmit
} from 'app/shared/helper';
import { Menu } from 'app/shared/menu';
import { BehaviorSubject, Observable, of, Subscription, timer } from 'rxjs';
import { first, map, switchMap } from 'rxjs/operators';

export type RegistrationStep = 'group' | 'idp' | 'fields' | 'confirm' | 'done';

/** Validator function that ensures password and confirmation match */
const SEGURITY_ANSWER_VAL: ValidatorFn = control => {
  if (control.touched) {
    const parent = control.parent;
    const question = parent.get('securityQuestion') == null ? '' : parent.get('securityQuestion').value;
    const answer = control.value;
    if (question != null && question !== '' && (answer == null || answer === '')) {
      return {
        required: true
      };
    }
  }
  return null;
};

/**
 * User registration. Works for guest, by admin and by broker
 */
@Component({
  selector: 'user-registration',
  templateUrl: 'user-registration.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserRegistrationComponent
  extends BasePageComponent<UserDataForNew>
  implements OnInit, OnDestroy {

  groupSets: Group[];
  groups: GroupForRegistration[];
  steps: RegistrationStep[] = ['group', 'idp', 'fields', 'confirm', 'done'];
  group: FormControl;
  form: FormGroup;
  mobileForm: FormGroup;
  landLineForm: FormGroup;
  defineAddress: FormControl;
  addressForm: FormGroup;
  confirmForm: FormGroup;
  image: Image;
  validationSub: Subscription;
  customImages: Image[] = [];
  customFiles: StoredFile[] = [];
  private identityProviderRequestId: string;

  step$ = new BehaviorSubject<RegistrationStep>(null);
  get step(): RegistrationStep {
    return this.step$.value;
  }
  set step(step: RegistrationStep) {
    this.step$.next(step);
  }

  result$ = new BehaviorSubject<UserRegistrationResult>(null);
  get result(): UserRegistrationResult {
    return this.result$.value;
  }
  set result(result: UserRegistrationResult) {
    this.result$.next(result);
  }

  constructor(
    injector: Injector,
    private usersService: UsersService,
    private userHelper: UserHelperService,
    private imagesService: ImagesService,
    private addressHelper: AddressHelperService,
    private nextRequestState: NextRequestState) {
    super(injector);
  }

  ngOnInit() {
    super.ngOnInit();

    const auth = this.login.auth || {};
    const role = auth.role;

    if (role == null) {
      // When guest, the possible groups are obtained from DataForUi
      this.initializeGroups(this.dataForUiHolder.dataForUi.publicRegistrationGroups);
    } else {
      // When admin / broker, fetch the possible registration groups from data, as they are more complete
      this.addSub(this.usersService.getUserDataForSearch({
        broker: role === RoleEnum.BROKER ? ApiHelper.SELF : null,
        fields: ['groupsForRegistration']
      }).subscribe(data => {
        this.groupSets = data.groupsForRegistration.filter(g => g.kind === GroupKind.GROUP_SET);
        const hasRootGroups = data.groupsForRegistration.find(g => g.kind !== GroupKind.GROUP_SET && g.groupSet == null);
        if (hasRootGroups) {
          this.groupSets.unshift(null);
        }
        this.initializeGroups(data.groupsForRegistration.filter(g => g.kind !== GroupKind.GROUP_SET));
      }));
    }
  }

  private initializeGroups(groups: (GroupForRegistration | Group)[]) {
    if (this.groups != null) {
      // Already initialized
      return;
    }
    this.groups = groups;
    if (empty(this.groups)) {
      // No possible registration groups - navigate to home
      this.router.navigateByUrl('/');
    } else {
      // Initialize the group value
      this.group = new FormControl(groups[0].id, Validators.required);
      if (groups.length === 1) {
        // When there's a single group, fetch the data already
        this.steps = this.steps.filter(s => s !== 'group');
        this.showFields();
      } else {
        // Initialize on the groups step
        this.step = 'group';
      }
    }
  }

  ngOnDestroy() {
    super.ngOnDestroy();
    if (this.image) {
      // When a temp image was uploaded, revoke its URL...
      URL.revokeObjectURL(this.image.url);

      // ... and remove it server-side
      this.errorHandler.requestWithCustomErrorHandler(() => {
        this.addSub(this.imagesService.deleteImage({ idOrKey: this.image.id }).subscribe());
      });<commit_msg>Error on registration when there's a single group<commit_after>import { ChangeDetectionStrategy, Component, Injector, OnDestroy, OnInit } from '@angular/core';
import { AbstractControl, AsyncValidatorFn, FormControl, FormGroup, ValidationErrors, ValidatorFn, Validators } from '@angular/forms';
import {
  AddressNew, AvailabilityEnum, Group, GroupForRegistration, GroupKind,
  IdentityProvider, IdentityProviderCallbackStatusEnum, Image, PhoneNew, RoleEnum, StoredFile,
  UserDataForNew, UserNew, UserRegistrationResult
} from 'app/api/models';
import { ImagesService, UsersService } from 'app/api/services';
import { AddressHelperService } from 'app/core/address-helper.service';
import { NextRequestState } from 'app/core/next-request-state';
import { UserHelperService } from 'app/core/user-helper.service';
import { ApiHelper } from 'app/shared/api-helper';
import { BasePageComponent } from 'app/shared/base-page.component';
import {
  blank, copyProperties, empty, focusFirstField, focusFirstInvalid,
  mergeValidity, scrollTop, setRootSpinnerVisible, validateBeforeSubmit
} from 'app/shared/helper';
import { Menu } from 'app/shared/menu';
import { BehaviorSubject, Observable, of, Subscription, timer } from 'rxjs';
import { first, map, switchMap } from 'rxjs/operators';

export type RegistrationStep = 'group' | 'idp' | 'fields' | 'confirm' | 'done';

/** Validator function that ensures password and confirmation match */
const SEGURITY_ANSWER_VAL: ValidatorFn = control => {
  if (control.touched) {
    const parent = control.parent;
    const question = parent.get('securityQuestion') == null ? '' : parent.get('securityQuestion').value;
    const answer = control.value;
    if (question != null && question !== '' && (answer == null || answer === '')) {
      return {
        required: true
      };
    }
  }
  return null;
};

/**
 * User registration. Works for guest, by admin and by broker
 */
@Component({
  selector: 'user-registration',
  templateUrl: 'user-registration.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserRegistrationComponent
  extends BasePageComponent<UserDataForNew>
  implements OnInit, OnDestroy {

  groupSets: Group[];
  groups: GroupForRegistration[];
  steps: RegistrationStep[] = ['group', 'idp', 'fields', 'confirm', 'done'];
  group: FormControl;
  form: FormGroup;
  mobileForm: FormGroup;
  landLineForm: FormGroup;
  defineAddress: FormControl;
  addressForm: FormGroup;
  confirmForm: FormGroup;
  image: Image;
  validationSub: Subscription;
  customImages: Image[] = [];
  customFiles: StoredFile[] = [];
  private identityProviderRequestId: string;

  step$ = new BehaviorSubject<RegistrationStep>(null);
  get step(): RegistrationStep {
    return this.step$.value;
  }
  set step(step: RegistrationStep) {
    this.step$.next(step);
  }

  result$ = new BehaviorSubject<UserRegistrationResult>(null);
  get result(): UserRegistrationResult {
    return this.result$.value;
  }
  set result(result: UserRegistrationResult) {
    this.result$.next(result);
  }

  constructor(
    injector: Injector,
    private usersService: UsersService,
    private userHelper: UserHelperService,
    private imagesService: ImagesService,
    private addressHelper: AddressHelperService,
    private nextRequestState: NextRequestState) {
    super(injector);
  }

  ngOnInit() {
    super.ngOnInit();

    const auth = this.login.auth || {};
    const role = auth.role;

    if (role == null) {
      // When guest, the possible groups are obtained from DataForUi
      this.initializeGroups(this.dataForUiHolder.dataForUi.publicRegistrationGroups);
    } else {
      // When admin / broker, fetch the possible registration groups from data, as they are more complete
      this.addSub(this.usersService.getUserDataForSearch({
        broker: role === RoleEnum.BROKER ? ApiHelper.SELF : null,
        fields: ['groupsForRegistration']
      }).subscribe(data => {
        this.groupSets = data.groupsForRegistration.filter(g => g.kind === GroupKind.GROUP_SET);
        const hasRootGroups = data.groupsForRegistration.find(g => g.kind !== GroupKind.GROUP_SET && g.groupSet == null);
        if (hasRootGroups) {
          this.groupSets.unshift(null);
        }
        this.initializeGroups(data.groupsForRegistration.filter(g => g.kind !== GroupKind.GROUP_SET));
      }));
    }
  }

  private initializeGroups(groups: (GroupForRegistration | Group)[]) {
    if (this.groups != null) {
      // Already initialized
      return;
    }
    this.groups = groups;
    if (empty(this.groups)) {
      // No possible registration groups - navigate to home
      this.router.navigateByUrl('/');
    } else {
      // Initialize the group value
      this.group = new FormControl(groups[0].id, Validators.required);
      if (groups.length === 1) {
        // When there's a single group, fetch the data already
        this.steps = this.steps.filter(s => s !== 'group');
        this.showIdentityProviders();
      } else {
        // Initialize on the groups step
        this.step = 'group';
      }
    }
  }

  ngOnDestroy() {
    super.ngOnDestroy();
    if (this.image) {
      // When a temp image was uploaded, revoke its URL...
      URL.revokeObjectURL(this.image.url);

      // ... and remove it server-side
      this.errorHandler.requestWithCustomErrorHandler(() => {
        this.addSub(this.imagesService.deleteImage({ idOrKey: this.image.id }).subscribe());
      });
{'fraction_non_alphanumeric': 0.12351914776379833, 'fraction_numerical': 0.0003673431903756084, 'mean_word_length': 3.730668983492615, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '528677', 'n_tokens_mistral': 3090, 'n_tokens_neox': 3052, 'n_words': 769}