Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wiki-js
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
1
Issues
1
List
Board
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
wiki-js
Commits
82ba7d0a
Commit
82ba7d0a
authored
Sep 28, 2019
by
Nick
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: import users from v1 - db + create users
parent
41716e52
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
388 additions
and
30 deletions
+388
-30
admin-utilities-importv1.vue
client/components/admin/admin-utilities-importv1.vue
+284
-22
editor-markdown.vue
client/components/editor/editor-markdown.vue
+5
-2
utilities-mutation-importv1-users.gql
...aph/admin/utilities/utilities-mutation-importv1-users.gql
+19
-0
app.scss
client/themes/default/scss/app.scss
+6
-6
system.js
server/graph/resolvers/system.js
+50
-0
system.graphql
server/graph/schemas/system.graphql
+24
-0
No files found.
client/components/admin/admin-utilities-importv1.vue
View file @
82ba7d0a
...
...
@@ -9,19 +9,124 @@
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'
label='Content
+ Uploads
'
value='content'
color='deep-orange darken-2'
v-model='importFilters'
hide-details
)
v-checkbox(
label='Uploads'
value='uploads'
color='deep-orange darken-2'
v-model='importFilters'
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'
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(
label='Users'
value='users'
...
...
@@ -29,25 +134,46 @@
v-model='importFilters'
hide-details
)
v-divider.my-5
v-text-field.mt-3(
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-if='needDB'
)
v-text-field.mt-3(
outlined
label='Content Repo Path'
hint='The full path to where the Wiki.js 1.x content is stored on disk.'
persistent-hint
v-model='contentPath'
v-if='needDisk'
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 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-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
span.white--text Start Import
v-dialog(
...
...
@@ -65,34 +191,170 @@
)
.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
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
>
<
script
>
import
_
from
'lodash'
import
{
SemipolarSpinner
}
from
'epic-spinners'
import
utilityImportv1UsersMutation
from
'gql/admin/utilities/utilities-mutation-importv1-users.gql'
export
default
{
components
:
{
SemipolarSpinner
},
data
()
{
return
{
importFilters
:
[
'content'
,
'uploads'
,
'users'
],
importFilters
:
[
'content'
,
'users'
],
groupMode
:
'SINGLE'
,
contentMode
:
'git'
,
dbConnStr
:
'mongodb://'
,
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
:
{
needDB
()
{
wantContent
()
{
return
this
.
importFilters
.
indexOf
(
'content'
)
>=
0
},
wantUsers
()
{
return
this
.
importFilters
.
indexOf
(
'users'
)
>=
0
},
needDisk
()
{
return
this
.
importFilters
.
indexOf
(
'content'
)
>=
0
||
this
.
importFilters
.
indexOf
(
'uploads'
)
>=
0
needDisk
()
{
return
this
.
contentMode
===
`local`
},
needGit
()
{
return
this
.
contentMode
===
`git`
}
},
methods
:
{
async
startImport
()
{
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
}
}
}
...
...
client/components/editor/editor-markdown.vue
View file @
82ba7d0a
...
...
@@ -597,6 +597,7 @@ $editor-height-mobile: calc(100vh - 112px - 16px);
position: relative;
height: $editor-height;
overflow: hidden;
padding: 1rem;
@at-root .theme--dark & {
background-color: mc('grey', '900');
...
...
@@ -622,8 +623,8 @@ $editor-height-mobile: calc(100vh - 112px - 16px);
&-content {
height: $editor-height;
overflow-y: scroll;
padding:
1rem 1rem 1rem 1rem
;
width: calc(100% + 1
rem + 1
7px);
padding:
0
;
width: calc(100% + 17px);
// -ms-overflow-style: none;
// &::-webkit-scrollbar {
...
...
@@ -701,6 +702,8 @@ $editor-height-mobile: calc(100vh - 112px - 16px);
.CodeMirror {
height: auto;
font-family: 'Roboto Mono', monospace;
font-size: .9rem;
.cm-header-1 {
font-size: 1.5rem;
...
...
client/graph/admin/utilities/utilities-mutation-importv1-users.gql
0 → 100644
View file @
82ba7d0a
mutation
(
$mongoDbConnString
:
String
!,
$groupMode
:
SystemImportUsersGroupMode
!)
{
system
{
importUsersFromV1
(
mongoDbConnString
:
$mongoDbConnString
,
groupMode
:
$groupMode
)
{
responseResult
{
succeeded
errorCode
slug
message
}
usersCount
groupsCount
failed
{
provider
email
error
}
}
}
}
client/themes/default/scss/app.scss
View file @
82ba7d0a
...
...
@@ -196,7 +196,7 @@
// ---------------------------------
p
{
padding
:
1rem
24px
0
24px
;
padding
:
1rem
0
0
0
;
margin
:
0
;
text-align
:
justify
;
...
...
@@ -319,7 +319,7 @@
// ---------------------------------
ol
,
ul
{
padding
:
1rem
24px
0
24px
;
padding
:
1rem
0
0
0
;
list-style-position
:
inside
;
li
+
li
{
...
...
@@ -396,7 +396,7 @@
}
&
.grid-list
{
margin
:
1rem
24px
0
24px
;
margin
:
1rem
0
0
0
;
background-color
:
#FFF
;
border
:
1px
solid
mc
(
'grey'
,
'200'
);
padding
:
1px
;
...
...
@@ -476,7 +476,7 @@
box-shadow
:
initial
;
background-color
:
mc
(
'grey'
,
'900'
);
padding
:
1rem
1rem
1rem
3rem
;
margin
:
1rem
24px
;
margin
:
1rem
0
;
@at-root
.theme--dark
&
{
background-color
:
darken
(
mc
(
'grey'
,
'900'
)
,
5%
);
...
...
@@ -604,12 +604,12 @@
border
:
1px
solid
mc
(
'grey'
,
'400'
);
}
&
.uml-diagram
{
margin
:
1rem
;
margin
:
1rem
0
;
}
}
figure
.image
{
margin
:
1rem
24px
0
24px
;
margin
:
1rem
0
0
0
;
img
{
margin
:
0
auto
;
...
...
server/graph/resolvers/system.js
View file @
82ba7d0a
...
...
@@ -84,6 +84,56 @@ module.exports = {
}
catch
(
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
:
{
...
...
server/graph/schemas/system.graphql
View file @
82ba7d0a
...
...
@@ -35,6 +35,11 @@ type SystemMutation {
):
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
"
])
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
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment