asyncForm.js 5.7 KB

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