asyncForm.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /* eslint-disable
  2. max-len,
  3. no-return-assign,
  4. no-undef,
  5. no-unused-vars,
  6. */
  7. // TODO: This file was created by bulk-decaffeinate.
  8. // Fix any style issues and re-enable lint.
  9. /*
  10. * decaffeinate suggestions:
  11. * DS101: Remove unnecessary use of Array.from
  12. * DS102: Remove unnecessary code created because of implicit returns
  13. * DS207: Consider shorter variations of null checks
  14. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  15. */
  16. define(['base', 'libs/passfield'], function(App) {
  17. App.directive('asyncForm', ($http, validateCaptcha, validateCaptchaV3) => ({
  18. controller: [
  19. '$scope',
  20. function($scope) {
  21. this.getEmail = () => $scope.email
  22. return this
  23. }
  24. ],
  25. link(scope, element, attrs) {
  26. let response
  27. const formName = attrs.asyncForm
  28. scope[attrs.name].response = response = {}
  29. scope[attrs.name].inflight = false
  30. const validateCaptchaIfEnabled = function(callback) {
  31. if (callback == null) {
  32. callback = function(response) {}
  33. }
  34. if (attrs.captchaActionName) {
  35. validateCaptchaV3(attrs.captchaActionName)
  36. }
  37. if (attrs.captcha != null) {
  38. return validateCaptcha(callback)
  39. } else {
  40. return callback()
  41. }
  42. }
  43. const submitRequest = function(grecaptchaResponse) {
  44. const formData = {}
  45. for (var data of Array.from(element.serializeArray())) {
  46. formData[data.name] = data.value
  47. }
  48. if (grecaptchaResponse != null) {
  49. formData['g-recaptcha-response'] = grecaptchaResponse
  50. }
  51. scope[attrs.name].inflight = true
  52. // for asyncForm prevent automatic redirect to /login if
  53. // authentication fails, we will handle it ourselves
  54. const httpRequestFn = _httpRequestFn(element.attr('method'))
  55. return httpRequestFn(element.attr('action'), formData, {
  56. disableAutoLoginRedirect: true
  57. })
  58. .then(function(httpResponse) {
  59. const { data, headers } = httpResponse
  60. scope[attrs.name].inflight = false
  61. response.success = true
  62. response.error = false
  63. const onSuccessHandler = scope[attrs.onSuccess]
  64. if (onSuccessHandler) {
  65. onSuccessHandler(httpResponse)
  66. return
  67. }
  68. if (data.redir != null) {
  69. ga('send', 'event', formName, 'success')
  70. return (window.location = data.redir)
  71. } else if (data.message != null) {
  72. response.message = data.message
  73. if (data.message.type === 'error') {
  74. response.success = false
  75. response.error = true
  76. return ga('send', 'event', formName, 'failure', data.message)
  77. } else {
  78. return ga('send', 'event', formName, 'success')
  79. }
  80. } else if (scope.$eval(attrs.asyncFormDownloadResponse)) {
  81. const blob = new Blob([data], {
  82. type: headers('Content-Type')
  83. })
  84. location.href = URL.createObjectURL(blob) // Trigger file save
  85. }
  86. })
  87. .catch(function(httpResponse) {
  88. let config, headers, status
  89. ;({ data, status, headers, config } = httpResponse)
  90. scope[attrs.name].inflight = false
  91. response.success = false
  92. response.error = true
  93. response.status = status
  94. response.data = data
  95. const onErrorHandler = scope[attrs.onError]
  96. if (onErrorHandler) {
  97. onErrorHandler(httpResponse)
  98. return
  99. }
  100. if (status === 400 && data.accountLinkingError) {
  101. // Bad Request for account linking
  102. response.message = {
  103. text: data.accountLinkingError,
  104. type: 'error'
  105. }
  106. } else if (status === 400) {
  107. // Bad Request
  108. response.message = {
  109. text: 'Invalid Request. Please correct the data and try again.',
  110. type: 'error'
  111. }
  112. } else if (status === 403) {
  113. // Forbidden
  114. response.message = {
  115. text:
  116. 'Session error. Please check you have cookies enabled. If the problem persists, try clearing your cache and cookies.',
  117. type: 'error'
  118. }
  119. } else if (status === 429) {
  120. response.message = {
  121. text:
  122. 'Too many attempts. Please wait for a while and try again.',
  123. type: 'error'
  124. }
  125. } else {
  126. response.message = {
  127. text:
  128. (data.message != null ? data.message.text : undefined) ||
  129. data.message ||
  130. 'Something went wrong talking to the server :(. Please try again.',
  131. type: 'error'
  132. }
  133. }
  134. return ga('send', 'event', formName, 'failure', data.message)
  135. })
  136. }
  137. const submit = () =>
  138. validateCaptchaIfEnabled(response => submitRequest(response))
  139. const _httpRequestFn = (method = 'post') => {
  140. const $HTTP_FNS = {
  141. post: $http.post,
  142. get: $http.get
  143. }
  144. return $HTTP_FNS[method.toLowerCase()]
  145. }
  146. element.on('submit', function(e) {
  147. e.preventDefault()
  148. return submit()
  149. })
  150. if (attrs.autoSubmit) {
  151. return submit()
  152. }
  153. }
  154. }))
  155. App.directive('formMessages', () => ({
  156. restrict: 'E',
  157. template: `\
  158. <div class="alert" ng-class="{
  159. 'alert-danger': form.response.message.type == 'error',
  160. 'alert-success': form.response.message.type != 'error'
  161. }" ng-show="!!form.response.message" ng-bind-html="form.response.message.text">
  162. </div>
  163. <div ng-transclude></div>\
  164. `,
  165. transclude: true,
  166. scope: {
  167. form: '=for'
  168. }
  169. }))
  170. })