<commit_before>'use strict';

const helpers = require('../helpers');
const gambitCampaigns = require('../gambit-campaigns');
const logger = require('../logger');
const analytics = require('./analytics');
const UnprocessableEntityError = require('../../app/exceptions/UnprocessableEntityError');

const config = require('../../config/lib/helpers/request');

/**
 * Updates conversation with given topic, and updates user subscription status to pending if
 * the new topic is an askSubscriptionStatus.
 *
 * @param {Object} req
 * @param {Object} topic
 * @return {Promise}
 */
function changeTopic(req, topic) {
  module.exports.setTopic(req, topic);
  const topicId = topic.id;
  let promise = Promise.resolve();
  if (req.currentTopicId === topicId) {
    return promise;
  }
  if (helpers.topic.isAskSubscriptionStatus(topic) && req.userId) {
    promise = helpers.user.setPendingSubscriptionStatusForUserId(req.userId);
  }
  return promise.then(() => req.conversation.setTopic(topic));
}

/**
 * @param {Object} req
 * @param {Object} campaign
 * @return {Promise}
 */
function changeTopicByCampaign(req, campaign) {
  module.exports.setCampaign(req, campaign);
  if (!campaign.topics.length) {
    return Promise.reject(new Error('Campaign does not have any topics'));
  }
  // For now, each campaign only has one topic so we can get away with this.
  // In the future; signup messages will need to find the selected topic to set conversation to
  // if a campaign supports multiple topics at once.
  // Broadcasts will eventually be topic specific instead of campaign specific, meaning we would
  // no longer call this function from the broadcast middleware, we'd have a nested topic object
  // included in a get broadcast lookup.
  const topic = campaign.topics[0];
  // Inject a campaign property into the topic, as we'll need it for the call to changeTopic.
  topic.campaign = campaign;
  return module.exports.changeTopic(req, topic);
}

/**
 * @param {Object} req
 * @return {Promise}
 */
async function executeRivescriptTopicChange(req) {
  const topicId = req.rivescriptReplyTopicId;
  logger.info('executeRivescriptTopicChange', { topicId, userId: req.userId }, req);

  const topic = await helpers.topic.getById(topicId);
  logger.debug('helpers.topic.getById success', { topicId }, req);

  if (helpers.topic.hasCampaign(topic)) {
    const signup = await helpers.user.createSignup(req.user, topic.campaign.id, req.platform);
    logger.debug('createdSignup', { signup });
  }

  return module.exports.changeTopic(req, topic);
}

/**
 * Changes conversation topic to the saidNo template topic.
 *
 * @param {Object} req
 * @return {Promise}
 */
async function executeSaidNoMacro(req, res) {
  // Ideally we'd want to set req.broadcastId here to record a saidNo macro stat, but the trouble
  // is then the next inbound message will have a req.broadcastId set because the last outbound
  // had one, which feels like some logic we may be outgrowing soon.
  const saidNoTemplate = req.topic.templates.saidNo;
  // Although saidNoTopic is a required field, check that an id exists (it may not if this is a
  // draft entry and we're using the Preview API.
  if (!saidNoTemplate.topic.id) {<commit_msg>Logs req for signup creation per https://github.com/DoSomething/gambit-conversations/pull/434/files#r231269706<commit_after>'use strict';

const helpers = require('../helpers');
const gambitCampaigns = require('../gambit-campaigns');
const logger = require('../logger');
const analytics = require('./analytics');
const UnprocessableEntityError = require('../../app/exceptions/UnprocessableEntityError');

const config = require('../../config/lib/helpers/request');

/**
 * Updates conversation with given topic, and updates user subscription status to pending if
 * the new topic is an askSubscriptionStatus.
 *
 * @param {Object} req
 * @param {Object} topic
 * @return {Promise}
 */
function changeTopic(req, topic) {
  module.exports.setTopic(req, topic);
  const topicId = topic.id;
  let promise = Promise.resolve();
  if (req.currentTopicId === topicId) {
    return promise;
  }
  if (helpers.topic.isAskSubscriptionStatus(topic) && req.userId) {
    promise = helpers.user.setPendingSubscriptionStatusForUserId(req.userId);
  }
  return promise.then(() => req.conversation.setTopic(topic));
}

/**
 * @param {Object} req
 * @param {Object} campaign
 * @return {Promise}
 */
function changeTopicByCampaign(req, campaign) {
  module.exports.setCampaign(req, campaign);
  if (!campaign.topics.length) {
    return Promise.reject(new Error('Campaign does not have any topics'));
  }
  // For now, each campaign only has one topic so we can get away with this.
  // In the future; signup messages will need to find the selected topic to set conversation to
  // if a campaign supports multiple topics at once.
  // Broadcasts will eventually be topic specific instead of campaign specific, meaning we would
  // no longer call this function from the broadcast middleware, we'd have a nested topic object
  // included in a get broadcast lookup.
  const topic = campaign.topics[0];
  // Inject a campaign property into the topic, as we'll need it for the call to changeTopic.
  topic.campaign = campaign;
  return module.exports.changeTopic(req, topic);
}

/**
 * @param {Object} req
 * @return {Promise}
 */
async function executeRivescriptTopicChange(req) {
  const topicId = req.rivescriptReplyTopicId;
  logger.info('executeRivescriptTopicChange', { topicId, userId: req.userId }, req);

  const topic = await helpers.topic.getById(topicId);
  logger.debug('helpers.topic.getById success', { topicId }, req);

  if (helpers.topic.hasCampaign(topic)) {
    const signup = await helpers.user.createSignup(req.user, topic.campaign.id, req.platform);
    logger.debug('createdSignup', { signup }, req);
  }

  return module.exports.changeTopic(req, topic);
}

/**
 * Changes conversation topic to the saidNo template topic.
 *
 * @param {Object} req
 * @return {Promise}
 */
async function executeSaidNoMacro(req, res) {
  // Ideally we'd want to set req.broadcastId here to record a saidNo macro stat, but the trouble
  // is then the next inbound message will have a req.broadcastId set because the last outbound
  // had one, which feels like some logic we may be outgrowing soon.
  const saidNoTemplate = req.topic.templates.saidNo;
  // Although saidNoTopic is a required field, check that an id exists (it may not if this is a
  // draft entry and we're using the Preview API.
  if (!saidNoTemplate.topic.id) {
{'fraction_non_alphanumeric': 0.11509029690847873, 'fraction_numerical': 0.0021426385062748698, 'mean_word_length': 4.125490196078432, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 1, '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': '2605380', 'n_tokens_mistral': 1891, 'n_tokens_neox': 1875, 'n_words': 645}