return sortedPermissionNames.map(function (permissionName) {
        var permission = self._getPermissionConfig(permissionName);
        if (permission.required !== true) {
          permission.required = false;
        }

        // convert label to the required label
        if (permission.required) {
          permission.label = Strings.interpolate(requiredPermissionLabel, {
            permissionName: permission.label
          });
        }

        // value is visible unless overridden
        if (permission.valueVisible !== false) {
          permission.valueVisible = true;
        }

        // permission as a whole is visible unless overridden
        if (permission.visible !== false) {
          permission.visible = true;
        }

        var accountKey = Account.PERMISSIONS_TO_KEYS[permissionName];
        permission.value = account.get(accountKey);

        return permission;
      }).map(PermissionTemplate).join('\n');
Example #2
0
 .then(() => {
   this.updateDisplayEmail(email);
   this.displaySuccess(Strings.interpolate(t('Primary email set to %(email)s'), { email }), {
     closePanel: false
   });
   this.render();
 });
    logViewEvent: function (viewName, eventName) {
      var event = Strings.interpolate('%(viewName)s.%(eventName)s', {
        eventName: eventName,
        viewName: viewName,
      });

      this.logEvent(event);
    },
Example #4
0
 it('can do string interpolation on named `%(name)s` when given array context', function () {
   var stringToInterpolate = 'Error encountered trying to register: %(email)s.';
   var interpolated = Strings.interpolate(stringToInterpolate, {
     email: 'testuser@testuser.com'
   });
   assert.equal(interpolated,
     'Error encountered trying to register: testuser@testuser.com.');
 });
 errorToId: function (error) {
   var id = Strings.interpolate('error.%s.%s.%s', [
     error.context || 'unknown context',
     error.namespace || 'unknown namespace',
     error.errno || String(error)
   ]);
   return id;
 },
Example #6
0
    toInterpolatedMessage: function (err, translator) {
      var msg = this.toMessage(err);
      var interpolationContext = this.toInterpolationContext(err);
      if (translator) {
        return translator.get(msg, interpolationContext);
      }

      return Strings.interpolate(msg, interpolationContext);
    },
Example #7
0
    it('can do interpolation multiple times with an array', function () {
      var stringToInterpolate = 'Hi %s, you have been signed in since %s';
      var interpolated = Strings.interpolate(stringToInterpolate, [
        'testuser@testuser.com', 'noon'
      ]);

      assert.equal(interpolated,
        'Hi testuser@testuser.com, you have been signed in since noon');
    });
Example #8
0
    it('can do interpolation multiple times with an object', function () {
      var stringToInterpolate = 'Hi %(email)s, you have been signed in since %(time)s';
      var interpolated = Strings.interpolate(stringToInterpolate, {
        email: 'testuser@testuser.com',
        time: 'noon'
      });

      assert.equal(interpolated,
        'Hi testuser@testuser.com, you have been signed in since noon');
    });
Example #9
0
define(function (require, exports, module) {
  'use strict';

  const _ = require('underscore');
  const Errors = require('lib/errors');
  const Logger = require('lib/logger');
  var logger = new Logger();
  const Strings = require('lib/strings');

  var t = function (msg) {
    return msg;
  };

  var UNEXPECTED_ERROR = t('Unexpected error');

  /*eslint-disable sorting/sort-object-props*/
  var ERRORS = {
    UNKNOWN_CLIENT: {
      errno: 101,
      message: t('Unknown client')
    },
    INCORRECT_REDIRECT: {
      errno: 103,
      message: t('Incorrect redirect_uri')
    },
    INVALID_ASSERTION: {
      errno: 104,
      message: t('Invalid assertion')
    },
    UNKNOWN_CODE: {
      errno: 105,
      message: t('Unknown code')
    },
    INCORRECT_CODE: {
      errno: 106,
      message: t('Incorrect code')
    },
    EXPIRED_CODE: {
      errno: 107,
      message: t('Expired code')
    },
    INVALID_TOKEN: {
      errno: 108,
      message: t('Invalid token')
    },
    INVALID_PARAMETER: {
      errno: 109,
      message: t('Invalid OAuth parameter: %(param)s')
    },
    INVALID_RESPONSE_TYPE: {
      errno: 110,
      message: UNEXPECTED_ERROR
    },
    UNAUTHORIZED: {
      errno: 111,
      message: t('Unauthorized')
    },
    FORBIDDEN: {
      errno: 112,
      message: t('Forbidden')
    },
    INVALID_CONTENT_TYPE: {
      errno: 113,
      message: UNEXPECTED_ERROR
    },
    INVALID_SCOPES: {
      errno: 114,
      message: Strings.interpolate(
        // `scope` should not be translated, so interpolate it in.
        t('Invalid OAuth parameter: %(param)s'), { param: 'scope' })
    },
    SERVICE_UNAVAILABLE: {
      errno: 998,
      message: t('System unavailable, try again soon')
    },
    UNEXPECTED_ERROR: {
      errno: 999,
      message: UNEXPECTED_ERROR
    },
    TRY_AGAIN: {
      errno: 1000,
      message: t('Something went wrong. Please close this tab and try again.')
    },
    INVALID_RESULT: {
      errno: 1001,
      message: UNEXPECTED_ERROR
    },
    INVALID_RESULT_REDIRECT: {
      errno: 1002,
      message: UNEXPECTED_ERROR
    },
    INVALID_RESULT_CODE: {
      errno: 1003,
      message: UNEXPECTED_ERROR
    },
    USER_CANCELED_OAUTH_LOGIN: {
      errno: 1004,
      message: t('no message')
    },
    MISSING_PARAMETER: {
      errno: 1005,
      message: t('Missing OAuth parameter: %(param)s')
    }
  };
  /*eslint-enable sorting/sort-object-props*/

  module.exports = _.extend({}, Errors, {
    ERRORS: ERRORS,
    NAMESPACE: 'oauth',

    /**
     * Fetch the interpolation context out of the server error.
     * @param {Error} err
     * @returns {Object}
     */
    toInterpolationContext (err) {
      // For data returned by backend, see
      // https://github.com/mozilla/fxa-oauth-server/blob/master/docs/api.md#errors
      try {
        if (this.is(err, 'MISSING_PARAMETER')) {
          return {
            param: err.param
          };
        } else if (this.is(err, 'INVALID_PARAMETER')) {
          return {
            param: err.param || err.validation.keys.join(',')
          };
        }
      } catch (e) {
        // handle invalid/unexpected data from the backend.
        logger.error('Error in oauth-errors.js->toInterpolationContext: %s', String(e));
      }

      return {};
    }
  });
});
define(function (require, exports, module) {
  'use strict';

  const _ = require('underscore');
  const $ = require('jquery');
  const BaseView = require('views/base');
  const Cocktail = require('cocktail');
  const Constants = require('lib/constants');
  const Strings = require('lib/strings');
  const Template = require('stache!templates/marketing_snippet');
  const UserAgentMixin = require('lib/user-agent-mixin');
  const VerificationReasonMixin = require('views/mixins/verification-reason-mixin');

  const APP_STORE_BUTTON = 'apple_app_store_button';
  const PLAY_STORE_BUTTON = 'google_play_store_button';

  const FORMAT_SVG = 'svg';
  const FORMAT_PNG = 'png';

  const playStoreImageLanguages = [
    'ca',
    'cs',
    'da',
    'de',
    'en',
    'es',
    'et',
    'fr',
    'hu',
    'id',
    'it',
    'ja',
    'ko',
    'lt',
    'nb-NO',
    'nl',
    'pl',
    'pt-BR',
    'pt',
    'ru',
    'sk',
    'sl',
    'sv',
    'tr',
    'uk',
    'zh-CN',
    'zh-TW'
  ];

  const View = BaseView.extend({
    template: Template,

    /**
     * Initialize.
     *
     * @param {Object} [options={}]
     *  @param {String} [options.marketingId] - marketing ID to use for logging.
     *   Defaults to Constants.MARKETING_ID_SPRING_2015.
     *  @param {String} [options.service] - the service being signed in to.
     *  @param {String} [options.which] - force a logo to be displayed.
     *   Defaults to `undefined`
     */
    initialize (options = {}) {
      this._marketingId = options.marketingId || Constants.MARKETING_ID_SPRING_2015;
      this._service = options.service;
      this._which = options.which;
    },

    events: {
      'click .marketing-link': '_onMarketingClick'
    },

    setInitialContext (context) {
      const showSignUpMarketing = this._shouldShowSignUpMarketing();
      const isIos = this._isIos();
      const isAndroid = this._isAndroid();
      const isOther = this._isOther();
      const downloadLinkAndroid = this._storeLink(Constants.DOWNLOAD_LINK_TEMPLATE_ANDROID);
      const playStoreImage = this._storeImage(PLAY_STORE_BUTTON, FORMAT_PNG);
      const downloadLinkIos = this._storeLink(Constants.DOWNLOAD_LINK_TEMPLATE_IOS);
      const appStoreImage = this._storeImage(APP_STORE_BUTTON, FORMAT_SVG);

      const marketingId = this._marketingId;
      const isAutumn2016 = marketingId === Constants.MARKETING_ID_AUTUMN_2016;
      const isSpring2015 = marketingId === Constants.MARKETING_ID_SPRING_2015;

      context.set({
        appStoreImage,
        downloadLinkAndroid,
        downloadLinkIos,
        isAndroid,
        isAutumn2016,
        isIos,
        isOther,
        isSpring2015,
        marketingId,
        playStoreImage,
        showSignUpMarketing
      });
    },

    afterRender () {
      this.$('.marketing-link').each((index, element) => {
        this._logMarketingImpression(element);
      });

      // Add the marketingId as a class so that different styles
      // can be applied to different snippets.
      this.$el.addClass(this._marketingId);
    },

    _shouldShowSignUpMarketing () {
      const hasBrokerSupport = this.broker.hasCapability('emailVerificationMarketingSnippet');
      const isFirefoxMobile = this._isFirefoxMobile();
      const isSignIn = this.isSignIn();
      const isSignUp = this.isSignUp();
      const isSync = this._service === Constants.SYNC_SERVICE;

      return !! this._which || // if _which is set, display is considered forced.
             (hasBrokerSupport && (isSignUp || isSignIn) && isSync && ! isFirefoxMobile);
    },

    _isFirefoxMobile () {
      const uap = this.getUserAgent();
      return uap.isFirefoxIos() || uap.isFirefoxAndroid();
    },

    _isIos () {
      // if _which is set, ignore the userAgent
      return (! this._which && this.getUserAgent().isIos()) || this._which === View.WHICH.IOS;
    },

    _isAndroid () {
      return (! this._which && this.getUserAgent().isAndroid()) || this._which === View.WHICH.ANDROID;
    },

    _isOther () {
      return (! this._isIos() && ! this._isAndroid()) || this._which === View.WHICH.BOTH;
    },

    /**
     * Add the appropriate metrics related query params to
     * the Firefox app's app store link.
     *
     * @param {String} base
     * @returns {String}
     */
    _storeLink (base) {
      return Strings.interpolate(base, {
        campaign: 'fxa-conf-page',
        creative: View.BUTTON_IDS[this._marketingId],
      });
    },

    _storeImage (buttonDir, imageFormat) {
      let buttonPath = _.contains(playStoreImageLanguages, this.lang) ?
                          this.lang : 'en';

      if (this._isHighRes() && imageFormat === FORMAT_PNG) {
        buttonPath += '@2x';
      }

      return '/images/' + buttonDir + '/' + buttonPath + '.' + imageFormat;
    },

    _isHighRes () {
      const win = this.window;

      return !! (win.matchMedia && win.matchMedia('(-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 1.5dppx), (min-resolution: 144dpi)'));
    },

    _logMarketingImpression (element) {
      const { id, type, url } = this._getMarketingLinkInfo(element);
      this.metrics.logMarketingImpression(id, url);
      this.notifier.trigger('marketing.impression', {
        id, type, url
      });
    },

    _onMarketingClick (event) {
      this._logMarketingClick(event.currentTarget);
    },

    _logMarketingClick (element) {
      const { id, type, url } = this._getMarketingLinkInfo(element);
      this.metrics.logMarketingClick(id, url);
      this.notifier.trigger('marketing.clicked', {
        id, type, url
      });
    },

    _getMarketingLinkInfo (element) {
      const $element = $(element);

      const id = $element.data('marketing-id');
      const type = $element.data('marketing-type');
      const url = $element.attr('href');

      return { id, type, url };
    }
  }, {
    BUTTON_IDS: {
      [Constants.MARKETING_ID_AUTUMN_2016]: 'button-autumn-2016-connect-another-device',
      [Constants.MARKETING_ID_SPRING_2015]: 'button'
    },
    WHICH: {
      ANDROID: 'android',
      BOTH: 'both',
      IOS: 'ios'
    }
  });

  Cocktail.mixin(
    View,
    UserAgentMixin,
    VerificationReasonMixin
  );

  module.exports = View;
});
Example #11
0
    it('leaves remaining %s if not enough items in context', function () {
      var stringToInterpolate = 'Hi %s, you have been signed in since %s';
      var interpolated = Strings.interpolate(stringToInterpolate, ['testuser@testuser.com']);

      assert.equal(interpolated, 'Hi testuser@testuser.com, you have been signed in since %s');
    });
Example #12
0
    it('does no replacement on %s and %(name)s if not in context', function () {
      var stringToInterpolate = 'Hi %s, you have been signed in since %(time)s';
      var interpolated = Strings.interpolate(stringToInterpolate);

      assert.equal(interpolated, stringToInterpolate);
    });
Example #13
0
 it('can do string interpolation on unnamed `%s` when given array context', function () {
   var stringToInterpolate = 'Hi %s, this is interpolated.';
   var interpolated = Strings.interpolate(stringToInterpolate, ['testuser@testuser.com']);
   assert.equal(interpolated,
     'Hi testuser@testuser.com, this is interpolated.');
 });