register-form.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. import Ember from 'ember';
  2. import ValidatedForm from 'misago/components/forms/validated-form';
  3. export default ValidatedForm.extend({
  4. tagName: 'form',
  5. classNames: 'form-horizontal',
  6. zxcvbn: Ember.inject.service('zxcvbn'),
  7. isLoaded: false,
  8. loadError: null,
  9. isBusy: false,
  10. username: '',
  11. email: '',
  12. password: '',
  13. router: function() {
  14. return this.container.lookup('router:main');
  15. }.property(),
  16. passwordScore: function() {
  17. return this.get('zxcvbn').scorePassword(this.get('password'), [
  18. this.get('username'), this.get('email')
  19. ]);
  20. }.property('password', 'username', 'email'),
  21. passwordHelpText: function() {
  22. if (Ember.$.trim(this.get('password')).length === 0) {
  23. return null;
  24. }
  25. return [
  26. gettext('Password is very weak.'),
  27. gettext('Password is weak.'),
  28. gettext('Password is average.'),
  29. gettext('Password is strong.'),
  30. gettext('Password is very strong.')
  31. ][this.get('passwordScore')];
  32. }.property('password', 'username', 'email', 'passwordScore'),
  33. passwordBarWidth: function() {
  34. this.$('.progress-bar').css('width', ((this.get('passwordScore') + 1) * 20) + '%');
  35. }.observes('password', 'username', 'email', 'passwordScore'),
  36. passwordBarClass: function() {
  37. return 'progress-bar-' + [
  38. 'danger',
  39. 'warning',
  40. 'warning',
  41. 'primary',
  42. 'success'
  43. ][this.get('passwordScore')];
  44. }.property('password', 'username', 'email', 'passwordScore'),
  45. loadServices: function() {
  46. var self = this;
  47. var promises = [
  48. this.get('zxcvbn').load(),
  49. this.get('captcha').load()
  50. ];
  51. Ember.RSVP.allSettled(promises).then(function(array) {
  52. if (self.isDestroyed) { return; }
  53. if (array[0].state === 'rejected') {
  54. self.set('loadError', true);
  55. console.log('zxcvbn service failed to load.');
  56. }
  57. if (array[1].state === 'rejected') {
  58. self.set('loadError', true);
  59. console.log('captcha service failed to load.');
  60. }
  61. self.set('isLoaded', !self.get('loadError'));
  62. self.get('captcha').reset();
  63. });
  64. }.on('didInsertElement'),
  65. usernameValidation: function() {
  66. var state = true;
  67. var value = Ember.$.trim(this.get('username'));
  68. var valueLength = value.length;
  69. var limit = 0;
  70. var message = null;
  71. if (valueLength < this.get('settings.username_length_min')) {
  72. limit = this.get('settings.username_length_min');
  73. message = ngettext('Username must be at least %(limit)s character long.',
  74. 'Username must be at least %(limit)s characters long.',
  75. limit);
  76. state = [interpolate(message, {limit: limit}, true)];
  77. } else if (valueLength > this.get('settings.username_length_max')) {
  78. limit = this.get('settings.username_length_max');
  79. message = ngettext('Username cannot be longer than %(limit)s characters.',
  80. 'Username cannot be longer than %(limit)s characters.',
  81. limit);
  82. state = [interpolate(message, {limit: limit}, true)];
  83. } else if (!new RegExp('^[0-9a-z]+$', 'i').test(value)) {
  84. state = [gettext('Username can only contain latin alphabet letters and digits.')];
  85. }
  86. if (state === true) {
  87. this.set('validation.username', 'ok');
  88. } else {
  89. this.set('validation.username', state);
  90. }
  91. }.observes('username'),
  92. emailValidation: function() {
  93. var state = true;
  94. var value = Ember.$.trim(this.get('email'));
  95. var valueLength = value.length;
  96. var re = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
  97. if (valueLength < 4) {
  98. state = [gettext('Enter valid e-mail address')];
  99. } else if (!re.test(value)) {
  100. state = [gettext('Invalid e-mail address.')];
  101. }
  102. if (state === true) {
  103. this.set('validation.email', 'ok');
  104. } else {
  105. this.set('validation.email', state);
  106. }
  107. }.observes('email'),
  108. passwordValidation: function() {
  109. var state = true;
  110. var valueLength = Ember.$.trim(this.get('password')).length;
  111. var limit = this.get('settings.password_length_min');
  112. if (valueLength < limit) {
  113. var message = ngettext('Valid password must be at least %(limit)s character long.',
  114. 'Valid password must be at least %(limit)s characters long.',
  115. limit);
  116. state = [interpolate(message, {limit: limit}, true)];
  117. }
  118. if (state === true) {
  119. this.set('validation.password', 'ok');
  120. } else {
  121. this.set('validation.password', state);
  122. }
  123. }.observes('password'),
  124. captchaValidation: function() {
  125. this.set('validation.captcha', undefined);
  126. }.observes('captcha.value'),
  127. submit: function() {
  128. if (this.get('isBusy')) {
  129. return false;
  130. }
  131. var data = {
  132. username: Ember.$.trim(this.get('username')),
  133. email: Ember.$.trim(this.get('email')),
  134. password: Ember.$.trim(this.get('password')),
  135. captcha: Ember.$.trim(this.get('captcha.value'))
  136. };
  137. this.usernameValidation();
  138. this.emailValidation();
  139. this.passwordValidation();
  140. if (this.hasValidationErrors()) {
  141. this.toast.error(gettext("Form contains errors."));
  142. return false;
  143. }
  144. this.set('isBusy', true);
  145. var self = this;
  146. this.ajax.post('users', data
  147. ).then(function(response) {
  148. if (self.isDestroyed) { return; }
  149. self.success(response);
  150. }, function(jqXHR) {
  151. if (self.isDestroyed) { return; }
  152. self.error(jqXHR);
  153. }).finally(function() {
  154. if (self.isDestroyed) { return; }
  155. self.set('isBusy', false);
  156. });
  157. return false;
  158. },
  159. success: function(responseJSON) {
  160. this.get('captcha').reset();
  161. var model = Ember.Object.create(responseJSON);
  162. model.set('isActive', model.get('activation') === 'active');
  163. model.set('needsAdminActivation', model.get('activation') === 'activation_by_admin');
  164. this.modal.show('register-done-modal', model);
  165. },
  166. error: function(jqXHR) {
  167. var rejection = jqXHR.responseJSON;
  168. if (jqXHR.status === 400) {
  169. this.toast.error(gettext("Form contains errors."));
  170. this.get('validation').setProperties(jqXHR.responseJSON);
  171. if (!this.get('validation.captcha')) {
  172. this.get('captcha').pass();
  173. } else {
  174. this.get('captcha').refresh();
  175. }
  176. } else if (jqXHR.status === 403 && typeof rejection.ban !== 'undefined') {
  177. this.get('router').intermediateTransitionTo('error-banned', rejection.ban);
  178. this.modal.hide();
  179. } else {
  180. this.toast.apiError(jqXHR);
  181. }
  182. },
  183. showTermsFootnote: function() {
  184. return this.get('settings.terms_of_service') || this.get('settings.terms_of_service_link');
  185. }.property('settings')
  186. });