Browse Source

Merge branch 'from/develop/tusooa/migration-ui' into 'develop'

Add ui for account migration

See merge request pleroma/pleroma-fe!1414
HJ 2 years ago
parent
commit
56501e95c4

+ 1 - 0
CHANGELOG.md

@@ -37,6 +37,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - Media modal now also displays description and counter position in gallery (i.e. 1/5)
 - Media modal now also displays description and counter position in gallery (i.e. 1/5)
 - Ability to rearrange order of attachments when uploading
 - Ability to rearrange order of attachments when uploading
 - Enabled users to zoom and pan images in media viewer with mouse and touch
 - Enabled users to zoom and pan images in media viewer with mouse and touch
+- Added frontend ui for account migration
 
 
 
 
 ## [2.4.2] - 2022-01-09
 ## [2.4.2] - 2022-01-09

+ 54 - 1
src/components/settings_modal/tabs/security_tab/security_tab.js

@@ -15,11 +15,21 @@ const SecurityTab = {
       deleteAccountError: false,
       deleteAccountError: false,
       changePasswordInputs: [ '', '', '' ],
       changePasswordInputs: [ '', '', '' ],
       changedPassword: false,
       changedPassword: false,
-      changePasswordError: false
+      changePasswordError: false,
+      moveAccountTarget: '',
+      moveAccountPassword: '',
+      movedAccount: false,
+      moveAccountError: false,
+      aliases: [],
+      listAliasesError: false,
+      addAliasTarget: '',
+      addedAlias: false,
+      addAliasError: false
     }
     }
   },
   },
   created () {
   created () {
     this.$store.dispatch('fetchTokens')
     this.$store.dispatch('fetchTokens')
+    this.fetchAliases()
   },
   },
   components: {
   components: {
     ProgressButton,
     ProgressButton,
@@ -92,6 +102,49 @@ const SecurityTab = {
           }
           }
         })
         })
     },
     },
+    moveAccount () {
+      const params = {
+        targetAccount: this.moveAccountTarget,
+        password: this.moveAccountPassword
+      }
+      this.$store.state.api.backendInteractor.moveAccount(params)
+        .then((res) => {
+          if (res.status === 'success') {
+            this.movedAccount = true
+            this.moveAccountError = false
+          } else {
+            this.movedAccount = false
+            this.moveAccountError = res.error
+          }
+        })
+    },
+    removeAlias (alias) {
+      this.$store.state.api.backendInteractor.deleteAlias({ alias })
+        .then(() => this.fetchAliases())
+    },
+    addAlias () {
+      this.$store.state.api.backendInteractor.addAlias({ alias: this.addAliasTarget })
+        .then((res) => {
+          this.addedAlias = true
+          this.addAliasError = false
+          this.addAliasTarget = ''
+        })
+        .catch((error) => {
+          this.addedAlias = false
+          this.addAliasError = error
+        })
+        .then(() => this.fetchAliases())
+    },
+    fetchAliases () {
+      this.$store.state.api.backendInteractor.listAliases()
+        .then((res) => {
+          this.aliases = res.aliases
+          this.listAliasesError = false
+        })
+        .catch((error) => {
+          this.listAliasesError = error.error
+        })
+    },
     logout () {
     logout () {
       this.$store.dispatch('logout')
       this.$store.dispatch('logout')
       this.$router.replace('/')
       this.$router.replace('/')

+ 108 - 0
src/components/settings_modal/tabs/security_tab/security_tab.vue

@@ -103,6 +103,114 @@
       </table>
       </table>
     </div>
     </div>
     <mfa />
     <mfa />
+
+    <div class="setting-item">
+      <h2>{{ $t('settings.account_alias') }}</h2>
+      <table>
+        <thead>
+          <tr>
+            <th>{{ $t('settings.account_alias_table_head') }}</th>
+            <th />
+          </tr>
+        </thead>
+        <tbody>
+          <tr
+            v-for="alias in aliases"
+            :key="alias"
+          >
+            <td>{{ alias }}</td>
+            <td class="actions">
+              <button
+                class="btn button-default"
+                @click="removeAlias(alias)"
+              >
+                {{ $t('settings.remove_alias') }}
+              </button>
+            </td>
+          </tr>
+        </tbody>
+      </table>
+      <div
+        v-if="listAliasesError"
+        class="alert error"
+      >
+        {{ $t('settings.list_aliases_error', { error }) }}
+        <FAIcon
+          class="fa-scale-110 fa-old-padding"
+          icon="times"
+          :title="$t('settings.hide_list_aliases_error_action')"
+          @click="listAliasesError = false"
+        />
+      </div>
+      <div>
+        <i18n
+          path="settings.new_alias_target"
+          tag="p"
+        >
+          <code
+            place="example"
+          >
+            foo@example.org
+          </code>
+        </i18n>
+        <input
+          v-model="addAliasTarget"
+        >
+      </div>
+      <button
+        class="btn button-default"
+        @click="addAlias"
+      >
+        {{ $t('settings.save') }}
+      </button>
+      <p v-if="addedAlias">
+        {{ $t('settings.added_alias') }}
+      </p>
+      <template v-if="addAliasError !== false">
+        <p>{{ $t('settings.add_alias_error', { error: addAliasError }) }}</p>
+      </template>
+    </div>
+
+    <div class="setting-item">
+      <h2>{{ $t('settings.move_account') }}</h2>
+      <p>{{ $t('settings.move_account_notes') }}</p>
+      <div>
+        <i18n
+          path="settings.move_account_target"
+          tag="p"
+        >
+          <code
+            place="example"
+          >
+            foo@example.org
+          </code>
+        </i18n>
+        <input
+          v-model="moveAccountTarget"
+        >
+      </div>
+      <div>
+        <p>{{ $t('settings.current_password') }}</p>
+        <input
+          v-model="moveAccountPassword"
+          type="password"
+          autocomplete="current-password"
+        >
+      </div>
+      <button
+        class="btn button-default"
+        @click="moveAccount"
+      >
+        {{ $t('settings.save') }}
+      </button>
+      <p v-if="movedAccount">
+        {{ $t('settings.moved_account') }}
+      </p>
+      <template v-if="moveAccountError !== false">
+        <p>{{ $t('settings.move_account_error', { error: moveAccountError }) }}</p>
+      </template>
+    </div>
+
     <div class="setting-item">
     <div class="setting-item">
       <h2>{{ $t('settings.delete_account') }}</h2>
       <h2>{{ $t('settings.delete_account') }}</h2>
       <p v-if="!deletingAccount">
       <p v-if="!deletingAccount">

+ 13 - 0
src/i18n/en.json

@@ -352,6 +352,19 @@
     "delete_account_description": "Permanently delete your data and deactivate your account.",
     "delete_account_description": "Permanently delete your data and deactivate your account.",
     "delete_account_error": "There was an issue deleting your account. If this persists please contact your instance administrator.",
     "delete_account_error": "There was an issue deleting your account. If this persists please contact your instance administrator.",
     "delete_account_instructions": "Type your password in the input below to confirm account deletion.",
     "delete_account_instructions": "Type your password in the input below to confirm account deletion.",
+    "account_alias": "Account aliases",
+    "account_alias_table_head": "Alias",
+    "list_aliases_error": "Error fetching aliases: {error}",
+    "hide_list_aliases_error_action": "Close",
+    "remove_alias": "Remove this alias",
+    "new_alias_target": "Add a new alias (e.g. {example})",
+    "added_alias": "Alias is added.",
+    "add_alias_error": "Error adding alias: {error}",
+    "move_account": "Move account",
+    "move_account_notes": "If you want to move the account somewhere else, you must go to your target account and add an alias pointing here.",
+    "move_account_target": "Target account (e.g. {example})",
+    "moved_account": "Account is moved.",
+    "move_account_error": "Error moving account: {error}",
     "discoverable": "Allow discovery of this account in search results and other services",
     "discoverable": "Allow discovery of this account in search results and other services",
     "domain_mutes": "Domains",
     "domain_mutes": "Domains",
     "avatar_size_instruction": "The recommended minimum size for avatar images is 150x150 pixels.",
     "avatar_size_instruction": "The recommended minimum size for avatar images is 150x150 pixels.",

+ 49 - 0
src/services/api/api.service.js

@@ -9,6 +9,8 @@ const FOLLOW_IMPORT_URL = '/api/pleroma/follow_import'
 const DELETE_ACCOUNT_URL = '/api/pleroma/delete_account'
 const DELETE_ACCOUNT_URL = '/api/pleroma/delete_account'
 const CHANGE_EMAIL_URL = '/api/pleroma/change_email'
 const CHANGE_EMAIL_URL = '/api/pleroma/change_email'
 const CHANGE_PASSWORD_URL = '/api/pleroma/change_password'
 const CHANGE_PASSWORD_URL = '/api/pleroma/change_password'
+const MOVE_ACCOUNT_URL = '/api/pleroma/move_account'
+const ALIASES_URL = '/api/pleroma/aliases'
 const TAG_USER_URL = '/api/pleroma/admin/users/tag'
 const TAG_USER_URL = '/api/pleroma/admin/users/tag'
 const PERMISSION_GROUP_URL = (screenName, right) => `/api/pleroma/admin/users/${screenName}/permission_group/${right}`
 const PERMISSION_GROUP_URL = (screenName, right) => `/api/pleroma/admin/users/${screenName}/permission_group/${right}`
 const ACTIVATE_USER_URL = '/api/pleroma/admin/users/activate'
 const ACTIVATE_USER_URL = '/api/pleroma/admin/users/activate'
@@ -790,6 +792,49 @@ const changeEmail = ({ credentials, email, password }) => {
     .then((response) => response.json())
     .then((response) => response.json())
 }
 }
 
 
+const moveAccount = ({ credentials, password, targetAccount }) => {
+  const form = new FormData()
+
+  form.append('password', password)
+  form.append('target_account', targetAccount)
+
+  return fetch(MOVE_ACCOUNT_URL, {
+    body: form,
+    method: 'POST',
+    headers: authHeaders(credentials)
+  })
+    .then((response) => response.json())
+}
+
+const addAlias = ({ credentials, alias }) => {
+  return promisedRequest({
+    url: ALIASES_URL,
+    method: 'PUT',
+    credentials,
+    payload: { alias }
+  })
+}
+
+const deleteAlias = ({ credentials, alias }) => {
+  return promisedRequest({
+    url: ALIASES_URL,
+    method: 'DELETE',
+    credentials,
+    payload: { alias }
+  })
+}
+
+const listAliases = ({ credentials }) => {
+  return promisedRequest({
+    url: ALIASES_URL,
+    method: 'GET',
+    credentials,
+    params: {
+      _cacheBooster: (new Date()).getTime()
+    }
+  })
+}
+
 const changePassword = ({ credentials, password, newPassword, newPasswordConfirmation }) => {
 const changePassword = ({ credentials, password, newPassword, newPasswordConfirmation }) => {
   const form = new FormData()
   const form = new FormData()
 
 
@@ -1346,6 +1391,10 @@ const apiService = {
   importFollows,
   importFollows,
   deleteAccount,
   deleteAccount,
   changeEmail,
   changeEmail,
+  moveAccount,
+  addAlias,
+  deleteAlias,
+  listAliases,
   changePassword,
   changePassword,
   settingsMFA,
   settingsMFA,
   mfaDisableOTP,
   mfaDisableOTP,