From 9cdb045c2ad928f8ca9da842e71c84fc5d3a173f Mon Sep 17 00:00:00 2001
From: Angelina Filippova <linakirsanova@gmail.com>
Date: Wed, 4 Sep 2019 22:53:38 +0300
Subject: [PATCH] Add ability to create new invite tokens

---
 src/api/users.js                              | 10 +++
 src/lang/en.js                                |  6 +-
 src/store/modules/users.js                    | 15 +++-
 .../users/components/NewAccountDialog.vue     | 81 ++++++++++++++-----
 4 files changed, 91 insertions(+), 21 deletions(-)

diff --git a/src/api/users.js b/src/api/users.js
index dd75045f..7e9001b2 100644
--- a/src/api/users.js
+++ b/src/api/users.js
@@ -57,6 +57,16 @@ export async function fetchUsers(filters, authHost, token, page = 1) {
   })
 }
 
+export async function generateInviteToken(max_use, expires_at, authHost, token) {
+  return await request({
+    baseURL: baseName(authHost),
+    url: `/api/pleroma/admin/users/invite_token`,
+    method: 'get',
+    headers: authHeaders(token),
+    invite: typeof expires_at === 'object' ? { max_use, expires_at } : { max_use }
+  })
+}
+
 export async function searchUsers(query, filters, authHost, token, page = 1) {
   return await request({
     baseURL: baseName(authHost),
diff --git a/src/lang/en.js b/src/lang/en.js
index e21edbce..497f27f9 100644
--- a/src/lang/en.js
+++ b/src/lang/en.js
@@ -224,7 +224,11 @@ export default {
     invalidEmailError: 'Please input valid e-mail',
     emptyPasswordError: 'Please input the password',
     emptyNicknameError: 'Please input the username',
-    invalidNicknameError: 'Username can include "a-z", "A-Z" and "0-9" characters'
+    invalidNicknameError: 'Username can include "a-z", "A-Z" and "0-9" characters',
+    maxUse: 'Max use',
+    expiresAt: 'Expires at',
+    tokenCreated: 'Invite token was created',
+    token: 'Token'
   },
   userProfile: {
     tags: 'Tags',
diff --git a/src/store/modules/users.js b/src/store/modules/users.js
index 0246a98d..7af8d60a 100644
--- a/src/store/modules/users.js
+++ b/src/store/modules/users.js
@@ -1,4 +1,4 @@
-import { addRight, createNewAccount, fetchUsers, deleteRight, deleteUser, searchUsers, tagUser, toggleUserActivation, untagUser } from '@/api/users'
+import { addRight, createNewAccount, fetchUsers, deleteRight, deleteUser, generateInviteToken, searchUsers, tagUser, toggleUserActivation, untagUser } from '@/api/users'
 
 const users = {
   state: {
@@ -12,7 +12,8 @@ const users = {
       external: false,
       active: false,
       deactivated: false
-    }
+    },
+    newToken: {}
   },
   mutations: {
     SET_USERS: (state, users) => {
@@ -37,6 +38,9 @@ const users = {
     SET_COUNT: (state, count) => {
       state.totalUsersCount = count
     },
+    SET_NEW_TOKEN: (state, token) => {
+      state.newToken = token
+    },
     SET_PAGE: (state, page) => {
       state.currentPage = page
     },
@@ -79,6 +83,13 @@ const users = {
       const response = await fetchUsers(filters, getters.authHost, getters.token, page)
       loadUsers(commit, page, response.data)
     },
+    async GenerateInviteToken({ commit, state, getters }, { maxUse, expiresAt }) {
+      const response = await generateInviteToken(maxUse, expiresAt, getters.authHost, getters.token)
+      commit('SET_NEW_TOKEN', { token: response.data, maxUse: response.config.invite.max_use, expiresAt: response.config.invite.expires_at })
+    },
+    RemoveNewToken({ commit }) {
+      commit('SET_NEW_TOKEN', {})
+    },
     async RemoveTag({ commit, getters }, { users, tag }) {
       const nicknames = users.map(user => user.nickname)
       await untagUser(nicknames, [tag], getters.authHost, getters.token)
diff --git a/src/views/users/components/NewAccountDialog.vue b/src/views/users/components/NewAccountDialog.vue
index 8cf2a725..f829f91c 100644
--- a/src/views/users/components/NewAccountDialog.vue
+++ b/src/views/users/components/NewAccountDialog.vue
@@ -5,25 +5,56 @@
     :title="$t('users.createAccount')"
     custom-class="create-user-dialog"
     @open="resetForm">
-    <el-form ref="form" :model="form" :rules="rules" :label-width="getLabelWidth" status-icon>
-      <el-form-item :label="$t('users.username')" prop="nickname" class="create-account-form-item">
-        <el-input v-model="form.nickname" name="nickname" autofocus/>
-      </el-form-item>
-      <el-form-item :label="$t('users.email')" prop="email" class="create-account-form-item">
-        <el-input v-model="form.email" name="email" type="email"/>
-      </el-form-item>
-      <el-form-item :label="$t('users.password')" prop="password" class="create-account-form-item">
-        <el-input v-model="form.password" type="password" name="password" autocomplete="off"/>
-      </el-form-item>
-    </el-form>
-    <span slot="footer">
-      <el-button @click="closeDialogWindow">{{ $t('users.cancel') }}</el-button>
-      <el-button type="primary" @click="submitForm('form')">{{ $t('users.create') }}</el-button>
-    </span>
+    <el-tabs type="card">
+      <el-tab-pane label="Create new user account">
+        <el-form ref="newUserForm" :model="newUserForm" :rules="rules" :label-width="getLabelWidth" status-icon>
+          <el-form-item :label="$t('users.username')" prop="nickname" class="create-account-form-item">
+            <el-input v-model="newUserForm.nickname" name="nickname" autofocus/>
+          </el-form-item>
+          <el-form-item :label="$t('users.email')" prop="email" class="create-account-form-item">
+            <el-input v-model="newUserForm.email" name="email" type="email"/>
+          </el-form-item>
+          <el-form-item :label="$t('users.password')" prop="password" class="create-account-form-item">
+            <el-input v-model="newUserForm.password" type="password" name="password" autocomplete="off"/>
+          </el-form-item>
+          <el-form-item>
+            <el-button @click="closeDialogWindow">{{ $t('users.cancel') }}</el-button>
+            <el-button type="primary" @click="submitForm('newUserForm')">{{ $t('users.create') }}</el-button>
+          </el-form-item>
+        </el-form>
+      </el-tab-pane>
+      <el-tab-pane label="Generate invite token">
+        <el-form ref="newTokenForm" :model="newTokenForm" :rules="rules" :label-width="getLabelWidth" status-icon>
+          <el-form-item :label="$t('users.maxUse')" class="create-account-form-item">
+            <el-input-number v-model="newTokenForm.maxUse" :min="0"/>
+          </el-form-item>
+          <el-form-item :label="$t('users.expiresAt')" class="create-account-form-item">
+            <el-date-picker
+              v-model="newTokenForm.expiresAt"
+              type="date"
+              placeholder="Pick a date"/>
+          </el-form-item>
+          <el-form-item>
+            <el-button @click="closeDialogWindow">{{ $t('users.cancel') }}</el-button>
+            <el-button type="primary" @click="createToken">{{ $t('users.create') }}</el-button>
+          </el-form-item>
+          <el-card v-if="'token' in newToken">
+            <div slot="header" class="clearfix">
+              <span>{{ $t('users.tokenCreated') }}</span>
+            </div>
+            <p>{{ this.$t('users.token') }}: {{ newToken.token }}</p>
+            <p>{{ this.$t('users.maxUse') }}: {{ newToken.maxUse }}</p>
+            <p>{{ this.$t('users.expiresAt') }}: {{ expiresAt }}</p>
+          </el-card>
+        </el-form>
+      </el-tab-pane>
+    </el-tabs>
   </el-dialog>
 </template>
 
 <script>
+import moment from 'moment'
+
 export default {
   name: 'NewAccountDialog',
   props: {
@@ -36,11 +67,15 @@ export default {
   },
   data() {
     return {
-      form: {
+      newUserForm: {
         nickname: '',
         email: '',
         password: ''
       },
+      newTokenForm: {
+        maxUse: 1,
+        expiresAt: ''
+      },
       rules: {
         nickname: [
           { validator: this.validateUsername, trigger: 'blur' }
@@ -55,6 +90,9 @@ export default {
     }
   },
   computed: {
+    expiresAt() {
+      return moment(this.newToken.expiresAt).format('MM-DD-YYYY')
+    },
     isDesktop() {
       return this.$store.state.app.device === 'desktop'
     },
@@ -68,21 +106,28 @@ export default {
     },
     getLabelWidth() {
       return this.isDesktop ? '120px' : '80px'
+    },
+    newToken() {
+      return this.$store.state.users.newToken
     }
   },
   methods: {
     closeDialogWindow() {
       this.$emit('closeWindow')
+      this.$store.dispatch('RemoveNewToken')
+    },
+    createToken() {
+      this.$store.dispatch('GenerateInviteToken', this.$data.newTokenForm)
     },
     resetForm() {
       this.$nextTick(() => {
-        this.$refs['form'].resetFields()
+        this.$refs['newUserForm'].resetFields()
       })
     },
     submitForm(formName) {
       this.$refs[formName].validate((valid) => {
         if (valid) {
-          this.$emit('createNewAccount', this.$data.form)
+          this.$emit('createNewAccount', this.$data.newUserForm)
           this.closeDialogWindow()
           this.$message({
             type: 'success',
-- 
GitLab