| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507 | 
							- <template lang='pug'>
 
-   v-card
 
-     v-toolbar(flat, color='primary', dark, dense)
 
-       .subtitle-1 {{ $t('admin:utilities.importv1Title') }}
 
-     v-card-text
 
-       .text-center
 
-         img.animated.fadeInUp.wait-p1s(src='/_assets/svg/icon-software.svg')
 
-         .body-2 Import from Wiki.js 1.x
 
-       v-divider.my-4
 
-       .body-2 Data from a Wiki.js 1.x installation can easily be imported using this tool. What do you want to import?
 
-       v-checkbox(
 
-         label='Content + Uploads'
 
-         value='content'
 
-         color='deep-orange darken-2'
 
-         v-model='importFilters'
 
-         hide-details
 
-         )
 
-         template(v-slot:label)
 
-           strong.deep-orange--text.text--darken-2 Content + Uploads
 
-       .pl-8(v-if='wantContent')
 
-         v-radio-group(v-model='contentMode', hide-details)
 
-           v-radio(
 
-             value='git'
 
-             color='primary'
 
-             )
 
-             template(v-slot:label)
 
-               div
 
-                 span Import from Git Connection
 
-                 .caption: em #[strong.primary--text Recommended] | The Git storage module will also be configured for you.
 
-         .pl-8.mt-5(v-if='needGit')
 
-           v-row
 
-             v-col(cols='8')
 
-               v-select(
 
-                 label='Authentication Mode'
 
-                 :items='gitAuthModes'
 
-                 v-model='gitAuthMode'
 
-                 outlined
 
-                 hide-details
 
-               )
 
-             v-col(cols='4')
 
-               v-switch(
 
-                 label='Verify SSL Certificate'
 
-                 v-model='gitVerifySSL'
 
-                 hide-details
 
-                 color='primary'
 
-               )
 
-             v-col(cols='8')
 
-               v-text-field(
 
-                 outlined
 
-                 label='Repository URL'
 
-                 :placeholder='(gitAuthMode === `ssh`) ? `e.g. git@github.com:orgname/repo.git` : `e.g. https://github.com/orgname/repo.git`'
 
-                 hide-details
 
-                 v-model='gitRepoUrl'
 
-               )
 
-             v-col(cols='4')
 
-               v-text-field(
 
-                 label='Branch'
 
-                 placeholder='e.g. master'
 
-                 v-model='gitRepoBranch'
 
-                 outlined
 
-                 hide-details
 
-               )
 
-             v-col(v-if='gitAuthMode === `ssh`', cols='12')
 
-               v-textarea(
 
-                 outlined
 
-                 label='Private Key Contents'
 
-                 placeholder='-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----'
 
-                 hide-details
 
-                 v-model='gitPrivKey'
 
-               )
 
-             template(v-else-if='gitAuthMode === `basic`')
 
-               v-col(cols='6')
 
-                 v-text-field(
 
-                   label='Username'
 
-                   v-model='gitUsername'
 
-                   outlined
 
-                   hide-details
 
-                 )
 
-               v-col(cols='6')
 
-                 v-text-field(
 
-                   type='password'
 
-                   label='Password / PAT'
 
-                   v-model='gitPassword'
 
-                   outlined
 
-                   hide-details
 
-                 )
 
-             v-col(cols='6')
 
-               v-text-field(
 
-                 label='Default Author Email'
 
-                 placeholder='e.g. name@company.com'
 
-                 v-model='gitUserEmail'
 
-                 outlined
 
-                 hide-details
 
-               )
 
-             v-col(cols='6')
 
-               v-text-field(
 
-                 label='Default Author Name'
 
-                 placeholder='e.g. John Smith'
 
-                 v-model='gitUserName'
 
-                 outlined
 
-                 hide-details
 
-               )
 
-             v-col(cols='12')
 
-               v-text-field(
 
-                 label='Local Repository Path'
 
-                 placeholder='e.g. ./data/repo'
 
-                 v-model='gitRepoPath'
 
-                 outlined
 
-                 hide-details
 
-               )
 
-               .caption.mt-2 This folder should be empty or not exist yet. #[strong.deep-orange--text.text--darken-2 DO NOT] point to your existing Wiki.js 1.x repository folder. In most cases, it should be left to the default value.
 
-           v-alert(color='deep-orange', outlined, icon='mdi-alert', prominent)
 
-             .body-2 - Note that if you already configured the git storage module, its configuration will be replaced with the above.
 
-             .body-2 - Although both v1 and v2 installations can use the same remote git repository, you shouldn't make edits to the same pages simultaneously.
 
-         v-radio-group(v-model='contentMode', hide-details)
 
-           v-divider
 
-           v-radio.mt-3(
 
-             value='disk'
 
-             color='primary'
 
-             )
 
-             template(v-slot:label)
 
-               div
 
-                 span Import from local folder
 
-                 .caption: em Choose this option only if you didn't have git configured in your Wiki.js 1.x installation.
 
-         .pl-8.mt-5(v-if='needDisk')
 
-           v-text-field(
 
-             outlined
 
-             label='Content Repo Path'
 
-             hint='The absolute path to where the Wiki.js 1.x content is stored on disk.'
 
-             persistent-hint
 
-             v-model='contentPath'
 
-           )
 
-       v-checkbox(
 
-         label='Users'
 
-         value='users'
 
-         color='deep-orange darken-2'
 
-         v-model='importFilters'
 
-         hide-details
 
-         )
 
-         template(v-slot:label)
 
-           strong.deep-orange--text.text--darken-2 Users
 
-       .pl-8.mt-5(v-if='wantUsers')
 
-         v-text-field(
 
-           outlined
 
-           label='MongoDB Connection String'
 
-           hint='The connection string to connect to the Wiki.js 1.x MongoDB database.'
 
-           persistent-hint
 
-           v-model='dbConnStr'
 
-         )
 
-         v-radio-group(v-model='groupMode', hide-details, mandatory)
 
-           v-radio(
 
-             value='MULTI'
 
-             color='primary'
 
-             )
 
-             template(v-slot:label)
 
-               div
 
-                 span Create groups for each unique user permissions configuration
 
-                 .caption: em #[strong.primary--text Recommended] | Users having identical permission sets will be assigned to the same group. Note that this can potentially result in a large amount of groups being created.
 
-           v-divider
 
-           v-radio.mt-3(
 
-             value='SINGLE'
 
-             color='primary'
 
-             )
 
-             template(v-slot:label)
 
-               div
 
-                 span Create a single group with all imported users
 
-                 .caption: em The new group will have read permissions enabled by default.
 
-           v-divider
 
-           v-radio.mt-3(
 
-             value='NONE'
 
-             color='primary'
 
-             )
 
-             template(v-slot:label)
 
-               div
 
-                 span Don't create any group
 
-                 .caption: em Users will not be able to access your wiki until they are assigned to a group.
 
-         v-alert.mt-5(color='deep-orange', outlined, icon='mdi-alert', prominent)
 
-           .body-2 Note that any user that already exists in this installation will not be imported. A list of skipped users will be displayed upon completion.
 
-           .caption.grey--text You must first delete from this installation any user you want to migrate over from the old installation.
 
-     v-card-chin
 
-       v-btn.px-3(depressed, color='deep-orange darken-2', :disabled='!wantUsers && !wantContent', @click='startImport').ml-0
 
-         v-icon(left, color='white') mdi-database-import
 
-         span.white--text Start Import
 
-     v-dialog(
 
-       v-model='isLoading'
 
-       persistent
 
-       max-width='350'
 
-       )
 
-       v-card(color='deep-orange darken-2', dark)
 
-         v-card-text.pa-10.text-center
 
-           semipolar-spinner.animated.fadeIn(
 
-             :animation-duration='1500'
 
-             :size='65'
 
-             color='#FFF'
 
-             style='margin: 0 auto;'
 
-           )
 
-           .mt-5.body-1.white--text Importing from Wiki.js 1.x...
 
-           .caption Please wait
 
-           v-progress-linear.mt-5(
 
-             color='white'
 
-             :value='progress'
 
-             stream
 
-             rounded
 
-             :buffer-value='0'
 
-           )
 
-     v-dialog(
 
-       v-model='isSuccess'
 
-       persistent
 
-       max-width='350'
 
-       )
 
-       v-card(color='green darken-2', dark)
 
-         v-card-text.pa-10.text-center
 
-           v-icon(size='60') mdi-check-circle-outline
 
-           .my-5.body-1.white--text Import completed
 
-           template(v-if='wantUsers')
 
-             .body-2
 
-               span #[strong {{successUsers}}] users imported
 
-               v-btn.text-none.ml-3(
 
-                 v-if='failedUsers.length > 0'
 
-                 text
 
-                 color='white'
 
-                 dark
 
-                 @click='showFailedUsers = true'
 
-                 )
 
-                 v-icon(left) mdi-alert
 
-                 span {{failedUsers.length}} failed
 
-             .body-2 #[strong {{successGroups}}] groups created
 
-         v-card-actions.green.darken-1
 
-           v-spacer
 
-           v-btn.px-5(
 
-             color='white'
 
-             outlined
 
-             @click='isSuccess = false'
 
-           ) Close
 
-           v-spacer
 
-     v-dialog(
 
-       v-model='showFailedUsers'
 
-       persistent
 
-       max-width='800'
 
-       )
 
-       v-card(color='red darken-2', dark)
 
-         v-toolbar(color='red darken-2', dense)
 
-           v-icon mdi-alert
 
-           .body-2.pl-3 Failed User Imports
 
-           v-spacer
 
-           v-btn.px-5(
 
-             color='white'
 
-             text
 
-             @click='showFailedUsers = false'
 
-             ) Close
 
-         v-simple-table(dense, fixed-header, height='300px')
 
-           template(v-slot:default)
 
-             thead
 
-               tr
 
-                 th Provider
 
-                 th Email
 
-                 th Error
 
-             tbody
 
-               tr(v-for='(fusr, idx) in failedUsers', :key='`fusr-` + idx')
 
-                 td {{fusr.provider}}
 
-                 td {{fusr.email}}
 
-                 td {{fusr.error}}
 
- </template>
 
- <script>
 
- import _ from 'lodash'
 
- import { SemipolarSpinner } from 'epic-spinners'
 
- import utilityImportv1UsersMutation from 'gql/admin/utilities/utilities-mutation-importv1-users.gql'
 
- import storageTargetsQuery from 'gql/admin/storage/storage-query-targets.gql'
 
- import storageStatusQuery from 'gql/admin/storage/storage-query-status.gql'
 
- import targetExecuteActionMutation from 'gql/admin/storage/storage-mutation-executeaction.gql'
 
- import targetsSaveMutation from 'gql/admin/storage/storage-mutation-save-targets.gql'
 
- export default {
 
-   components: {
 
-     SemipolarSpinner
 
-   },
 
-   data() {
 
-     return {
 
-       importFilters: ['content', 'users'],
 
-       groupMode: 'MULTI',
 
-       contentMode: 'git',
 
-       dbConnStr: 'mongodb://',
 
-       contentPath: '/wiki-v1/repo',
 
-       isLoading: false,
 
-       isSuccess: false,
 
-       gitAuthMode: 'ssh',
 
-       gitAuthModes: [
 
-         { text: 'SSH', value: 'ssh' },
 
-         { text: 'Basic', value: 'basic' }
 
-       ],
 
-       gitVerifySSL: true,
 
-       gitRepoUrl: '',
 
-       gitRepoBranch: 'master',
 
-       gitPrivKey: '',
 
-       gitUsername: '',
 
-       gitPassword: '',
 
-       gitUserEmail: '',
 
-       gitUserName: '',
 
-       gitRepoPath: './data/repo',
 
-       progress: 0,
 
-       successGroups: 0,
 
-       successUsers: 0,
 
-       successPages: 0,
 
-       showFailedUsers: false,
 
-       failedUsers: []
 
-     }
 
-   },
 
-   computed: {
 
-     wantContent () {
 
-       return this.importFilters.indexOf('content') >= 0
 
-     },
 
-     wantUsers () {
 
-       return this.importFilters.indexOf('users') >= 0
 
-     },
 
-     needDisk () {
 
-       return this.contentMode === `disk`
 
-     },
 
-     needGit () {
 
-       return this.contentMode === `git`
 
-     }
 
-   },
 
-   methods: {
 
-     async startImport () {
 
-       this.isLoading = true
 
-       this.progress = 0
 
-       this.failedUsers = []
 
-       _.delay(async () => {
 
-         // -> Import Users
 
-         if (this.wantUsers) {
 
-           try {
 
-             const resp = await this.$apollo.mutate({
 
-               mutation: utilityImportv1UsersMutation,
 
-               variables: {
 
-                 mongoDbConnString: this.dbConnStr,
 
-                 groupMode: this.groupMode
 
-               }
 
-             })
 
-             const respObj = _.get(resp, 'data.system.importUsersFromV1', {})
 
-             if (!_.get(respObj, 'responseResult.succeeded', false)) {
 
-               throw new Error(_.get(respObj, 'responseResult.message', 'An unexpected error occured'))
 
-             }
 
-             this.successUsers = _.get(respObj, 'usersCount', 0)
 
-             this.successGroups = _.get(respObj, 'groupsCount', 0)
 
-             this.failedUsers = _.get(respObj, 'failed', [])
 
-             this.progress += 50
 
-           } catch (err) {
 
-             this.$store.commit('pushGraphError', err)
 
-             this.isLoading = false
 
-             return
 
-           }
 
-         }
 
-         // -> Import Content
 
-         if (this.wantContent) {
 
-           try {
 
-             const resp = await this.$apollo.query({
 
-               query: storageTargetsQuery,
 
-               fetchPolicy: 'network-only'
 
-             })
 
-             if (_.has(resp, 'data.storage.targets')) {
 
-               this.progress += 10
 
-               let targets = resp.data.storage.targets.map(str => {
 
-                 let nStr = {
 
-                   ...str,
 
-                   config: _.sortBy(str.config.map(cfg => ({
 
-                     ...cfg,
 
-                     value: JSON.parse(cfg.value)
 
-                   })), [t => t.value.order])
 
-                 }
 
-                 // -> Setup Git Module
 
-                 if (this.contentMode === 'git' && nStr.key === 'git') {
 
-                   nStr.isEnabled = true
 
-                   nStr.mode = 'sync'
 
-                   nStr.syncInterval = 'PT5M'
 
-                   nStr.config = [
 
-                     { key: 'authType', value: { value: this.gitAuthMode } },
 
-                     { key: 'repoUrl', value: { value: this.gitRepoUrl } },
 
-                     { key: 'branch', value: { value: this.gitRepoBranch } },
 
-                     { key: 'sshPrivateKeyMode', value: { value: 'contents' } },
 
-                     { key: 'sshPrivateKeyPath', value: { value: '' } },
 
-                     { key: 'sshPrivateKeyContent', value: { value: this.gitPrivKey } },
 
-                     { key: 'verifySSL', value: { value: this.gitVerifySSL } },
 
-                     { key: 'basicUsername', value: { value: this.gitUsername } },
 
-                     { key: 'basicPassword', value: { value: this.gitPassword } },
 
-                     { key: 'defaultEmail', value: { value: this.gitUserEmail } },
 
-                     { key: 'defaultName', value: { value: this.gitUserName } },
 
-                     { key: 'localRepoPath', value: { value: this.gitRepoPath } },
 
-                     { key: 'gitBinaryPath', value: { value: '' } }
 
-                   ]
 
-                 }
 
-                 // -> Setup Disk Module
 
-                 if (this.contentMode === 'disk' && nStr.key === 'disk') {
 
-                   nStr.isEnabled = true
 
-                   nStr.mode = 'push'
 
-                   nStr.syncInterval = 'P0D'
 
-                   nStr.config = [
 
-                     { key: 'path', value: { value: this.contentPath } },
 
-                     { key: 'createDailyBackups', value: { value: false } }
 
-                   ]
 
-                 }
 
-                 return nStr
 
-               })
 
-               // -> Save storage modules configuration
 
-               const respSv = await this.$apollo.mutate({
 
-                 mutation: targetsSaveMutation,
 
-                 variables: {
 
-                   targets: targets.map(tgt => _.pick(tgt, [
 
-                     'isEnabled',
 
-                     'key',
 
-                     'config',
 
-                     'mode',
 
-                     'syncInterval'
 
-                   ])).map(str => ({...str, config: str.config.map(cfg => ({...cfg, value: JSON.stringify({ v: cfg.value.value })}))}))
 
-                 }
 
-               })
 
-               const respObj = _.get(respSv, 'data.storage.updateTargets', {})
 
-               if (!_.get(respObj, 'responseResult.succeeded', false)) {
 
-                 throw new Error(_.get(respObj, 'responseResult.message', 'An unexpected error occured'))
 
-               }
 
-               this.progress += 10
 
-               // -> Wait for success sync
 
-               let statusAttempts = 0
 
-               while (statusAttempts < 10) {
 
-                 statusAttempts++
 
-                 const respStatus = await this.$apollo.query({
 
-                   query: storageStatusQuery,
 
-                   fetchPolicy: 'network-only'
 
-                 })
 
-                 if (_.has(respStatus, 'data.storage.status[0]')) {
 
-                   const st = _.find(respStatus.data.storage.status, ['key', this.contentMode])
 
-                   if (!st) {
 
-                     throw new Error('Storage target could not be configured.')
 
-                   }
 
-                   switch (st.status) {
 
-                     case 'pending':
 
-                       if (statusAttempts >= 10) {
 
-                         throw new Error('Storage target is stuck in pending state. Try again.')
 
-                       } else {
 
-                         continue
 
-                       }
 
-                     case 'operational':
 
-                       statusAttempts = 10
 
-                       break
 
-                     case 'error':
 
-                       throw new Error(st.message)
 
-                   }
 
-                 } else {
 
-                   throw new Error('Failed to fetch storage sync status.')
 
-                 }
 
-               }
 
-               this.progress += 15
 
-               // -> Perform import all
 
-               const respImport = await this.$apollo.mutate({
 
-                 mutation: targetExecuteActionMutation,
 
-                 variables: {
 
-                   targetKey: this.contentMode,
 
-                   handler: 'importAll'
 
-                 }
 
-               })
 
-               const respImportObj = _.get(respImport, 'data.storage.executeAction', {})
 
-               if (!_.get(respImportObj, 'responseResult.succeeded', false)) {
 
-                 throw new Error(_.get(respImportObj, 'responseResult.message', 'An unexpected error occured'))
 
-               }
 
-               this.progress += 15
 
-             } else {
 
-               throw new Error('Failed to fetch storage targets.')
 
-             }
 
-           } catch (err) {
 
-             this.$store.commit('pushGraphError', err)
 
-             this.isLoading = false
 
-             return
 
-           }
 
-         }
 
-         this.isLoading = false
 
-         this.isSuccess = true
 
-       }, 1500)
 
-     }
 
-   }
 
- }
 
- </script>
 
- <style lang='scss'>
 
- </style>
 
 
  |