feat: import users from v1 - db + create users
This commit is contained in:
		@@ -9,45 +9,171 @@
 | 
				
			|||||||
      v-divider.my-4
 | 
					      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?
 | 
					      .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(
 | 
					      v-checkbox(
 | 
				
			||||||
        label='Content'
 | 
					        label='Content + Uploads'
 | 
				
			||||||
        value='content'
 | 
					        value='content'
 | 
				
			||||||
        color='deep-orange darken-2'
 | 
					        color='deep-orange darken-2'
 | 
				
			||||||
        v-model='importFilters'
 | 
					        v-model='importFilters'
 | 
				
			||||||
        hide-details
 | 
					        hide-details
 | 
				
			||||||
      )
 | 
					        )
 | 
				
			||||||
      v-checkbox(
 | 
					        template(v-slot:label)
 | 
				
			||||||
        label='Uploads'
 | 
					          strong.deep-orange--text.text--darken-2 Content + Uploads
 | 
				
			||||||
        value='uploads'
 | 
					      .pl-8(v-if='wantContent')
 | 
				
			||||||
        color='deep-orange darken-2'
 | 
					        v-radio-group(v-model='contentMode', hide-details)
 | 
				
			||||||
        v-model='importFilters'
 | 
					          v-radio(
 | 
				
			||||||
        hide-details
 | 
					            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'
 | 
				
			||||||
 | 
					                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='gitUserEmail'
 | 
				
			||||||
 | 
					                  outlined
 | 
				
			||||||
 | 
					                  hide-details
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					              v-col(cols='6')
 | 
				
			||||||
 | 
					                v-text-field(
 | 
				
			||||||
 | 
					                  type='password'
 | 
				
			||||||
 | 
					                  label='Password / PAT'
 | 
				
			||||||
 | 
					                  v-model='gitUserName'
 | 
				
			||||||
 | 
					                  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
 | 
				
			||||||
 | 
					              )
 | 
				
			||||||
 | 
					        v-radio-group(v-model='contentMode', hide-details)
 | 
				
			||||||
 | 
					          v-divider
 | 
				
			||||||
 | 
					          v-radio.mt-3(
 | 
				
			||||||
 | 
					            value='local'
 | 
				
			||||||
 | 
					            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(
 | 
					      v-checkbox(
 | 
				
			||||||
        label='Users'
 | 
					        label='Users'
 | 
				
			||||||
        value='users'
 | 
					        value='users'
 | 
				
			||||||
        color='deep-orange darken-2'
 | 
					        color='deep-orange darken-2'
 | 
				
			||||||
        v-model='importFilters'
 | 
					        v-model='importFilters'
 | 
				
			||||||
        hide-details
 | 
					        hide-details
 | 
				
			||||||
      )
 | 
					        )
 | 
				
			||||||
      v-divider.my-5
 | 
					        template(v-slot:label)
 | 
				
			||||||
      v-text-field.mt-3(
 | 
					          strong.deep-orange--text.text--darken-2 Users
 | 
				
			||||||
        outlined
 | 
					      .pl-8.mt-5(v-if='wantUsers')
 | 
				
			||||||
        label='MongoDB Connection String'
 | 
					        v-text-field(
 | 
				
			||||||
        hint='The connection string to connect to the Wiki.js 1.x MongoDB database.'
 | 
					          outlined
 | 
				
			||||||
        persistent-hint
 | 
					          label='MongoDB Connection String'
 | 
				
			||||||
        v-model='dbConnStr'
 | 
					          hint='The connection string to connect to the Wiki.js 1.x MongoDB database.'
 | 
				
			||||||
        v-if='needDB'
 | 
					          persistent-hint
 | 
				
			||||||
      )
 | 
					          v-model='dbConnStr'
 | 
				
			||||||
      v-text-field.mt-3(
 | 
					        )
 | 
				
			||||||
        outlined
 | 
					        v-radio-group(v-model='groupMode', hide-details, mandatory)
 | 
				
			||||||
        label='Content Repo Path'
 | 
					          v-radio(
 | 
				
			||||||
        hint='The full path to where the Wiki.js 1.x content is stored on disk.'
 | 
					            value='MULTI'
 | 
				
			||||||
        persistent-hint
 | 
					            color='primary'
 | 
				
			||||||
        v-model='contentPath'
 | 
					            )
 | 
				
			||||||
        v-if='needDisk'
 | 
					            template(v-slot:label)
 | 
				
			||||||
      )
 | 
					              div
 | 
				
			||||||
 | 
					                span Create groups for each unique user permissions configuration
 | 
				
			||||||
 | 
					                .caption: em Note that this can 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 #[strong.primary--text Recommended] | 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-card-chin
 | 
					    v-card-chin
 | 
				
			||||||
      v-btn.px-3(depressed, color='deep-orange darken-2', :disabled='!needDB && !needDisk', @click='startImport').ml-0
 | 
					      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
 | 
					        v-icon(left, color='white') mdi-database-import
 | 
				
			||||||
        span.white--text Start Import
 | 
					        span.white--text Start Import
 | 
				
			||||||
    v-dialog(
 | 
					    v-dialog(
 | 
				
			||||||
@@ -65,34 +191,170 @@
 | 
				
			|||||||
          )
 | 
					          )
 | 
				
			||||||
          .mt-5.body-1.white--text Importing from Wiki.js 1.x...
 | 
					          .mt-5.body-1.white--text Importing from Wiki.js 1.x...
 | 
				
			||||||
          .caption Please wait
 | 
					          .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
 | 
				
			||||||
 | 
					          template(v-if='wantContent')
 | 
				
			||||||
 | 
					            .body-2 #[strong {{successPages}}] pages
 | 
				
			||||||
 | 
					            .body-2 #[strong {{successAssets}}] assets
 | 
				
			||||||
 | 
					        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>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
 | 
					import _ from 'lodash'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { SemipolarSpinner } from 'epic-spinners'
 | 
					import { SemipolarSpinner } from 'epic-spinners'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import utilityImportv1UsersMutation from 'gql/admin/utilities/utilities-mutation-importv1-users.gql'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
  components: {
 | 
					  components: {
 | 
				
			||||||
    SemipolarSpinner
 | 
					    SemipolarSpinner
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  data() {
 | 
					  data() {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      importFilters: ['content', 'uploads', 'users'],
 | 
					      importFilters: ['content', 'users'],
 | 
				
			||||||
 | 
					      groupMode: 'SINGLE',
 | 
				
			||||||
 | 
					      contentMode: 'git',
 | 
				
			||||||
      dbConnStr: 'mongodb://',
 | 
					      dbConnStr: 'mongodb://',
 | 
				
			||||||
      contentPath: '/wiki-v1/repo',
 | 
					      contentPath: '/wiki-v1/repo',
 | 
				
			||||||
      isLoading: false
 | 
					      isLoading: false,
 | 
				
			||||||
 | 
					      isSuccess: false,
 | 
				
			||||||
 | 
					      gitAuthMode: 'ssh',
 | 
				
			||||||
 | 
					      gitAuthModes: [
 | 
				
			||||||
 | 
					        { text: 'SSH', value: 'ssh' },
 | 
				
			||||||
 | 
					        { text: 'Basic', value: 'basic' }
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      gitVerifySSL: true,
 | 
				
			||||||
 | 
					      gitRepoUrl: '',
 | 
				
			||||||
 | 
					      gitRepoBranch: 'master',
 | 
				
			||||||
 | 
					      gitPrivKey: '',
 | 
				
			||||||
 | 
					      gitUserEmail: '',
 | 
				
			||||||
 | 
					      gitUserName: '',
 | 
				
			||||||
 | 
					      gitRepoPath: './data/repo',
 | 
				
			||||||
 | 
					      progress: 0,
 | 
				
			||||||
 | 
					      successUsers: 0,
 | 
				
			||||||
 | 
					      successPages: 0,
 | 
				
			||||||
 | 
					      successGroups: 0,
 | 
				
			||||||
 | 
					      successAssets: 0,
 | 
				
			||||||
 | 
					      showFailedUsers: false,
 | 
				
			||||||
 | 
					      failedUsers: []
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  computed: {
 | 
					  computed: {
 | 
				
			||||||
    needDB() {
 | 
					    wantContent () {
 | 
				
			||||||
 | 
					      return this.importFilters.indexOf('content') >= 0
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    wantUsers () {
 | 
				
			||||||
      return this.importFilters.indexOf('users') >= 0
 | 
					      return this.importFilters.indexOf('users') >= 0
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    needDisk() {
 | 
					    needDisk () {
 | 
				
			||||||
      return this.importFilters.indexOf('content') >= 0 || this.importFilters.indexOf('uploads') >= 0
 | 
					      return this.contentMode === `local`
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    needGit () {
 | 
				
			||||||
 | 
					      return this.contentMode === `git`
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  methods: {
 | 
					  methods: {
 | 
				
			||||||
    async startImport () {
 | 
					    async startImport () {
 | 
				
			||||||
      this.isLoading = true
 | 
					      this.isLoading = true
 | 
				
			||||||
 | 
					      this.progress = 0
 | 
				
			||||||
 | 
					      this.failedUsers = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // -> 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) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      this.isLoading = false
 | 
				
			||||||
 | 
					      this.isSuccess = true
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -597,6 +597,7 @@ $editor-height-mobile: calc(100vh - 112px - 16px);
 | 
				
			|||||||
    position: relative;
 | 
					    position: relative;
 | 
				
			||||||
    height: $editor-height;
 | 
					    height: $editor-height;
 | 
				
			||||||
    overflow: hidden;
 | 
					    overflow: hidden;
 | 
				
			||||||
 | 
					    padding: 1rem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @at-root .theme--dark & {
 | 
					    @at-root .theme--dark & {
 | 
				
			||||||
      background-color: mc('grey', '900');
 | 
					      background-color: mc('grey', '900');
 | 
				
			||||||
@@ -622,8 +623,8 @@ $editor-height-mobile: calc(100vh - 112px - 16px);
 | 
				
			|||||||
    &-content {
 | 
					    &-content {
 | 
				
			||||||
      height: $editor-height;
 | 
					      height: $editor-height;
 | 
				
			||||||
      overflow-y: scroll;
 | 
					      overflow-y: scroll;
 | 
				
			||||||
      padding: 1rem 1rem 1rem 1rem;
 | 
					      padding: 0;
 | 
				
			||||||
      width: calc(100% + 1rem + 17px);
 | 
					      width: calc(100% + 17px);
 | 
				
			||||||
      // -ms-overflow-style: none;
 | 
					      // -ms-overflow-style: none;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // &::-webkit-scrollbar {
 | 
					      // &::-webkit-scrollbar {
 | 
				
			||||||
@@ -701,6 +702,8 @@ $editor-height-mobile: calc(100vh - 112px - 16px);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  .CodeMirror {
 | 
					  .CodeMirror {
 | 
				
			||||||
    height: auto;
 | 
					    height: auto;
 | 
				
			||||||
 | 
					    font-family: 'Roboto Mono', monospace;
 | 
				
			||||||
 | 
					    font-size: .9rem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .cm-header-1 {
 | 
					    .cm-header-1 {
 | 
				
			||||||
      font-size: 1.5rem;
 | 
					      font-size: 1.5rem;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					mutation($mongoDbConnString: String!, $groupMode: SystemImportUsersGroupMode!) {
 | 
				
			||||||
 | 
					  system {
 | 
				
			||||||
 | 
					    importUsersFromV1(mongoDbConnString: $mongoDbConnString, groupMode: $groupMode) {
 | 
				
			||||||
 | 
					      responseResult {
 | 
				
			||||||
 | 
					        succeeded
 | 
				
			||||||
 | 
					        errorCode
 | 
				
			||||||
 | 
					        slug
 | 
				
			||||||
 | 
					        message
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      usersCount
 | 
				
			||||||
 | 
					      groupsCount
 | 
				
			||||||
 | 
					      failed {
 | 
				
			||||||
 | 
					        provider
 | 
				
			||||||
 | 
					        email
 | 
				
			||||||
 | 
					        error
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -196,7 +196,7 @@
 | 
				
			|||||||
  // ---------------------------------
 | 
					  // ---------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  p {
 | 
					  p {
 | 
				
			||||||
    padding: 1rem 24px 0 24px;
 | 
					    padding: 1rem 0 0 0;
 | 
				
			||||||
    margin: 0;
 | 
					    margin: 0;
 | 
				
			||||||
    text-align: justify;
 | 
					    text-align: justify;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -319,7 +319,7 @@
 | 
				
			|||||||
  // ---------------------------------
 | 
					  // ---------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ol, ul {
 | 
					  ol, ul {
 | 
				
			||||||
    padding: 1rem 24px 0 24px;
 | 
					    padding: 1rem 0 0 0;
 | 
				
			||||||
    list-style-position: inside;
 | 
					    list-style-position: inside;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    li + li {
 | 
					    li + li {
 | 
				
			||||||
@@ -396,7 +396,7 @@
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    &.grid-list {
 | 
					    &.grid-list {
 | 
				
			||||||
      margin: 1rem 24px 0 24px;
 | 
					      margin: 1rem 0 0 0;
 | 
				
			||||||
      background-color: #FFF;
 | 
					      background-color: #FFF;
 | 
				
			||||||
      border: 1px solid mc('grey', '200');
 | 
					      border: 1px solid mc('grey', '200');
 | 
				
			||||||
      padding: 1px;
 | 
					      padding: 1px;
 | 
				
			||||||
@@ -476,7 +476,7 @@
 | 
				
			|||||||
    box-shadow: initial;
 | 
					    box-shadow: initial;
 | 
				
			||||||
    background-color: mc('grey', '900');
 | 
					    background-color: mc('grey', '900');
 | 
				
			||||||
    padding: 1rem 1rem 1rem 3rem;
 | 
					    padding: 1rem 1rem 1rem 3rem;
 | 
				
			||||||
    margin: 1rem 24px;
 | 
					    margin: 1rem 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @at-root .theme--dark & {
 | 
					    @at-root .theme--dark & {
 | 
				
			||||||
      background-color: darken(mc('grey', '900'), 5%);
 | 
					      background-color: darken(mc('grey', '900'), 5%);
 | 
				
			||||||
@@ -604,12 +604,12 @@
 | 
				
			|||||||
      border: 1px solid mc('grey', '400');
 | 
					      border: 1px solid mc('grey', '400');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    &.uml-diagram {
 | 
					    &.uml-diagram {
 | 
				
			||||||
      margin: 1rem;
 | 
					      margin: 1rem 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  figure.image {
 | 
					  figure.image {
 | 
				
			||||||
    margin: 1rem 24px 0 24px;
 | 
					    margin: 1rem 0 0 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    img {
 | 
					    img {
 | 
				
			||||||
      margin: 0 auto;
 | 
					      margin: 0 auto;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -84,6 +84,56 @@ module.exports = {
 | 
				
			|||||||
      } catch (err) {
 | 
					      } catch (err) {
 | 
				
			||||||
        return graphHelper.generateError(err)
 | 
					        return graphHelper.generateError(err)
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    async importUsersFromV1(obj, args, context) {
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        const MongoClient = require('mongodb').MongoClient
 | 
				
			||||||
 | 
					        if (args.mongoDbConnString && args.mongoDbConnString.length > 10) {
 | 
				
			||||||
 | 
					          const client = await MongoClient.connect(args.mongoDbConnString, {
 | 
				
			||||||
 | 
					            appname: `Wiki.js ${WIKI.version} Migration Tool`
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					          const dbUsers = client.db().collection('users')
 | 
				
			||||||
 | 
					          const userCursor = dbUsers.find({ email: { '$ne': 'guest' } })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          let failed = []
 | 
				
			||||||
 | 
					          let usersCount = 0
 | 
				
			||||||
 | 
					          let groupsCount = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          while (await userCursor.hasNext()) {
 | 
				
			||||||
 | 
					            const usr = await userCursor.next()
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					              await WIKI.models.users.createNewUser({
 | 
				
			||||||
 | 
					                providerKey: usr.provider,
 | 
				
			||||||
 | 
					                email: usr.email,
 | 
				
			||||||
 | 
					                name: usr.name,
 | 
				
			||||||
 | 
					                passwordRaw: usr.password,
 | 
				
			||||||
 | 
					                mustChangePassword: false,
 | 
				
			||||||
 | 
					                sendWelcomeEmail: false
 | 
				
			||||||
 | 
					              })
 | 
				
			||||||
 | 
					              usersCount++
 | 
				
			||||||
 | 
					            } catch (err) {
 | 
				
			||||||
 | 
					              failed.push({
 | 
				
			||||||
 | 
					                provider: usr.provider,
 | 
				
			||||||
 | 
					                email: usr.email,
 | 
				
			||||||
 | 
					                error: err.message
 | 
				
			||||||
 | 
					              })
 | 
				
			||||||
 | 
					              WIKI.logger.warn(`${usr.email}: ${err}`)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          client.close()
 | 
				
			||||||
 | 
					          return {
 | 
				
			||||||
 | 
					            responseResult: graphHelper.generateSuccess('Import completed.'),
 | 
				
			||||||
 | 
					            usersCount: usersCount,
 | 
				
			||||||
 | 
					            groupsCount: groupsCount,
 | 
				
			||||||
 | 
					            failed: failed
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          throw new Error('MongoDB Connection String is missing or invalid.')
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      } catch (err) {
 | 
				
			||||||
 | 
					        return graphHelper.generateError(err)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  SystemInfo: {
 | 
					  SystemInfo: {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,6 +35,11 @@ type SystemMutation {
 | 
				
			|||||||
  ): DefaultResponse @auth(requires: ["manage:system"])
 | 
					  ): DefaultResponse @auth(requires: ["manage:system"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  performUpgrade: DefaultResponse @auth(requires: ["manage:system"])
 | 
					  performUpgrade: DefaultResponse @auth(requires: ["manage:system"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  importUsersFromV1(
 | 
				
			||||||
 | 
					    mongoDbConnString: String!
 | 
				
			||||||
 | 
					    groupMode: SystemImportUsersGroupMode!
 | 
				
			||||||
 | 
					  ): SystemImportUsersResponse @auth(requires:  ["manage:system"])
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# -----------------------------------------------
 | 
					# -----------------------------------------------
 | 
				
			||||||
@@ -73,3 +78,22 @@ type SystemInfo {
 | 
				
			|||||||
  usersTotal: Int @auth(requires: ["manage:system", "manage:navigation", "manage:groups", "write:groups", "manage:users", "write:users"])
 | 
					  usersTotal: Int @auth(requires: ["manage:system", "manage:navigation", "manage:groups", "write:groups", "manage:users", "write:users"])
 | 
				
			||||||
  workingDirectory: String @auth(requires: ["manage:system"])
 | 
					  workingDirectory: String @auth(requires: ["manage:system"])
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum SystemImportUsersGroupMode {
 | 
				
			||||||
 | 
					  MULTI
 | 
				
			||||||
 | 
					  SINGLE
 | 
				
			||||||
 | 
					  NONE
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type SystemImportUsersResponse {
 | 
				
			||||||
 | 
					  responseResult: ResponseStatus
 | 
				
			||||||
 | 
					  usersCount: Int
 | 
				
			||||||
 | 
					  groupsCount: Int
 | 
				
			||||||
 | 
					  failed: [SystemImportUsersResponseFailed]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type SystemImportUsersResponseFailed {
 | 
				
			||||||
 | 
					  provider: String
 | 
				
			||||||
 | 
					  email: String
 | 
				
			||||||
 | 
					  error: String
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user