<commit_before>import Users from '../modules/index.js';
import { runCallbacks, runCallbacksAsync, Utils, debug, debugGroup, debugGroupEnd } from 'meteor/vulcan:lib'; // import from vulcan:lib because vulcan:core isn't loaded yet
import clone from 'lodash/clone';

// TODO: the following should use async/await, but async/await doesn't seem to work with Accounts.onCreateUser
function onCreateUserCallback(options, user) {
  debug('');
  debugGroup(`--------------- start \x1b[35m onCreateUser ---------------`);
  debug(`Options: ${JSON.stringify(options)}`);
  debug(`User: ${JSON.stringify(user)}`);

  const schema = Users.simpleSchema()._schema;

  delete options.password; // we don't need to store the password digest
  delete options.username; // username is already in user object

  options = runCallbacks({name: `user.create.validate.before`, iterator: options});
  // OpenCRUD backwards compatibility
  options = runCallbacks(`users.new.validate.before`, options);

  // validate options since they can't be trusted
  Users.simpleSchema().validate(options);

  // check that the current user has permission to insert each option field
  _.keys(options).forEach(fieldName => {
    var field = schema[fieldName];
    if (!field || !Users.canCreateField(user, field)) {
      throw new Error(Utils.encodeIntlError({ id: 'app.disallowed_property_detected', value: fieldName }));
    }
  });

  // extend user with options
  user = Object.assign(user, options);

  // run validation callbacks
  user = runCallbacks({name:`user.create.validate`, iterator: user});
  // OpenCRUD backwards compatibility
  user = runCallbacks(`users.new.validate`, user);

  // run onCreate step
  for(let fieldName of Object.keys(schema)) {
    let autoValue;
    if (schema[fieldName].onCreate) {
      // eslint-disable-next-line no-await-in-loop
      autoValue = schema[fieldName].onCreate({ newDocument: clone(user) });
    } else if (schema[fieldName].onInsert) {
      // OpenCRUD backwards compatibility
      // eslint-disable-next-line no-await-in-loop
      autoValue = schema[fieldName].onInsert(clone(user));
    }
    if (typeof autoValue !== 'undefined') {
      user[fieldName] = autoValue;
    }
  }

  user = runCallbacks('users.new.sync', user);

  runCallbacksAsync({name: "user.create.async", properties: {data: user}});
  // OpenCRUD backwards compatibility
  runCallbacksAsync("users.new.async", user);

  // check if all required fields have been filled in. If so, run profile completion callbacks
  if (Users.hasCompletedProfile(user)) {
    runCallbacksAsync("user.profileCompleted.async", user);
    // OpenCRUD backwards compatibility
    runCallbacksAsync("users.profileCompleted.async", user);<commit_msg>add `user.create.before` hook to classic signup workflow<commit_after>import Users from '../modules/index.js';
import { runCallbacks, runCallbacksAsync, Utils, debug, debugGroup, debugGroupEnd } from 'meteor/vulcan:lib'; // import from vulcan:lib because vulcan:core isn't loaded yet
import clone from 'lodash/clone';

// TODO: the following should use async/await, but async/await doesn't seem to work with Accounts.onCreateUser
function onCreateUserCallback(options, user) {
  debug('');
  debugGroup(`--------------- start \x1b[35m onCreateUser ---------------`);
  debug(`Options: ${JSON.stringify(options)}`);
  debug(`User: ${JSON.stringify(user)}`);

  const schema = Users.simpleSchema()._schema;

  delete options.password; // we don't need to store the password digest
  delete options.username; // username is already in user object

  options = runCallbacks({name: `user.create.validate.before`, iterator: options});
  // OpenCRUD backwards compatibility
  options = runCallbacks(`users.new.validate.before`, options);

  // validate options since they can't be trusted
  Users.simpleSchema().validate(options);

  // check that the current user has permission to insert each option field
  _.keys(options).forEach(fieldName => {
    var field = schema[fieldName];
    if (!field || !Users.canCreateField(user, field)) {
      throw new Error(Utils.encodeIntlError({ id: 'app.disallowed_property_detected', value: fieldName }));
    }
  });

  // extend user with options
  user = Object.assign(user, options);

  // run validation callbacks
  user = runCallbacks({name:`user.create.validate`, iterator: user});
  // OpenCRUD backwards compatibility
  user = runCallbacks(`users.new.validate`, user);

  // run onCreate step
  for(let fieldName of Object.keys(schema)) {
    let autoValue;
    if (schema[fieldName].onCreate) {
      // eslint-disable-next-line no-await-in-loop
      autoValue = schema[fieldName].onCreate({ newDocument: clone(user) });
    } else if (schema[fieldName].onInsert) {
      // OpenCRUD backwards compatibility
      // eslint-disable-next-line no-await-in-loop
      autoValue = schema[fieldName].onInsert(clone(user));
    }
    if (typeof autoValue !== 'undefined') {
      user[fieldName] = autoValue;
    }
  }
  user = runCallbacks({ name: 'user.create.before', iterator: user });
  user = runCallbacks('users.new.sync', user);

  runCallbacksAsync({name: "user.create.async", properties: {data: user}});
  // OpenCRUD backwards compatibility
  runCallbacksAsync("users.new.async", user);

  // check if all required fields have been filled in. If so, run profile completion callbacks
  if (Users.hasCompletedProfile(user)) {
    runCallbacksAsync("user.profileCompleted.async", user);
    // OpenCRUD backwards compatibility
    runCallbacksAsync("users.profileCompleted.async", user);
{'fraction_non_alphanumeric': 0.13838402015475976, 'fraction_numerical': 0.001079719272989023, 'mean_word_length': 3.9892280071813286, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, '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': '6265523', 'n_tokens_mistral': 1585, 'n_tokens_neox': 1558, 'n_words': 427}