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
5eaba2cb
Unverified
Commit
5eaba2cb
authored
Jul 17, 2023
by
NGPixel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: remove localeCode ref + new nav items + fetch current
parent
269040ed
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
30 changed files
with
469 additions
and
351 deletions
+469
-351
auth.mjs
server/core/auth.mjs
+1
-1
3.0.0.mjs
server/db/migrations/3.0.0.mjs
+65
-12
asset.mjs
server/graph/resolvers/asset.mjs
+2
-2
comment.mjs
server/graph/resolvers/comment.mjs
+3
-3
navigation.mjs
server/graph/resolvers/navigation.mjs
+9
-26
page.mjs
server/graph/resolvers/page.mjs
+29
-31
tree.mjs
server/graph/resolvers/tree.mjs
+1
-1
navigation.graphql
server/graph/schemas/navigation.graphql
+11
-44
page.graphql
server/graph/schemas/page.graphql
+1
-0
common.mjs
server/helpers/common.mjs
+4
-4
en.json
server/locales/en.json
+5
-0
assets.mjs
server/models/assets.mjs
+1
-1
comments.mjs
server/models/comments.mjs
+3
-3
navigation.mjs
server/models/navigation.mjs
+18
-5
pageHistory.mjs
server/models/pageHistory.mjs
+3
-3
pageLinks.mjs
server/models/pageLinks.mjs
+2
-2
pages.mjs
server/models/pages.mjs
+30
-40
sites.mjs
server/models/sites.mjs
+14
-0
tree.mjs
server/models/tree.mjs
+6
-14
users.mjs
server/models/users.mjs
+1
-9
comment.js
server/modules/comments/default/comment.js
+1
-1
renderer.mjs
server/modules/rendering/core/renderer.mjs
+10
-10
rebuild-search-index.mjs
server/tasks/workers/rebuild-search-index.mjs
+1
-1
IconPickerDialog.vue
ux/src/components/IconPickerDialog.vue
+7
-7
NavEditMenu.vue
ux/src/components/NavEditMenu.vue
+6
-4
NavEditOverlay.vue
ux/src/components/NavEditOverlay.vue
+150
-111
NavSidebar.vue
ux/src/components/NavSidebar.vue
+27
-14
MainLayout.vue
ux/src/layouts/MainLayout.vue
+14
-1
page.js
ux/src/stores/page.js
+2
-0
site.js
ux/src/stores/site.js
+42
-1
No files found.
server/core/auth.mjs
View file @
5eaba2cb
...
...
@@ -188,7 +188,7 @@ export default {
name
:
'API'
,
pictureUrl
:
null
,
timezone
:
'America/New_York'
,
locale
Code
:
'en'
,
locale
:
'en'
,
permissions
:
_
.
get
(
WIKI
.
auth
.
groups
,
`
${
user
.
grp
}
.permissions`
,
[]),
groups
:
[
user
.
grp
],
getPermissions
()
{
...
...
server/db/migrations/3.0.0.mjs
View file @
5eaba2cb
...
...
@@ -178,8 +178,9 @@ export async function up (knex) {
})
// NAVIGATION ----------------------------
.
createTable
(
'navigation'
,
table
=>
{
table
.
string
(
'key'
).
notNullable
().
primary
()
table
.
jsonb
(
'config'
)
table
.
uuid
(
'id'
).
notNullable
().
primary
().
defaultTo
(
knex
.
raw
(
'gen_random_uuid()'
))
table
.
string
(
'name'
).
notNullable
()
table
.
jsonb
(
'items'
).
notNullable
().
defaultTo
(
'[]'
)
})
// PAGE HISTORY ------------------------
.
createTable
(
'pageHistory'
,
table
=>
{
...
...
@@ -187,6 +188,7 @@ export async function up (knex) {
table
.
uuid
(
'pageId'
).
notNullable
().
index
()
table
.
string
(
'action'
).
defaultTo
(
'updated'
)
table
.
jsonb
(
'affectedFields'
).
notNullable
().
defaultTo
(
'[]'
)
table
.
string
(
'locale'
,
10
).
notNullable
().
defaultTo
(
'en'
)
table
.
string
(
'path'
).
notNullable
()
table
.
string
(
'hash'
).
notNullable
()
table
.
string
(
'alias'
)
...
...
@@ -211,11 +213,12 @@ export async function up (knex) {
.
createTable
(
'pageLinks'
,
table
=>
{
table
.
increments
(
'id'
).
primary
()
table
.
string
(
'path'
).
notNullable
()
table
.
string
(
'locale
Code
'
,
10
).
notNullable
()
table
.
string
(
'locale'
,
10
).
notNullable
()
})
// PAGES -------------------------------
.
createTable
(
'pages'
,
table
=>
{
table
.
uuid
(
'id'
).
notNullable
().
primary
().
defaultTo
(
knex
.
raw
(
'gen_random_uuid()'
))
table
.
string
(
'locale'
,
10
).
notNullable
()
table
.
string
(
'path'
).
notNullable
()
table
.
string
(
'hash'
).
notNullable
()
table
.
string
(
'alias'
)
...
...
@@ -293,7 +296,7 @@ export async function up (knex) {
table
.
string
(
'fileName'
).
notNullable
().
index
()
table
.
string
(
'hash'
).
notNullable
().
index
()
table
.
enu
(
'type'
,
[
'folder'
,
'page'
,
'asset'
]).
notNullable
().
index
()
table
.
string
(
'locale
Code
'
,
10
).
notNullable
().
defaultTo
(
'en'
).
index
()
table
.
string
(
'locale'
,
10
).
notNullable
().
defaultTo
(
'en'
).
index
()
table
.
string
(
'title'
).
notNullable
()
table
.
jsonb
(
'meta'
).
notNullable
().
defaultTo
(
'{}'
)
table
.
timestamp
(
'createdAt'
).
notNullable
().
defaultTo
(
knex
.
fn
.
now
())
...
...
@@ -369,16 +372,14 @@ export async function up (knex) {
table
.
uuid
(
'siteId'
).
notNullable
().
references
(
'id'
).
inTable
(
'sites'
).
index
()
})
.
table
(
'pageHistory'
,
table
=>
{
table
.
string
(
'localeCode'
,
10
).
references
(
'code'
).
inTable
(
'locales'
)
table
.
uuid
(
'authorId'
).
notNullable
().
references
(
'id'
).
inTable
(
'users'
)
table
.
uuid
(
'siteId'
).
notNullable
().
references
(
'id'
).
inTable
(
'sites'
).
index
()
})
.
table
(
'pageLinks'
,
table
=>
{
table
.
uuid
(
'pageId'
).
notNullable
().
references
(
'id'
).
inTable
(
'pages'
).
onDelete
(
'CASCADE'
)
table
.
index
([
'path'
,
'locale
Code
'
])
table
.
index
([
'path'
,
'locale'
])
})
.
table
(
'pages'
,
table
=>
{
table
.
string
(
'localeCode'
,
10
).
references
(
'code'
).
inTable
(
'locales'
).
index
()
table
.
uuid
(
'authorId'
).
notNullable
().
references
(
'id'
).
inTable
(
'users'
).
index
()
table
.
uuid
(
'creatorId'
).
notNullable
().
references
(
'id'
).
inTable
(
'users'
).
index
()
table
.
uuid
(
'ownerId'
).
notNullable
().
references
(
'id'
).
inTable
(
'users'
).
index
()
...
...
@@ -392,6 +393,7 @@ export async function up (knex) {
table
.
unique
([
'siteId'
,
'tag'
])
})
.
table
(
'tree'
,
table
=>
{
table
.
uuid
(
'navigationId'
).
references
(
'id'
).
inTable
(
'navigation'
).
index
()
table
.
uuid
(
'siteId'
).
notNullable
().
references
(
'id'
).
inTable
(
'sites'
)
})
.
table
(
'userKeys'
,
table
=>
{
...
...
@@ -413,6 +415,7 @@ export async function up (knex) {
const
groupAdminId
=
uuid
()
const
groupGuestId
=
'10000000-0000-4000-8000-000000000001'
const
navDefaultId
=
uuid
()
const
siteId
=
uuid
()
const
authModuleId
=
uuid
()
const
userAdminId
=
uuid
()
...
...
@@ -619,6 +622,10 @@ export async function up (knex) {
config
:
{}
}
},
nav
:
{
mode
:
'mixed'
,
defaultId
:
navDefaultId
,
},
theme
:
{
dark
:
false
,
codeBlocksTheme
:
'github-dark'
,
...
...
@@ -747,6 +754,52 @@ export async function up (knex) {
}
])
// -> NAVIGATION
await
knex
(
'navigation'
).
insert
({
id
:
navDefaultId
,
name
:
'Default'
,
items
:
JSON
.
stringify
([
{
id
:
uuid
(),
type
:
'header'
,
label
:
'Sample Header'
},
{
id
:
uuid
(),
type
:
'link'
,
icon
:
'mdi-file-document-outline'
,
label
:
'Sample Link 1'
,
target
:
'/'
,
openInNewWindow
:
false
,
children
:
[]
},
{
id
:
uuid
(),
type
:
'link'
,
icon
:
'mdi-book-open-variant'
,
label
:
'Sample Link 2'
,
target
:
'/'
,
openInNewWindow
:
false
,
children
:
[]
},
{
id
:
uuid
(),
type
:
'separator'
,
},
{
id
:
uuid
(),
type
:
'link'
,
icon
:
'mdi-airballoon'
,
label
:
'Sample Link 3'
,
target
:
'/'
,
openInNewWindow
:
false
,
children
:
[]
}
]),
siteId
:
siteId
})
// -> STORAGE MODULE
await
knex
(
'storage'
).
insert
({
...
...
@@ -782,11 +835,11 @@ export async function up (knex) {
cron
:
'5 0 * * *'
,
type
:
'system'
},
{
task
:
'refreshAutocomplete'
,
cron
:
'0 */6 * * *'
,
type
:
'system'
},
//
{
//
task: 'refreshAutocomplete',
//
cron: '0 */6 * * *',
//
type: 'system'
//
},
{
task
:
'updateLocales'
,
cron
:
'0 0 * * *'
,
...
...
server/graph/resolvers/asset.mjs
View file @
5eaba2cb
...
...
@@ -170,7 +170,7 @@ export default {
folder
=
{
folderPath
:
''
,
fileName
:
''
,
locale
Code
:
args
.
locale
,
locale
:
args
.
locale
,
siteId
:
args
.
siteId
}
}
...
...
@@ -263,7 +263,7 @@ export default {
parentPath
:
folder
.
folderPath
?
`
${
folder
.
folderPath
}
.
${
folder
.
fileName
}
`
:
folder
.
fileName
,
fileName
:
formattedFilename
,
title
:
formattedFilename
,
locale
:
folder
.
locale
Code
,
locale
:
folder
.
locale
,
siteId
:
folder
.
siteId
,
meta
:
{
authorId
:
asset
.
authorId
,
...
...
server/graph/resolvers/comment.mjs
View file @
5eaba2cb
...
...
@@ -32,7 +32,7 @@ export default {
* Fetch list of comments for a page
*/
async
comments
(
obj
,
args
,
context
)
{
const
page
=
await
WIKI
.
db
.
pages
.
query
().
select
(
'id'
).
findOne
({
locale
Code
:
args
.
locale
,
path
:
args
.
path
})
const
page
=
await
WIKI
.
db
.
pages
.
query
().
select
(
'id'
).
findOne
({
locale
:
args
.
locale
,
path
:
args
.
path
})
if
(
page
)
{
if
(
WIKI
.
auth
.
checkAccess
(
context
.
req
.
user
,
[
'read:comments'
],
args
))
{
const
comments
=
await
WIKI
.
db
.
comments
.
query
().
where
(
'pageId'
,
page
.
id
).
orderBy
(
'createdAt'
)
...
...
@@ -57,11 +57,11 @@ export default {
if
(
!
cm
||
!
cm
.
pageId
)
{
throw
new
WIKI
.
Error
.
CommentNotFound
()
}
const
page
=
await
WIKI
.
db
.
pages
.
query
().
select
(
'locale
Code
'
,
'path'
).
findById
(
cm
.
pageId
)
const
page
=
await
WIKI
.
db
.
pages
.
query
().
select
(
'locale'
,
'path'
).
findById
(
cm
.
pageId
)
if
(
page
)
{
if
(
WIKI
.
auth
.
checkAccess
(
context
.
req
.
user
,
[
'read:comments'
],
{
path
:
page
.
path
,
locale
:
page
.
locale
Code
locale
:
page
.
locale
}))
{
return
{
...
cm
,
...
...
server/graph/resolvers/navigation.mjs
View file @
5eaba2cb
...
...
@@ -2,22 +2,19 @@ import { generateError, generateSuccess } from '../../helpers/graph.mjs'
export
default
{
Query
:
{
async
navigationTree
(
obj
,
args
,
context
,
info
)
{
return
WIKI
.
db
.
navigation
.
getTree
({
cache
:
false
,
locale
:
'all'
,
bypassAuth
:
true
})
},
navigationConfig
(
obj
,
args
,
context
,
info
)
{
return
WIKI
.
config
.
nav
async
navigationById
(
obj
,
args
,
context
,
info
)
{
return
WIKI
.
db
.
navigation
.
getNav
({
id
:
args
.
id
,
cache
:
true
,
userGroups
:
context
.
req
.
user
?.
groups
})
}
},
Mutation
:
{
async
updateNavigation
Tree
(
obj
,
args
,
context
)
{
async
updateNavigation
(
obj
,
args
,
context
)
{
try
{
await
WIKI
.
db
.
navigation
.
query
().
patch
({
config
:
args
.
tree
}).
where
(
'key'
,
'site'
)
for
(
const
tree
of
args
.
tree
)
{
await
WIKI
.
cache
.
set
(
`nav:sidebar:
${
tree
.
locale
}
`
,
tree
.
items
,
300
)
}
//
await WIKI.db.navigation.query().patch({
//
config: args.tree
//
}).where('key', 'site')
//
for (const tree of args.tree) {
//
await WIKI.cache.set(`nav:sidebar:${tree.locale}`, tree.items, 300)
//
}
return
{
responseResult
:
generateSuccess
(
'Navigation updated successfully'
)
...
...
@@ -25,20 +22,6 @@ export default {
}
catch
(
err
)
{
return
generateError
(
err
)
}
},
async
updateNavigationConfig
(
obj
,
args
,
context
)
{
try
{
WIKI
.
config
.
nav
=
{
mode
:
args
.
mode
}
await
WIKI
.
configSvc
.
saveToDb
([
'nav'
])
return
{
responseResult
:
generateSuccess
(
'Navigation config updated successfully'
)
}
}
catch
(
err
)
{
return
generateError
(
err
)
}
}
}
}
server/graph/resolvers/page.mjs
View file @
5eaba2cb
...
...
@@ -12,10 +12,10 @@ export default {
* PAGE HISTORY
*/
async
pageHistoryById
(
obj
,
args
,
context
,
info
)
{
const
page
=
await
WIKI
.
db
.
pages
.
query
().
select
(
'path'
,
'locale
Code
'
).
findById
(
args
.
id
)
const
page
=
await
WIKI
.
db
.
pages
.
query
().
select
(
'path'
,
'locale'
).
findById
(
args
.
id
)
if
(
WIKI
.
auth
.
checkAccess
(
context
.
req
.
user
,
[
'read:history'
],
{
path
:
page
.
path
,
locale
:
page
.
locale
Code
locale
:
page
.
locale
}))
{
return
WIKI
.
db
.
pageHistory
.
getHistory
({
pageId
:
args
.
id
,
...
...
@@ -30,10 +30,10 @@ export default {
* PAGE VERSION
*/
async
pageVersionById
(
obj
,
args
,
context
,
info
)
{
const
page
=
await
WIKI
.
db
.
pages
.
query
().
select
(
'path'
,
'locale
Code
'
).
findById
(
args
.
pageId
)
const
page
=
await
WIKI
.
db
.
pages
.
query
().
select
(
'path'
,
'locale'
).
findById
(
args
.
pageId
)
if
(
WIKI
.
auth
.
checkAccess
(
context
.
req
.
user
,
[
'read:history'
],
{
path
:
page
.
path
,
locale
:
page
.
locale
Code
locale
:
page
.
locale
}))
{
return
WIKI
.
db
.
pageHistory
.
getVersion
({
pageId
:
args
.
pageId
,
...
...
@@ -68,7 +68,7 @@ export default {
const
searchCols
=
[
'id'
,
'path'
,
'locale
Code AS locale
'
,
'locale'
,
'title'
,
'description'
,
'icon'
,
...
...
@@ -99,7 +99,7 @@ export default {
builder
.
where
(
'path'
,
'ILIKE'
,
`
${
args
.
path
}
%`
)
}
if
(
args
.
locale
?.
length
>
0
)
{
builder
.
whereIn
(
'locale
Code
'
,
args
.
locale
)
builder
.
whereIn
(
'locale'
,
args
.
locale
)
}
if
(
args
.
editor
)
{
builder
.
where
(
'editor'
,
args
.
editor
)
...
...
@@ -143,7 +143,7 @@ export default {
let
results
=
await
WIKI
.
db
.
pages
.
query
().
column
([
'pages.id'
,
'path'
,
{
locale
:
'localeCode'
}
,
'locale'
,
'title'
,
'description'
,
'isPublished'
,
...
...
@@ -162,7 +162,7 @@ export default {
queryBuilder
.
limit
(
args
.
limit
)
}
if
(
args
.
locale
)
{
queryBuilder
.
where
(
'locale
Code
'
,
args
.
locale
)
queryBuilder
.
where
(
'locale'
,
args
.
locale
)
}
if
(
args
.
creatorId
&&
args
.
authorId
&&
args
.
creatorId
>
0
&&
args
.
authorId
>
0
)
{
queryBuilder
.
where
(
function
()
{
...
...
@@ -220,15 +220,14 @@ export default {
if
(
page
)
{
if
(
WIKI
.
auth
.
checkAccess
(
context
.
req
.
user
,
[
'read:pages'
],
{
path
:
page
.
path
,
locale
:
page
.
locale
Code
locale
:
page
.
locale
}))
{
return
{
...
page
,
...
page
.
config
,
scriptCss
:
page
.
scripts
?.
css
,
scriptJsLoad
:
page
.
scripts
?.
jsLoad
,
scriptJsUnload
:
page
.
scripts
?.
jsUnload
,
locale
:
page
.
localeCode
scriptJsUnload
:
page
.
scripts
?.
jsUnload
}
}
else
{
throw
new
Error
(
'ERR_FORBIDDEN'
)
...
...
@@ -253,8 +252,7 @@ export default {
...
page
.
config
,
scriptCss
:
page
.
scripts
?.
css
,
scriptJsLoad
:
page
.
scripts
?.
jsLoad
,
scriptJsUnload
:
page
.
scripts
?.
jsUnload
,
locale
:
page
.
localeCode
scriptJsUnload
:
page
.
scripts
?.
jsUnload
}
}
else
{
throw
new
Error
(
'ERR_PAGE_NOT_FOUND'
)
...
...
@@ -275,13 +273,13 @@ export default {
const
page
=
await
WIKI
.
db
.
pages
.
query
().
findOne
({
alias
:
args
.
alias
,
siteId
:
args
.
siteId
}).
select
(
'id'
,
'path'
,
'locale
Code
'
)
}).
select
(
'id'
,
'path'
,
'locale'
)
if
(
!
page
)
{
throw
new
Error
(
'ERR_ALIAS_NOT_FOUND'
)
}
return
{
id
:
page
.
id
,
path
:
WIKI
.
sites
[
args
.
siteId
].
config
.
localeNamespacing
?
`
${
page
.
locale
Code
}
/
${
page
.
path
}
`
:
page
.
path
path
:
WIKI
.
sites
[
args
.
siteId
].
config
.
localeNamespacing
?
`
${
page
.
locale
}
/
${
page
.
path
}
`
:
page
.
path
}
},
...
...
@@ -305,7 +303,7 @@ export default {
if
(
args
.
path
&&
!
args
.
parent
)
{
curPage
=
await
WIKI
.
db
.
knex
(
'pageTree'
).
first
(
'parent'
,
'ancestors'
).
where
({
path
:
args
.
path
,
locale
Code
:
args
.
locale
locale
:
args
.
locale
})
if
(
curPage
)
{
args
.
parent
=
curPage
.
parent
||
0
...
...
@@ -315,7 +313,7 @@ export default {
}
const
results
=
await
WIKI
.
db
.
knex
(
'pageTree'
).
where
(
builder
=>
{
builder
.
where
(
'locale
Code
'
,
args
.
locale
)
builder
.
where
(
'locale'
,
args
.
locale
)
switch
(
args
.
mode
)
{
case
'FOLDERS'
:
builder
.
andWhere
(
'isFolder'
,
true
)
...
...
@@ -336,12 +334,12 @@ export default {
return
results
.
filter
(
r
=>
{
return
WIKI
.
auth
.
checkAccess
(
context
.
req
.
user
,
[
'read:pages'
],
{
path
:
r
.
path
,
locale
:
r
.
locale
Code
locale
:
r
.
locale
})
}).
map
(
r
=>
({
...
r
,
parent
:
r
.
parent
||
0
,
locale
:
r
.
locale
Code
locale
:
r
.
locale
}))
},
/**
...
...
@@ -352,25 +350,25 @@ export default {
if
(
WIKI
.
config
.
db
.
type
===
'mysql'
||
WIKI
.
config
.
db
.
type
===
'mariadb'
||
WIKI
.
config
.
db
.
type
===
'sqlite'
)
{
results
=
await
WIKI
.
db
.
knex
(
'pages'
)
.
column
({
id
:
'pages.id'
},
{
path
:
'pages.path'
},
'title'
,
{
link
:
'pageLinks.path'
},
{
locale
:
'pageLinks.locale
Code
'
})
.
column
({
id
:
'pages.id'
},
{
path
:
'pages.path'
},
'title'
,
{
link
:
'pageLinks.path'
},
{
locale
:
'pageLinks.locale'
})
.
leftJoin
(
'pageLinks'
,
'pages.id'
,
'pageLinks.pageId'
)
.
where
({
'pages.locale
Code
'
:
args
.
locale
'pages.locale'
:
args
.
locale
})
.
unionAll
(
WIKI
.
db
.
knex
(
'pageLinks'
)
.
column
({
id
:
'pages.id'
},
{
path
:
'pages.path'
},
'title'
,
{
link
:
'pageLinks.path'
},
{
locale
:
'pageLinks.locale
Code
'
})
.
column
({
id
:
'pages.id'
},
{
path
:
'pages.path'
},
'title'
,
{
link
:
'pageLinks.path'
},
{
locale
:
'pageLinks.locale'
})
.
leftJoin
(
'pages'
,
'pageLinks.pageId'
,
'pages.id'
)
.
where
({
'pages.locale
Code
'
:
args
.
locale
'pages.locale'
:
args
.
locale
})
)
}
else
{
results
=
await
WIKI
.
db
.
knex
(
'pages'
)
.
column
({
id
:
'pages.id'
},
{
path
:
'pages.path'
},
'title'
,
{
link
:
'pageLinks.path'
},
{
locale
:
'pageLinks.locale
Code
'
})
.
column
({
id
:
'pages.id'
},
{
path
:
'pages.path'
},
'title'
,
{
link
:
'pageLinks.path'
},
{
locale
:
'pageLinks.locale'
})
.
fullOuterJoin
(
'pageLinks'
,
'pages.id'
,
'pageLinks.pageId'
)
.
where
({
'pages.locale
Code
'
:
args
.
locale
'pages.locale'
:
args
.
locale
})
}
...
...
@@ -403,11 +401,11 @@ export default {
* CHECK FOR EDITING CONFLICT
*/
async
checkConflicts
(
obj
,
args
,
context
,
info
)
{
let
page
=
await
WIKI
.
db
.
pages
.
query
().
select
(
'path'
,
'locale
Code
'
,
'updatedAt'
).
findById
(
args
.
id
)
let
page
=
await
WIKI
.
db
.
pages
.
query
().
select
(
'path'
,
'locale'
,
'updatedAt'
).
findById
(
args
.
id
)
if
(
page
)
{
if
(
WIKI
.
auth
.
checkAccess
(
context
.
req
.
user
,
[
'write:pages'
,
'manage:pages'
],
{
path
:
page
.
path
,
locale
:
page
.
locale
Code
locale
:
page
.
locale
}))
{
return
page
.
updatedAt
>
args
.
checkoutDate
}
else
{
...
...
@@ -425,12 +423,12 @@ export default {
if
(
page
)
{
if
(
WIKI
.
auth
.
checkAccess
(
context
.
req
.
user
,
[
'write:pages'
,
'manage:pages'
],
{
path
:
page
.
path
,
locale
:
page
.
locale
Code
locale
:
page
.
locale
}))
{
return
{
...
page
,
tags
:
page
.
tags
.
map
(
t
=>
t
.
tag
),
locale
:
page
.
locale
Code
locale
:
page
.
locale
}
}
else
{
throw
new
WIKI
.
Error
.
PageViewForbidden
()
...
...
@@ -626,14 +624,14 @@ export default {
*/
async
restorePage
(
obj
,
args
,
context
)
{
try
{
const
page
=
await
WIKI
.
db
.
pages
.
query
().
select
(
'path'
,
'locale
Code
'
).
findById
(
args
.
pageId
)
const
page
=
await
WIKI
.
db
.
pages
.
query
().
select
(
'path'
,
'locale'
).
findById
(
args
.
pageId
)
if
(
!
page
)
{
throw
new
WIKI
.
Error
.
PageNotFound
()
}
if
(
!
WIKI
.
auth
.
checkAccess
(
context
.
req
.
user
,
[
'write:pages'
],
{
path
:
page
.
path
,
locale
:
page
.
locale
Code
locale
:
page
.
locale
}))
{
throw
new
WIKI
.
Error
.
PageRestoreForbidden
()
}
...
...
server/graph/resolvers/tree.mjs
View file @
5eaba2cb
...
...
@@ -142,7 +142,7 @@ export default {
.
select
(
WIKI
.
db
.
knex
.
raw
(
'tree.*, nlevel(tree."folderPath") AS depth'
))
.
where
({
siteId
:
args
.
siteId
,
locale
Code
:
args
.
locale
,
locale
:
args
.
locale
,
folderPath
:
_
.
dropRight
(
parentPathParts
).
join
(
'.'
),
fileName
:
_
.
last
(
parentPathParts
)
})
...
...
server/graph/schemas/navigation.graphql
View file @
5eaba2cb
...
...
@@ -3,8 +3,9 @@
# ===============================================
extend
type
Query
{
navigationTree
:
[
NavigationTree
]
navigationConfig
:
NavigationConfig
navigationById
(
id
:
UUID
!
):
[
NavigationItem
]
}
# -----------------------------------------------
...
...
@@ -12,11 +13,10 @@ extend type Query {
# -----------------------------------------------
extend
type
Mutation
{
updateNavigationTree
(
tree
:
[
NavigationTreeInput
]!
):
DefaultResponse
updateNavigationConfig
(
mode
:
NavigationMode
!
updateNavigation
(
id
:
UUID
!
name
:
String
!
items
:
[
JSON
]!
):
DefaultResponse
}
...
...
@@ -24,45 +24,12 @@ extend type Mutation {
# TYPES
# -----------------------------------------------
type
NavigationTree
{
locale
:
String
items
:
[
NavigationItem
]
}
input
NavigationTreeInput
{
locale
:
String
!
items
:
[
NavigationItemInput
]!
}
type
NavigationItem
{
id
:
String
kind
:
String
label
:
String
icon
:
String
targetType
:
String
target
:
String
visibilityMode
:
String
visibilityGroups
:
[
Int
]
}
input
NavigationItemInput
{
id
:
String
!
kind
:
String
!
id
:
UUID
type
:
String
label
:
String
icon
:
String
targetType
:
String
target
:
String
visibilityMode
:
String
visibilityGroups
:
[
Int
]
}
type
NavigationConfig
{
mode
:
NavigationMode
}
enum
NavigationMode
{
NONE
TREE
MIXED
STATIC
openInNewWindow
:
Boolean
children
:
[
NavigationItem
]
}
server/graph/schemas/page.graphql
View file @
5eaba2cb
...
...
@@ -237,6 +237,7 @@ type Page {
isBrowsable
:
Boolean
isSearchable
:
Boolean
locale
:
String
navigationId
:
UUID
password
:
String
path
:
String
publishEndDate
:
Date
...
...
server/helpers/common.mjs
View file @
5eaba2cb
...
...
@@ -122,10 +122,10 @@ export function parseModuleProps (props) {
}
export
function
getDictNameFromLocale
(
locale
)
{
const
loc
aleCode
=
locale
.
length
>
2
?
locale
.
substring
(
0
,
2
)
:
locale
if
(
loc
aleCode
in
WIKI
.
config
.
search
.
dictOverrides
)
{
return
WIKI
.
config
.
search
.
dictOverrides
[
loc
aleCode
]
const
loc
=
locale
.
length
>
2
?
locale
.
substring
(
0
,
2
)
:
locale
if
(
loc
in
WIKI
.
config
.
search
.
dictOverrides
)
{
return
WIKI
.
config
.
search
.
dictOverrides
[
loc
]
}
else
{
return
WIKI
.
data
.
tsDictMappings
[
loc
aleCode
]
??
'simple'
return
WIKI
.
data
.
tsDictMappings
[
loc
]
??
'simple'
}
}
server/locales/en.json
View file @
5eaba2cb
...
...
@@ -1683,7 +1683,9 @@
"history.restore.confirmText"
:
"Are you sure you want to restore this page content as it was on {date}? This version will be copied on top of the current history. As such, newer versions will still be preserved."
,
"history.restore.confirmTitle"
:
"Restore page version?"
,
"history.restore.success"
:
"Page version restored succesfully!"
,
"navEdit.clearItems"
:
"Clear All Items"
,
"navEdit.editMenuItems"
:
"Edit Menu Items"
,
"navEdit.emptyMenuText"
:
"Click the Add button to add your first menu item."
,
"navEdit.header"
:
"Header"
,
"navEdit.icon"
:
"Icon"
,
"navEdit.iconHint"
:
"Icon to display to the left of the menu item."
,
...
...
@@ -1691,8 +1693,11 @@
"navEdit.labelHint"
:
"Text to display on the menu item."
,
"navEdit.link"
:
"Link"
,
"navEdit.nestItem"
:
"Nest Item"
,
"navEdit.nestingWarn"
:
"The previous menu item must be a normal link or another nested link. Invalid nested items will be shown in red."
,
"navEdit.noSelection"
:
"Select a menu item from the left to start editing."
,
"navEdit.openInNewWindow"
:
"Open in New Window"
,
"navEdit.openInNewWindowHint"
:
"Whether the link should open in a new window / tab."
,
"navEdit.selectGroups"
:
"Group(s):"
,
"navEdit.separator"
:
"Separator"
,
"navEdit.target"
:
"Target"
,
"navEdit.targetHint"
:
"Target path or external link to point to."
,
...
...
server/models/assets.mjs
View file @
5eaba2cb
...
...
@@ -160,7 +160,7 @@ export class Asset extends Model {
.
innerJoin
(
'assets'
,
'tree.id'
,
'assets.id'
)
.
where
(
id
?
{
'tree.id'
:
id
}
:
{
'tree.hash'
:
generateHash
(
path
),
'tree.locale
Code
'
:
locale
,
'tree.locale'
:
locale
,
'tree.siteId'
:
siteId
})
.
first
()
...
...
server/models/comments.mjs
View file @
5eaba2cb
...
...
@@ -99,7 +99,7 @@ export class Comment extends Model {
if
(
page
)
{
if
(
!
WIKI
.
auth
.
checkAccess
(
user
,
[
'write:comments'
],
{
path
:
page
.
path
,
locale
:
page
.
locale
Code
locale
:
page
.
locale
}))
{
throw
new
WIKI
.
Error
.
CommentPostForbidden
()
}
...
...
@@ -136,7 +136,7 @@ export class Comment extends Model {
if
(
page
)
{
if
(
!
WIKI
.
auth
.
checkAccess
(
user
,
[
'manage:comments'
],
{
path
:
page
.
path
,
locale
:
page
.
locale
Code
locale
:
page
.
locale
}))
{
throw
new
WIKI
.
Error
.
CommentManageForbidden
()
}
...
...
@@ -169,7 +169,7 @@ export class Comment extends Model {
if
(
page
)
{
if
(
!
WIKI
.
auth
.
checkAccess
(
user
,
[
'manage:comments'
],
{
path
:
page
.
path
,
locale
:
page
.
locale
Code
locale
:
page
.
locale
}))
{
throw
new
WIKI
.
Error
.
CommentManageForbidden
()
}
...
...
server/models/navigation.mjs
View file @
5eaba2cb
import
{
Model
}
from
'objection'
import
{
has
,
intersection
}
from
'lodash-es'
import
{
has
,
intersection
,
templateSettings
}
from
'lodash-es'
/**
* Navigation model
*/
export
class
Navigation
extends
Model
{
static
get
tableName
()
{
return
'navigation'
}
static
get
idColumn
()
{
return
'key'
}
static
get
jsonSchema
()
{
return
{
type
:
'object'
,
required
:
[
'key'
],
properties
:
{
key
:
{
type
:
'string'
},
config
:
{
type
:
'array'
,
items
:
{
type
:
'object'
}}
name
:
{
type
:
'string'
},
items
:
{
type
:
'array'
,
items
:
{
type
:
'object'
}}
}
}
}
static
async
getNav
({
id
,
cache
=
false
,
userGroups
=
[]
})
{
const
result
=
await
WIKI
.
db
.
navigation
.
query
().
findById
(
id
).
select
(
'items'
)
return
result
.
items
.
filter
(
item
=>
{
return
!
item
.
visibilityGroups
?.
length
||
intersection
(
item
.
visibilityGroups
,
userGroups
).
length
>
0
}).
map
(
item
=>
{
if
(
!
item
.
children
||
item
.
children
?.
length
<
1
)
{
return
item
}
return
{
...
item
,
children
:
item
.
children
.
filter
(
child
=>
{
return
!
child
.
visibilityGroups
?.
length
||
intersection
(
child
.
visibilityGroups
,
userGroups
).
length
>
0
})
}
})
}
static
async
getTree
({
cache
=
false
,
locale
=
'en'
,
groups
=
[],
bypassAuth
=
false
}
=
{})
{
if
(
cache
)
{
const
navTreeCached
=
await
WIKI
.
cache
.
get
(
`nav:sidebar:
${
locale
}
`
)
...
...
server/models/pageHistory.mjs
View file @
5eaba2cb
...
...
@@ -69,7 +69,7 @@ export class PageHistory extends Model {
relation
:
Model
.
BelongsToOneRelation
,
modelClass
:
Locale
,
join
:
{
from
:
'pageHistory.locale
Code
'
,
from
:
'pageHistory.locale'
,
to
:
'locales.code'
}
}
...
...
@@ -94,7 +94,7 @@ export class PageHistory extends Model {
editor
:
opts
.
editor
,
hash
:
opts
.
hash
,
publishState
:
opts
.
publishState
,
locale
Code
:
opts
.
localeCod
e
,
locale
:
opts
.
local
e
,
path
:
opts
.
path
,
publishEndDate
:
opts
.
publishEndDate
?.
toISO
(),
publishStartDate
:
opts
.
publishStartDate
?.
toISO
(),
...
...
@@ -126,7 +126,7 @@ export class PageHistory extends Model {
{
versionId
:
'pageHistory.id'
,
editor
:
'pageHistory.editorKey'
,
locale
:
'pageHistory.locale
Code
'
,
locale
:
'pageHistory.locale'
,
authorName
:
'author.name'
}
])
...
...
server/models/pageLinks.mjs
View file @
5eaba2cb
...
...
@@ -11,12 +11,12 @@ export class PageLink extends Model {
static
get
jsonSchema
()
{
return
{
type
:
'object'
,
required
:
[
'path'
,
'locale
Code
'
],
required
:
[
'path'
,
'locale'
],
properties
:
{
id
:
{
type
:
'integer'
},
path
:
{
type
:
'string'
},
locale
Code
:
{
type
:
'string'
}
locale
:
{
type
:
'string'
}
}
}
}
...
...
server/models/pages.mjs
View file @
5eaba2cb
...
...
@@ -99,14 +99,6 @@ export class Page extends Model {
from
:
'pages.creatorId'
,
to
:
'users.id'
}
},
locale
:
{
relation
:
Model
.
BelongsToOneRelation
,
modelClass
:
Locale
,
join
:
{
from
:
'pages.localeCode'
,
to
:
'locales.code'
}
}
}
}
...
...
@@ -267,7 +259,7 @@ export class Page extends Model {
// -> Check for duplicate
const
dupCheck
=
await
WIKI
.
db
.
pages
.
query
().
findOne
({
siteId
:
opts
.
siteId
,
locale
Code
:
opts
.
locale
,
locale
:
opts
.
locale
,
path
:
opts
.
path
}).
select
(
'id'
)
if
(
dupCheck
)
{
...
...
@@ -345,7 +337,7 @@ export class Page extends Model {
icon
:
opts
.
icon
,
isBrowsable
:
opts
.
isBrowsable
??
true
,
isSearchable
:
opts
.
isSearchable
??
true
,
locale
Code
:
opts
.
locale
,
locale
:
opts
.
locale
,
ownerId
:
opts
.
user
.
id
,
path
:
opts
.
path
,
publishState
:
opts
.
publishState
,
...
...
@@ -372,7 +364,7 @@ export class Page extends Model {
id
:
page
.
id
,
parentPath
:
initial
(
pathParts
).
join
(
'/'
),
fileName
:
last
(
pathParts
),
locale
:
page
.
locale
Code
,
locale
:
page
.
locale
,
title
:
page
.
title
,
meta
:
{
authorId
:
page
.
authorId
,
...
...
@@ -401,7 +393,7 @@ export class Page extends Model {
// // -> Reconnect Links
// await WIKI.db.pages.reconnectLinks({
// locale: page.locale
Code
,
// locale: page.locale,
// path: page.path,
// mode: 'create'
// })
...
...
@@ -427,7 +419,7 @@ export class Page extends Model {
// -> Check for page access
if
(
!
WIKI
.
auth
.
checkAccess
(
opts
.
user
,
[
'write:pages'
],
{
locale
:
ogPage
.
locale
Code
,
locale
:
ogPage
.
locale
,
path
:
ogPage
.
path
}))
{
throw
new
Error
(
'ERR_PAGE_UPDATE_FORBIDDEN'
)
...
...
@@ -596,7 +588,7 @@ export class Page extends Model {
// -> Format CSS Scripts
if
(
opts
.
patch
.
scriptCss
)
{
if
(
WIKI
.
auth
.
checkAccess
(
opts
.
user
,
[
'write:styles'
],
{
locale
:
ogPage
.
locale
Code
,
locale
:
ogPage
.
locale
,
path
:
ogPage
.
path
}))
{
patch
.
scripts
=
{
...
...
@@ -610,7 +602,7 @@ export class Page extends Model {
// -> Format JS Scripts
if
(
opts
.
patch
.
scriptJsLoad
)
{
if
(
WIKI
.
auth
.
checkAccess
(
opts
.
user
,
[
'write:scripts'
],
{
locale
:
ogPage
.
locale
Code
,
locale
:
ogPage
.
locale
,
path
:
ogPage
.
path
}))
{
patch
.
scripts
=
{
...
...
@@ -622,7 +614,7 @@ export class Page extends Model {
}
if
(
opts
.
patch
.
scriptJsUnload
)
{
if
(
WIKI
.
auth
.
checkAccess
(
opts
.
user
,
[
'write:scripts'
],
{
locale
:
ogPage
.
locale
Code
,
locale
:
ogPage
.
locale
,
path
:
ogPage
.
path
}))
{
patch
.
scripts
=
{
...
...
@@ -701,11 +693,11 @@ export class Page extends Model {
if
(
!
id
)
{
throw
new
Error
(
'Must provide either the page ID or the page object.'
)
}
page
=
await
WIKI
.
db
.
pages
.
query
().
findById
(
id
).
select
(
'id'
,
'locale
Code
'
,
'render'
,
'password'
)
page
=
await
WIKI
.
db
.
pages
.
query
().
findById
(
id
).
select
(
'id'
,
'locale'
,
'render'
,
'password'
)
}
// -> Exclude password-protected content from being indexed
const
safeContent
=
page
.
password
?
''
:
WIKI
.
db
.
pages
.
cleanHTML
(
page
.
render
)
const
dictName
=
getDictNameFromLocale
(
page
.
locale
Code
)
const
dictName
=
getDictNameFromLocale
(
page
.
locale
)
return
WIKI
.
db
.
knex
(
'pages'
).
where
(
'id'
,
page
.
id
).
update
({
searchContent
:
safeContent
,
ts
:
WIKI
.
db
.
knex
.
raw
(
`
...
...
@@ -747,7 +739,7 @@ export class Page extends Model {
// -> Check for page access
if
(
!
WIKI
.
auth
.
checkAccess
(
opts
.
user
,
[
'write:pages'
],
{
locale
:
ogPage
.
locale
Code
,
locale
:
ogPage
.
locale
,
path
:
ogPage
.
path
}))
{
throw
new
WIKI
.
Error
.
PageUpdateForbidden
()
...
...
@@ -908,7 +900,7 @@ export class Page extends Model {
}
else
{
page
=
await
WIKI
.
db
.
pages
.
query
().
findOne
({
path
:
opts
.
path
,
locale
Code
:
opts
.
locale
locale
:
opts
.
locale
})
}
if
(
!
page
)
{
...
...
@@ -932,7 +924,7 @@ export class Page extends Model {
// -> Check for source page access
if
(
!
WIKI
.
auth
.
checkAccess
(
opts
.
user
,
[
'manage:pages'
],
{
locale
:
page
.
locale
Code
,
locale
:
page
.
locale
,
path
:
page
.
path
}))
{
throw
new
WIKI
.
Error
.
PageMoveForbidden
()
...
...
@@ -948,7 +940,7 @@ export class Page extends Model {
// -> Check for existing page at destination path
const
destPage
=
await
WIKI
.
db
.
pages
.
query
().
findOne
({
path
:
opts
.
destinationPath
,
locale
Code
:
opts
.
destinationLocale
locale
:
opts
.
destinationLocale
})
if
(
destPage
)
{
throw
new
WIKI
.
Error
.
PagePathCollision
()
...
...
@@ -967,7 +959,7 @@ export class Page extends Model {
const
destinationTitle
=
(
page
.
title
===
page
.
path
?
opts
.
destinationPath
:
page
.
title
)
await
WIKI
.
db
.
pages
.
query
().
patch
({
path
:
opts
.
destinationPath
,
locale
Code
:
opts
.
destinationLocale
,
locale
:
opts
.
destinationLocale
,
title
:
destinationTitle
,
hash
:
destinationHash
}).
findById
(
page
.
id
)
...
...
@@ -983,7 +975,7 @@ export class Page extends Model {
await
WIKI
.
data
.
searchEngine
.
renamed
({
...
page
,
destinationPath
:
opts
.
destinationPath
,
destinationLocale
Code
:
opts
.
destinationLocale
,
destinationLocale
:
opts
.
destinationLocale
,
destinationHash
})
...
...
@@ -994,7 +986,7 @@ export class Page extends Model {
page
:
{
...
page
,
destinationPath
:
opts
.
destinationPath
,
destinationLocale
Code
:
opts
.
destinationLocale
,
destinationLocale
:
opts
.
destinationLocale
,
destinationHash
,
moveAuthorId
:
opts
.
user
.
id
,
moveAuthorName
:
opts
.
user
.
name
,
...
...
@@ -1005,7 +997,7 @@ export class Page extends Model {
// -> Reconnect Links : Changing old links to the new path
await
WIKI
.
db
.
pages
.
reconnectLinks
({
sourceLocale
:
page
.
locale
Code
,
sourceLocale
:
page
.
locale
,
sourcePath
:
page
.
path
,
locale
:
opts
.
destinationLocale
,
path
:
opts
.
destinationPath
,
...
...
@@ -1066,7 +1058,7 @@ export class Page extends Model {
// -> Reconnect Links
await
WIKI
.
db
.
pages
.
reconnectLinks
({
locale
:
page
.
locale
Code
,
locale
:
page
.
locale
,
path
:
page
.
path
,
mode
:
'delete'
})
...
...
@@ -1118,7 +1110,7 @@ export class Page extends Model {
.
whereIn
(
'pages.id'
,
function
()
{
this
.
select
(
'pageLinks.pageId'
).
from
(
'pageLinks'
).
where
({
'pageLinks.path'
:
opts
.
path
,
'pageLinks.locale
Code
'
:
opts
.
locale
'pageLinks.locale'
:
opts
.
locale
})
})
affectedHashes
=
qryHashes
.
map
(
h
=>
h
.
hash
)
...
...
@@ -1131,7 +1123,7 @@ export class Page extends Model {
.
whereIn
(
'pages.id'
,
function
()
{
this
.
select
(
'pageLinks.pageId'
).
from
(
'pageLinks'
).
where
({
'pageLinks.path'
:
opts
.
path
,
'pageLinks.locale
Code
'
:
opts
.
locale
'pageLinks.locale'
:
opts
.
locale
})
})
const
qryHashes
=
await
WIKI
.
db
.
pages
.
query
()
...
...
@@ -1139,7 +1131,7 @@ export class Page extends Model {
.
whereIn
(
'pages.id'
,
function
()
{
this
.
select
(
'pageLinks.pageId'
).
from
(
'pageLinks'
).
where
({
'pageLinks.path'
:
opts
.
path
,
'pageLinks.locale
Code
'
:
opts
.
locale
'pageLinks.locale'
:
opts
.
locale
})
})
affectedHashes
=
qryHashes
.
map
(
h
=>
h
.
hash
)
...
...
@@ -1227,20 +1219,18 @@ export class Page extends Model {
authorEmail
:
'author.email'
,
creatorName
:
'creator.name'
,
creatorEmail
:
'creator.email'
}
},
'tree.navigationId'
])
.
joinRelated
(
'author'
)
.
joinRelated
(
'creator'
)
// .withGraphJoined('tags')
// .modifyGraph('tags', builder => {
// builder.select('tag')
// })
.
leftJoin
(
'tree'
,
'pages.id'
,
'tree.id'
)
.
where
(
queryModeID
?
{
'pages.id'
:
opts
}
:
{
'pages.siteId'
:
opts
.
siteId
,
'pages.path'
:
opts
.
path
,
'pages.locale
Code
'
:
opts
.
locale
'pages.locale'
:
opts
.
locale
})
// .andWhere(builder => {
// if (queryModeID) return
...
...
@@ -1307,7 +1297,7 @@ export class Page extends Model {
return
{
...
page
,
path
:
opts
.
path
,
locale
Code
:
opts
.
locale
locale
:
opts
.
locale
}
}
catch
(
err
)
{
if
(
err
.
code
===
'ENOENT'
)
{
...
...
@@ -1346,13 +1336,13 @@ export class Page extends Model {
static
async
migrateToLocale
({
sourceLocale
,
targetLocale
})
{
return
WIKI
.
db
.
pages
.
query
()
.
patch
({
locale
Code
:
targetLocale
locale
:
targetLocale
})
.
where
({
locale
Code
:
sourceLocale
locale
:
sourceLocale
})
.
whereNotExists
(
function
()
{
this
.
select
(
'id'
).
from
(
'pages AS pagesm'
).
where
(
'pagesm.locale
Code
'
,
targetLocale
).
andWhereRaw
(
'pagesm.path = pages.path'
)
this
.
select
(
'id'
).
from
(
'pages AS pagesm'
).
where
(
'pagesm.locale'
,
targetLocale
).
andWhereRaw
(
'pagesm.path = pages.path'
)
})
}
...
...
server/models/sites.mjs
View file @
5eaba2cb
import
{
Model
}
from
'objection'
import
{
defaultsDeep
,
keyBy
}
from
'lodash-es'
import
{
v4
as
uuid
}
from
'uuid'
/**
* Site model
...
...
@@ -47,7 +48,16 @@ export class Site extends Model {
}
static
async
createSite
(
hostname
,
config
)
{
const
newSiteId
=
uuid
const
newDefaultNav
=
await
WIKI
.
db
.
navigation
.
query
().
insertAndFetch
({
name
:
'Default'
,
siteId
:
newSiteId
,
items
:
JSON
.
stringify
([])
})
const
newSite
=
await
WIKI
.
db
.
sites
.
query
().
insertAndFetch
({
id
:
newSiteId
,
hostname
,
isEnabled
:
true
,
config
:
defaultsDeep
(
config
,
{
...
...
@@ -138,6 +148,10 @@ export class Site extends Model {
config
:
{}
}
},
nav
:
{
mode
:
'mixed'
,
defaultId
:
newDefaultNav
.
id
,
},
uploads
:
{
conflictBehavior
:
'overwrite'
,
normalizeFilename
:
true
...
...
server/models/tree.mjs
View file @
5eaba2cb
...
...
@@ -43,14 +43,6 @@ export class Tree extends Model {
static
get
relationMappings
()
{
return
{
locale
:
{
relation
:
Model
.
BelongsToOneRelation
,
modelClass
:
Locale
,
join
:
{
from
:
'tree.localeCode'
,
to
:
'locales.code'
}
},
site
:
{
relation
:
Model
.
BelongsToOneRelation
,
modelClass
:
Site
,
...
...
@@ -99,7 +91,7 @@ export class Tree extends Model {
const
parent
=
await
WIKI
.
db
.
knex
(
'tree'
).
where
({
...
parentFilter
,
type
:
'folder'
,
locale
Code
:
locale
,
locale
:
locale
,
siteId
}).
first
()
if
(
parent
)
{
...
...
@@ -153,7 +145,7 @@ export class Tree extends Model {
type
:
'page'
,
title
:
title
,
hash
:
generateHash
(
fullPath
),
locale
Code
:
locale
,
locale
:
locale
,
siteId
,
meta
}).
returning
(
'*'
)
...
...
@@ -196,7 +188,7 @@ export class Tree extends Model {
type
:
'asset'
,
title
:
title
,
hash
:
generateHash
(
fullPath
),
locale
Code
:
locale
,
locale
:
locale
,
siteId
,
meta
}).
returning
(
'*'
)
...
...
@@ -251,7 +243,7 @@ export class Tree extends Model {
// Check for collision
const
existingFolder
=
await
WIKI
.
db
.
knex
(
'tree'
).
select
(
'id'
).
where
({
siteId
:
siteId
,
locale
Code
:
locale
,
locale
:
locale
,
folderPath
:
encodeFolderPath
(
parentPath
),
fileName
:
pathName
}).
first
()
...
...
@@ -284,7 +276,7 @@ export class Tree extends Model {
type
:
'folder'
,
title
:
ancestor
.
fileName
,
hash
:
generateHash
(
newAncestorFullPath
),
locale
Code
:
locale
,
locale
:
locale
,
siteId
:
siteId
,
meta
:
{
children
:
1
...
...
@@ -306,7 +298,7 @@ export class Tree extends Model {
type
:
'folder'
,
title
:
title
,
hash
:
generateHash
(
fullPath
),
locale
Code
:
locale
,
locale
:
locale
,
siteId
:
siteId
,
meta
:
{
children
:
0
...
...
server/models/users.mjs
View file @
5eaba2cb
...
...
@@ -53,14 +53,6 @@ export class User extends Model {
},
to
:
'groups.id'
}
},
locale
:
{
relation
:
Model
.
BelongsToOneRelation
,
modelClass
:
Locale
,
join
:
{
from
:
'users.localeCode'
,
to
:
'locales.code'
}
}
}
}
...
...
@@ -232,7 +224,7 @@ export class User extends Model {
email
:
primaryEmail
,
name
:
displayName
,
pictureUrl
:
pictureUrl
,
locale
Code
:
WIKI
.
config
.
lang
.
code
,
locale
:
WIKI
.
config
.
lang
.
code
,
defaultEditor
:
'markdown'
,
tfaIsActive
:
false
,
isSystem
:
false
,
...
...
server/modules/comments/default/comment.js
View file @
5eaba2cb
...
...
@@ -89,7 +89,7 @@ module.exports = {
content
,
name
:
user
.
name
,
email
:
user
.
email
,
permalink
:
`
${
WIKI
.
config
.
host
}
/
${
page
.
locale
Code
}
/
${
page
.
path
}
`
,
permalink
:
`
${
WIKI
.
config
.
host
}
/
${
page
.
locale
}
/
${
page
.
path
}
`
,
permalinkDate
:
page
.
updatedAt
,
type
:
(
replyTo
>
0
)
?
'reply'
:
'comment'
,
role
:
userRole
...
...
server/modules/rendering/core/renderer.mjs
View file @
5eaba2cb
...
...
@@ -68,12 +68,12 @@ export async function render () {
// -> Reformat paths
if
(
href
.
indexOf
(
'/'
)
!==
0
)
{
if
(
this
.
config
.
absoluteLinks
)
{
href
=
`/
${
this
.
page
.
locale
Code
}
/
${
href
}
`
href
=
`/
${
this
.
page
.
locale
}
/
${
href
}
`
}
else
{
href
=
(
this
.
page
.
path
===
'home'
)
?
`/
${
this
.
page
.
locale
Code
}
/
${
href
}
`
:
`/
${
this
.
page
.
localeCod
e
}
/
${
this
.
page
.
path
}
/
${
href
}
`
href
=
(
this
.
page
.
path
===
'home'
)
?
`/
${
this
.
page
.
locale
}
/
${
href
}
`
:
`/
${
this
.
page
.
local
e
}
/
${
this
.
page
.
path
}
/
${
href
}
`
}
}
else
if
(
href
.
charAt
(
3
)
!==
'/'
)
{
href
=
`/
${
this
.
page
.
locale
Code
}${
href
}
`
href
=
`/
${
this
.
page
.
locale
}${
href
}
`
}
try
{
...
...
@@ -101,7 +101,7 @@ export async function render () {
}
// -> Save internal references
internalRefs
.
push
({
locale
Code
:
pagePath
.
locale
,
locale
:
pagePath
.
locale
,
path
:
pagePath
.
path
})
...
...
@@ -127,7 +127,7 @@ export async function render () {
if
(
internalRefs
.
length
>
0
)
{
// -> Find matching pages
const
results
=
await
WIKI
.
db
.
pages
.
query
().
column
(
'id'
,
'path'
,
'locale
Code
'
).
where
(
builder
=>
{
const
results
=
await
WIKI
.
db
.
pages
.
query
().
column
(
'id'
,
'path'
,
'locale'
).
where
(
builder
=>
{
internalRefs
.
forEach
((
ref
,
idx
)
=>
{
if
(
idx
<
1
)
{
builder
.
where
(
ref
)
...
...
@@ -148,7 +148,7 @@ export async function render () {
return
}
if
(
_
.
some
(
results
,
r
=>
{
return
r
.
locale
Code
===
hrefObj
.
locale
&&
r
.
path
===
hrefObj
.
path
return
r
.
locale
===
hrefObj
.
locale
&&
r
.
path
===
hrefObj
.
path
}))
{
$
(
elm
).
addClass
(
`is-valid-page`
)
}
else
{
...
...
@@ -158,21 +158,21 @@ export async function render () {
// -> Add missing links
const
missingLinks
=
_
.
differenceWith
(
internalRefs
,
pastLinks
,
(
nLink
,
pLink
)
=>
{
return
nLink
.
locale
Code
===
pLink
.
localeCod
e
&&
nLink
.
path
===
pLink
.
path
return
nLink
.
locale
===
pLink
.
local
e
&&
nLink
.
path
===
pLink
.
path
})
if
(
missingLinks
.
length
>
0
)
{
if
(
WIKI
.
config
.
db
.
type
===
'postgres'
)
{
await
WIKI
.
db
.
pageLinks
.
query
().
insert
(
missingLinks
.
map
(
lnk
=>
({
pageId
:
this
.
page
.
id
,
path
:
lnk
.
path
,
locale
Code
:
lnk
.
localeCod
e
locale
:
lnk
.
local
e
})))
}
else
{
for
(
const
lnk
of
missingLinks
)
{
await
WIKI
.
db
.
pageLinks
.
query
().
insert
({
pageId
:
this
.
page
.
id
,
path
:
lnk
.
path
,
locale
Code
:
lnk
.
localeCod
e
locale
:
lnk
.
local
e
})
}
}
...
...
@@ -182,7 +182,7 @@ export async function render () {
// -> Remove outdated links
if
(
pastLinks
)
{
const
outdatedLinks
=
_
.
differenceWith
(
pastLinks
,
internalRefs
,
(
nLink
,
pLink
)
=>
{
return
nLink
.
locale
Code
===
pLink
.
localeCod
e
&&
nLink
.
path
===
pLink
.
path
return
nLink
.
locale
===
pLink
.
local
e
&&
nLink
.
path
===
pLink
.
path
})
if
(
outdatedLinks
.
length
>
0
)
{
await
WIKI
.
db
.
pageLinks
.
query
().
delete
().
whereIn
(
'id'
,
_
.
map
(
outdatedLinks
,
'id'
))
...
...
server/tasks/workers/rebuild-search-index.mjs
View file @
5eaba2cb
...
...
@@ -9,7 +9,7 @@ export async function task ({ payload }) {
let
idx
=
0
await
pipeline
(
WIKI
.
db
.
knex
.
select
(
'id'
,
'title'
,
'description'
,
'locale
Code
'
,
'render'
,
'password'
).
from
(
'pages'
).
stream
(),
WIKI
.
db
.
knex
.
select
(
'id'
,
'title'
,
'description'
,
'locale'
,
'render'
,
'password'
).
from
(
'pages'
).
stream
(),
new
Transform
({
objectMode
:
true
,
transform
:
async
(
page
,
enc
,
cb
)
=>
{
...
...
ux/src/components/IconPickerDialog.vue
View file @
5eaba2cb
...
...
@@ -125,7 +125,7 @@ import { computed, onMounted, reactive } from 'vue'
// PROPS
const
props
=
defineProps
({
v
alue
:
{
modelV
alue
:
{
type
:
String
,
required
:
true
}
...
...
@@ -133,7 +133,7 @@ const props = defineProps({
// EMITS
const
emit
=
defineEmits
([
'
input
'
])
const
emit
=
defineEmits
([
'
update:modelValue
'
])
// DATA
...
...
@@ -169,24 +169,24 @@ const iconPackRefWebsite = computed(() => {
function
apply
()
{
if
(
state
.
currentTab
===
'img'
)
{
emit
(
'
input
'
,
`img:
${
state
.
imgPath
}
`
)
emit
(
'
update:modelValue
'
,
`img:
${
state
.
imgPath
}
`
)
}
else
{
emit
(
'
input
'
,
state
.
iconName
)
emit
(
'
update:modelValue
'
,
state
.
iconName
)
}
}
// MOUNTED
onMounted
(()
=>
{
if
(
props
.
v
alue
?.
startsWith
(
'img:'
))
{
if
(
props
.
modelV
alue
?.
startsWith
(
'img:'
))
{
state
.
currentTab
=
'img'
state
.
imgPath
=
props
.
v
alue
.
substring
(
4
)
state
.
imgPath
=
props
.
modelV
alue
.
substring
(
4
)
}
else
{
state
.
currentTab
=
'icon'
for
(
const
pack
of
iconPacks
)
{
if
(
props
.
value
?.
startsWith
(
pack
.
prefix
))
{
state
.
selPack
=
pack
.
value
state
.
selIcon
=
props
.
v
alue
.
substring
(
pack
.
prefix
.
length
)
state
.
selIcon
=
props
.
modelV
alue
.
substring
(
pack
.
prefix
.
length
)
break
}
}
...
...
ux/src/components/NavEditMenu.vue
View file @
5eaba2cb
...
...
@@ -16,19 +16,19 @@ q-card(style='min-width: 350px')
q-list(padding)
q-item(tag='label')
q-item-section(side)
q-radio(v-model='state.mode', val='inherit')
q-radio(v-model='state.mode', val='inherit'
, :disable='isRoot'
)
q-item-section
q-item-label Inherit
q-item-label(caption) Use the menu items and settings from the parent path.
q-item(tag='label')
q-item-section(side)
q-radio(v-model='state.mode', val='starting')
q-radio(v-model='state.mode', val='starting'
, :disable='isRoot'
)
q-item-section
q-item-label Override Current + Descendants
q-item-label(caption) Set menu items and settings for this path and all children.
q-item(tag='label')
q-item-section(side)
q-radio(v-model='state.mode', val='exact')
q-radio(v-model='state.mode', val='exact'
, :disable='isRoot'
)
q-item-section
q-item-label Override Current Only
q-item-label(caption) Set menu items and settings only for this path.
...
...
@@ -50,9 +50,10 @@ q-card(style='min-width: 350px')
</
template
>
<
script
setup
>
import
{
onMounted
,
reactive
,
ref
,
watch
}
from
'vue'
import
{
computed
,
onMounted
,
reactive
,
ref
,
watch
}
from
'vue'
import
{
useI18n
}
from
'vue-i18n'
import
{
usePageStore
}
from
'src/stores/page'
import
{
useSiteStore
}
from
'src/stores/site'
// PROPS
...
...
@@ -66,6 +67,7 @@ const props = defineProps({
// STORES
const
pageStore
=
usePageStore
()
const
siteStore
=
useSiteStore
()
// I18N
...
...
ux/src/components/NavEditOverlay.vue
View file @
5eaba2cb
This diff is collapsed.
Click to expand it.
ux/src/components/NavSidebar.vue
View file @
5eaba2cb
...
...
@@ -8,20 +8,22 @@ q-scroll-area.sidebar-nav(
dense
dark
)
q-item-label.text-blue-2.text-caption(header) Header
q-item(to='/install')
q-item-section(side)
q-icon(name='las la-dog', color='white')
q-item-section Link 1
q-item(to='/install')
q-item-section(side)
q-icon(name='las la-cat', color='white')
q-item-section Link 2
q-separator.q-my-sm(dark)
q-item(to='/install')
q-item-section(side)
q-icon(name='mdi-fruit-grapes', color='white')
q-item-section.text-wordbreak-all Link 3
template(v-for='item of siteStore.nav.items')
q-item-label.text-blue-2.text-caption.text-wordbreak-all(
v-if='item.type === `header`'
header
)
{{
item
.
label
}}
q-item(
v-else-if='item.type === `link`'
:to='item.target'
)
q-item-section(side)
q-icon(:name='item.icon', color='white')
q-item-section.text-wordbreak-all.text-white
{{
item
.
label
}}
q-separator.q-my-sm(
v-else-if='item.type === `separator`'
dark
)
</
template
>
<
script
setup
>
...
...
@@ -30,6 +32,7 @@ import { computed, onMounted, reactive, ref, watch } from 'vue'
import
{
useRouter
,
useRoute
}
from
'vue-router'
import
{
useI18n
}
from
'vue-i18n'
import
{
usePageStore
}
from
'src/stores/page'
import
{
useSiteStore
}
from
'src/stores/site'
// QUASAR
...
...
@@ -38,6 +41,7 @@ const $q = useQuasar()
// STORES
const
pageStore
=
usePageStore
()
const
siteStore
=
useSiteStore
()
// ROUTER
...
...
@@ -63,6 +67,15 @@ const barStyle = {
width
:
'9px'
,
opacity
:
0.1
}
// WATCHERS
watch
(()
=>
pageStore
.
navigationId
,
(
newValue
)
=>
{
if
(
newValue
!==
siteStore
.
nav
.
currentId
)
{
siteStore
.
fetchNavigation
(
newValue
)
}
},
{
immediate
:
true
})
</
script
>
<
style
lang=
"scss"
>
...
...
ux/src/layouts/MainLayout.vue
View file @
5eaba2cb
...
...
@@ -33,6 +33,14 @@ q-layout(view='hHh Lpr lff')
nav-sidebar
q-bar.bg-blue-9.text-white(dense, v-if='userStore.authenticated')
q-btn.col(
v-if='isRoot'
icon='las la-dharmachakra'
label='Edit Nav'
flat
@click='siteStore.$patch({ overlay: `NavEdit` })'
)
q-btn.col(
v-else
icon='las la-dharmachakra'
label='Edit Nav'
flat
...
...
@@ -44,7 +52,6 @@ q-layout(view='hHh Lpr lff')
:offset='[0, 10]'
)
nav-edit-menu(:menu-hide-handler='navEditMenu.hide')
q-separator(vertical)
q-btn.col(
icon='las la-bookmark'
...
...
@@ -78,6 +85,7 @@ import { useI18n } from 'vue-i18n'
import
{
useCommonStore
}
from
'src/stores/common'
import
{
useEditorStore
}
from
'src/stores/editor'
import
{
useFlagsStore
}
from
'src/stores/flags'
import
{
usePageStore
}
from
'src/stores/page'
import
{
useSiteStore
}
from
'src/stores/site'
import
{
useUserStore
}
from
'src/stores/user'
...
...
@@ -99,6 +107,7 @@ const $q = useQuasar()
const
commonStore
=
useCommonStore
()
const
editorStore
=
useEditorStore
()
const
flagsStore
=
useFlagsStore
()
const
pageStore
=
usePageStore
()
const
siteStore
=
useSiteStore
()
const
userStore
=
useUserStore
()
...
...
@@ -127,6 +136,10 @@ const isSidebarShown = computed(() => {
return
siteStore
.
showSideNav
&&
!
siteStore
.
sideNavIsDisabled
&&
!
(
editorStore
.
isActive
&&
editorStore
.
hideSideNav
)
})
const
isRoot
=
computed
(()
=>
{
return
pageStore
.
path
===
''
||
pageStore
.
path
===
'home'
})
</
script
>
<
style
lang=
"scss"
>
...
...
ux/src/stores/page.js
View file @
5eaba2cb
...
...
@@ -21,6 +21,7 @@ const pagePropsFragment = gql`
isBrowsable
isSearchable
locale
navigationId
password
path
publishEndDate
...
...
@@ -197,6 +198,7 @@ export const usePageStore = defineStore('page', {
isBrowsable
:
true
,
isSearchable
:
true
,
locale
:
'en'
,
navigationId
:
null
,
password
:
''
,
path
:
''
,
publishEndDate
:
''
,
...
...
ux/src/stores/site.js
View file @
5eaba2cb
...
...
@@ -65,7 +65,10 @@ export const useSiteStore = defineStore('site', {
sideDialogShown
:
false
,
sideDialogComponent
:
''
,
docsBase
:
'https://next.js.wiki/docs'
,
nav
:
{}
nav
:
{
currentId
:
null
,
items
:
[]
}
}),
getters
:
{
overlayIsShown
:
(
state
)
=>
Boolean
(
state
.
overlay
),
...
...
@@ -236,6 +239,44 @@ export const useSiteStore = defineStore('site', {
console
.
warn
(
err
.
networkError
?.
result
??
err
.
message
)
throw
err
}
},
async
fetchNavigation
(
id
)
{
try
{
const
resp
=
await
APOLLO_CLIENT
.
query
({
query
:
gql
`
query getNavigationItems ($id: UUID!) {
navigationById (
id: $id
) {
id
type
label
icon
target
openInNewWindow
children {
id
type
label
icon
target
openInNewWindow
}
}
}
`
,
variables
:
{
id
}
})
this
.
$patch
({
nav
:
{
currentId
:
id
,
items
:
resp
?.
data
?.
navigationById
??
[]
}
})
}
catch
(
err
)
{
console
.
warn
(
err
.
networkError
?.
result
??
err
.
message
)
throw
err
}
}
}
})
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