You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

usePersonalAccessToken.ts 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2024 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. import { useEffect, useState } from 'react';
  21. import {
  22. checkPersonalAccessTokenIsValid,
  23. setAlmPersonalAccessToken,
  24. } from '../../../api/alm-integrations';
  25. import { translate } from '../../../helpers/l10n';
  26. import { AlmSettingsInstance } from '../../../types/alm-settings';
  27. import { tokenExistedBefore } from './utils';
  28. export interface PATType {
  29. validationFailed: boolean;
  30. validationErrorMessage?: string;
  31. touched: boolean;
  32. password: string;
  33. username?: string;
  34. submitting: boolean;
  35. checkingPat: boolean;
  36. firstConnection: boolean;
  37. handleUsernameChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
  38. handlePasswordChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
  39. handleSubmit: (e: React.SyntheticEvent<HTMLFormElement>) => Promise<void>;
  40. }
  41. export const usePersonalAccessToken = (
  42. almSetting: AlmSettingsInstance,
  43. resetPat: boolean,
  44. onPersonalAccessTokenCreated: () => void,
  45. ): PATType => {
  46. const [checkingPat, setCheckingPat] = useState(false);
  47. const [touched, setTouched] = useState(false);
  48. const [password, setPassword] = useState('');
  49. const [submitting, setSubmitting] = useState(false);
  50. const [validationFailed, setValidationFailed] = useState(false);
  51. const [validationErrorMessage, setValidationErrorMessage] = useState<string | undefined>();
  52. const [firstConnection, setFirstConnection] = useState(false);
  53. const [username, setUsername] = useState('');
  54. useEffect(() => {
  55. const checkPATAndUpdateView = async () => {
  56. const { key } = almSetting;
  57. // We don't need to check PAT if we want to reset
  58. if (!resetPat) {
  59. setCheckingPat(true);
  60. const { patIsValid, error } = await checkPersonalAccessTokenIsValid(key)
  61. .then(({ status, error }) => ({ patIsValid: status, error }))
  62. .catch(() => ({ patIsValid: status, error: translate('default_error_message') }));
  63. if (patIsValid) {
  64. onPersonalAccessTokenCreated();
  65. return;
  66. }
  67. // This is the initial message when no token was provided
  68. if (tokenExistedBefore(error)) {
  69. setCheckingPat(false);
  70. setFirstConnection(true);
  71. } else {
  72. setCheckingPat(false);
  73. setValidationFailed(true);
  74. setValidationErrorMessage(error);
  75. }
  76. }
  77. };
  78. checkPATAndUpdateView();
  79. }, [almSetting, resetPat, onPersonalAccessTokenCreated]);
  80. const handleUsernameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
  81. setTouched(true);
  82. setUsername(event.target.value);
  83. };
  84. const handlePasswordChange = (event: React.ChangeEvent<HTMLInputElement>) => {
  85. setTouched(true);
  86. setPassword(event.target.value);
  87. };
  88. const handleSubmit = async (e: React.SyntheticEvent<HTMLFormElement>) => {
  89. const { key } = almSetting;
  90. e.preventDefault();
  91. if (password) {
  92. setSubmitting(true);
  93. await setAlmPersonalAccessToken(key, password, username).catch(() => {
  94. /* Set will not check pat validity. We need to check again so we will catch issue after */
  95. });
  96. const { status, error } = await checkPersonalAccessTokenIsValid(key)
  97. .then(({ status, error }) => ({ status, error }))
  98. .catch(() => ({ status: false, error: translate('default_error_message') }));
  99. if (status) {
  100. // Let's reset status,
  101. setCheckingPat(false);
  102. setTouched(false);
  103. setPassword('');
  104. setSubmitting(false);
  105. setUsername('');
  106. setValidationFailed(false);
  107. onPersonalAccessTokenCreated();
  108. } else {
  109. setSubmitting(false);
  110. setTouched(false);
  111. setValidationFailed(true);
  112. setValidationErrorMessage(error);
  113. }
  114. }
  115. };
  116. return {
  117. username,
  118. password,
  119. firstConnection,
  120. validationFailed,
  121. touched,
  122. submitting,
  123. checkingPat,
  124. validationErrorMessage,
  125. handleUsernameChange,
  126. handlePasswordChange,
  127. handleSubmit,
  128. };
  129. };