refactor: global namespace + admin pages UI

This commit is contained in:
NGPixel
2018-03-05 15:49:36 -05:00
parent f203173c6c
commit 7acc4e9fed
61 changed files with 751 additions and 508 deletions

34
server/graph/index.js Normal file
View File

@@ -0,0 +1,34 @@
const _ = require('lodash')
const fs = require('fs')
const gqlTools = require('graphql-tools')
const path = require('path')
const autoload = require('auto-load')
/* global WIKI */
WIKI.logger.info(`Loading GraphQL Schema...`)
// Schemas
let typeDefs = []
let schemas = fs.readdirSync(path.join(WIKI.SERVERPATH, 'graph/schemas'))
schemas.forEach(schema => {
typeDefs.push(fs.readFileSync(path.join(WIKI.SERVERPATH, `graph/schemas/${schema}`), 'utf8'))
})
// Resolvers
let resolvers = {}
const resolversObj = _.values(autoload(path.join(WIKI.SERVERPATH, 'graph/resolvers')))
resolversObj.forEach(resolver => {
_.merge(resolvers, resolver)
})
const Schema = gqlTools.makeExecutableSchema({
typeDefs,
resolvers
})
WIKI.logger.info(`GraphQL Schema: [ OK ]`)
module.exports = Schema

View File

@@ -0,0 +1,45 @@
const _ = require('lodash')
const fs = require('fs-extra')
const path = require('path')
/* global WIKI */
module.exports = {
Query: {
async authentication() { return {} }
},
Mutation: {
async authentication() { return {} }
},
AuthenticationQuery: {
providers(obj, args, context, info) {
switch (args.mode) {
case 'active':
let strategies = _.chain(WIKI.auth.strategies).map(str => {
return {
key: str.key,
title: str.title,
useForm: str.useForm
}
}).sortBy(['title']).value()
let localStrategy = _.remove(strategies, str => str.key === 'local')
return _.concat(localStrategy, strategies)
case 'all':
break
default:
return null
}
}
},
AuthenticationProvider: {
icon (ap, args) {
return fs.readFileAsync(path.join(WIKI.ROOTPATH, `assets/svg/auth-icon-${ap.key}.svg`), 'utf8').catch(err => {
if (err.code === 'ENOENT') {
return null
}
throw err
})
}
}
}

View File

@@ -0,0 +1,42 @@
/* global WIKI */
module.exports = {
Query: {
comments(obj, args, context, info) {
return WIKI.db.Comment.findAll({ where: args })
}
},
Mutation: {
createComment(obj, args) {
return WIKI.db.Comment.create({
content: args.content,
author: args.userId,
document: args.documentId
})
},
deleteComment(obj, args) {
return WIKI.db.Comment.destroy({
where: {
id: args.id
},
limit: 1
})
},
modifyComment(obj, args) {
return WIKI.db.Comment.update({
content: args.content
}, {
where: { id: args.id }
})
}
},
Comment: {
author(cm) {
return cm.getAuthor()
},
document(cm) {
return cm.getDocument()
}
}
}

View File

@@ -0,0 +1,46 @@
/* global WIKI */
module.exports = {
Query: {
documents(obj, args, context, info) {
return WIKI.db.Document.findAll({ where: args })
}
},
Mutation: {
createDocument(obj, args) {
return WIKI.db.Document.create(args)
},
deleteDocument(obj, args) {
return WIKI.db.Document.destroy({
where: {
id: args.id
},
limit: 1
})
},
modifyDocument(obj, args) {
return WIKI.db.Document.update({
title: args.title,
subtitle: args.subtitle
}, {
where: { id: args.id }
})
},
moveDocument(obj, args) {
return WIKI.db.Document.update({
path: args.path
}, {
where: { id: args.id }
})
}
},
Document: {
comments(doc) {
return doc.getComments()
},
tags(doc) {
return doc.getTags()
}
}
}

View File

@@ -0,0 +1,51 @@
/* global WIKI */
const gql = require('graphql')
module.exports = {
Query: {
files(obj, args, context, info) {
return WIKI.db.File.findAll({ where: args })
}
},
Mutation: {
uploadFile(obj, args) {
// todo
return WIKI.db.File.create(args)
},
deleteFile(obj, args) {
return WIKI.db.File.destroy({
where: {
id: args.id
},
limit: 1
})
},
renameFile(obj, args) {
return WIKI.db.File.update({
filename: args.filename
}, {
where: { id: args.id }
})
},
moveFile(obj, args) {
return WIKI.db.File.findById(args.fileId).then(fl => {
if (!fl) {
throw new gql.GraphQLError('Invalid File ID')
}
return WIKI.db.Folder.findById(args.folderId).then(fld => {
if (!fld) {
throw new gql.GraphQLError('Invalid Folder ID')
}
return fl.setFolder(fld)
})
})
}
},
File: {
folder(fl) {
return fl.getFolder()
}
}
}

View File

@@ -0,0 +1,35 @@
/* global WIKI */
module.exports = {
Query: {
folders(obj, args, context, info) {
return WIKI.db.Folder.findAll({ where: args })
}
},
Mutation: {
createFolder(obj, args) {
return WIKI.db.Folder.create(args)
},
deleteGroup(obj, args) {
return WIKI.db.Folder.destroy({
where: {
id: args.id
},
limit: 1
})
},
renameFolder(obj, args) {
return WIKI.db.Folder.update({
name: args.name
}, {
where: { id: args.id }
})
}
},
Folder: {
files(grp) {
return grp.getFiles()
}
}
}

View File

@@ -0,0 +1,63 @@
/* global WIKI */
const gql = require('graphql')
module.exports = {
Query: {
groups(obj, args, context, info) {
return WIKI.db.Group.findAll({ where: args })
}
},
Mutation: {
assignUserToGroup(obj, args) {
return WIKI.db.Group.findById(args.groupId).then(grp => {
if (!grp) {
throw new gql.GraphQLError('Invalid Group ID')
}
return WIKI.db.User.findById(args.userId).then(usr => {
if (!usr) {
throw new gql.GraphQLError('Invalid User ID')
}
return grp.addUser(usr)
})
})
},
createGroup(obj, args) {
return WIKI.db.Group.create(args)
},
deleteGroup(obj, args) {
return WIKI.db.Group.destroy({
where: {
id: args.id
},
limit: 1
})
},
removeUserFromGroup(obj, args) {
return WIKI.db.Group.findById(args.groupId).then(grp => {
if (!grp) {
throw new gql.GraphQLError('Invalid Group ID')
}
return WIKI.db.User.findById(args.userId).then(usr => {
if (!usr) {
throw new gql.GraphQLError('Invalid User ID')
}
return grp.removeUser(usr)
})
})
},
renameGroup(obj, args) {
return WIKI.db.Group.update({
name: args.name
}, {
where: { id: args.id }
})
}
},
Group: {
users(grp) {
return grp.getUsers()
}
}
}

View File

@@ -0,0 +1,53 @@
/* global WIKI */
const gql = require('graphql')
module.exports = {
Query: {
rights(obj, args, context, info) {
return WIKI.db.Right.findAll({ where: args })
}
},
Mutation: {
addRightToGroup(obj, args) {
return WIKI.db.Group.findById(args.groupId).then(grp => {
if (!grp) {
throw new gql.GraphQLError('Invalid Group ID')
}
return WIKI.db.Right.create({
path: args.path,
role: args.role,
exact: args.exact,
allow: args.allow,
group: grp
})
})
},
removeRightFromGroup(obj, args) {
return WIKI.db.Right.destroy({
where: {
id: args.rightId
},
limit: 1
})
},
modifyRight(obj, args) {
return WIKI.db.Right.update({
path: args.path,
role: args.role,
exact: args.exact,
allow: args.allow
}, {
where: {
id: args.id
}
})
}
},
Right: {
group(rt) {
return rt.getGroup()
}
}
}

View File

@@ -0,0 +1,24 @@
/* global WIKI */
const _ = require('lodash')
module.exports = {
Query: {
settings(obj, args, context, info) {
return WIKI.db.Setting.findAll({ where: args, raw: true }).then(entries => {
return _.map(entries, entry => {
entry.config = JSON.stringify(entry.config)
return entry
})
})
}
},
Mutation: {
setConfigEntry(obj, args) {
return WIKI.db.Setting.update({
value: args.value
}, { where: { key: args.key } })
}
}
}

View File

@@ -0,0 +1,63 @@
/* global WIKI */
const gql = require('graphql')
module.exports = {
Query: {
tags(obj, args, context, info) {
return WIKI.db.Tag.findAll({ where: args })
}
},
Mutation: {
assignTagToDocument(obj, args) {
return WIKI.db.Tag.findById(args.tagId).then(tag => {
if (!tag) {
throw new gql.GraphQLError('Invalid Tag ID')
}
return WIKI.db.Document.findById(args.documentId).then(doc => {
if (!doc) {
throw new gql.GraphQLError('Invalid Document ID')
}
return tag.addDocument(doc)
})
})
},
createTag(obj, args) {
return WIKI.db.Tag.create(args)
},
deleteTag(obj, args) {
return WIKI.db.Tag.destroy({
where: {
id: args.id
},
limit: 1
})
},
removeTagFromDocument(obj, args) {
return WIKI.db.Tag.findById(args.tagId).then(tag => {
if (!tag) {
throw new gql.GraphQLError('Invalid Tag ID')
}
return WIKI.db.Document.findById(args.documentId).then(doc => {
if (!doc) {
throw new gql.GraphQLError('Invalid Document ID')
}
return tag.removeDocument(doc)
})
})
},
renameTag(obj, args) {
return WIKI.db.Group.update({
key: args.key
}, {
where: { id: args.id }
})
}
},
Tag: {
documents(tag) {
return tag.getDocuments()
}
}
}

View File

@@ -0,0 +1,12 @@
/* global WIKI */
module.exports = {
Query: {
translations (obj, args, context, info) {
return WIKI.lang.getByNamespace(args.locale, args.namespace)
}
},
Mutation: {},
Translation: {}
}

View File

@@ -0,0 +1,61 @@
/* global WIKI */
module.exports = {
Query: {
users(obj, args, context, info) {
return WIKI.db.User.findAll({ where: args })
}
},
Mutation: {
createUser(obj, args) {
return WIKI.db.User.create(args)
},
deleteUser(obj, args) {
return WIKI.db.User.destroy({
where: {
id: args.id
},
limit: 1
})
},
login(obj, args, context) {
return WIKI.db.User.login(args, context).catch(err => {
return {
succeeded: false,
message: err.message
}
})
},
loginTFA(obj, args, context) {
return WIKI.db.User.loginTFA(args, context).catch(err => {
return {
succeeded: false,
message: err.message
}
})
},
modifyUser(obj, args) {
return WIKI.db.User.update({
email: args.email,
name: args.name,
provider: args.provider,
providerId: args.providerId,
role: args.role
}, {
where: { id: args.id }
})
},
resetUserPassword(obj, args) {
return false
},
setUserPassword(obj, args) {
return false
}
},
User: {
groups(usr) {
return usr.getGroups()
}
}
}

View File

@@ -0,0 +1,21 @@
const gql = require('graphql')
module.exports = {
Date: new gql.GraphQLScalarType({
name: 'Date',
description: 'ISO date-time string at UTC',
parseValue(value) {
return new Date(value)
},
serialize(value) {
return value.toISOString()
},
parseLiteral(ast) {
if (ast.kind !== gql.Kind.STRING) {
throw new TypeError('Date value must be an string!')
}
return new Date(ast.value)
}
})
}

View File

@@ -0,0 +1,23 @@
extend type Query {
authentication: AuthenticationQuery
}
extend type Mutation {
authentication: AuthenticationMutation
}
type AuthenticationQuery {
providers: [AuthenticationProvider]
}
type AuthenticationMutation
type AuthenticationProvider {
isEnabled: Boolean!
key: String!
props: [String]
title: String!
useForm: Boolean!
icon: String
config: String
}

View File

@@ -0,0 +1,349 @@
# ENUMS
enum UserRole {
guest
user
admin
}
enum FileType {
binary
image
}
enum RightRole {
read
write
manage
}
# INTERFACES
interface Base {
id: Int!
createdAt: Date
updatedAt: Date
}
# TYPES
type Comment implements Base {
id: Int!
createdAt: Date
updatedAt: Date
content: String
document: Document!
author: User!
}
type Document implements Base {
id: Int!
createdAt: Date
updatedAt: Date
path: String!
title: String!
subtitle: String
parentPath: String
parentTitle: String
isDirectory: Boolean!
isEntry: Boolean!
searchContent: String
comments: [Comment]
tags: [Tag]
}
type File implements Base {
id: Int!
createdAt: Date
updatedAt: Date
category: FileType!
mime: String!
extra: String
filename: String!
basename: String!
filesize: Int!
folder: Folder
}
type Folder implements Base {
id: Int!
createdAt: Date
updatedAt: Date
name: String!
files: [File]
}
type Group implements Base {
id: Int!
createdAt: Date
updatedAt: Date
name: String!
users: [User]
rights: [Right]
}
type Right implements Base {
id: Int!
createdAt: Date
updatedAt: Date
path: String!
role: RightRole!
exact: Boolean!
allow: Boolean!
group: Group!
}
type SearchResult {
path: String
title: String
tags: [String]
}
type Setting implements Base {
id: Int!
createdAt: Date
updatedAt: Date
key: String!
config: String!
}
# Tags are attached to one or more documents
type Tag implements Base {
id: Int!
createdAt: Date
updatedAt: Date
key: String!
documents: [Document]
}
type Translation {
key: String!
value: String!
}
# A User
type User implements Base {
id: Int!
createdAt: Date
updatedAt: Date
email: String!
provider: String!
providerId: String
name: String
role: UserRole!
groups: [Group]
}
type OperationResult {
succeeded: Boolean!
message: String
data: String
}
type LoginResult {
succeeded: Boolean!
message: String
tfaRequired: Boolean
tfaLoginToken: String
}
# Query (Read)
type Query {
comments(id: Int): [Comment]
documents(id: Int, path: String): [Document]
files(id: Int): [File]
folders(id: Int, name: String): [Folder]
groups(id: Int, name: String): [Group]
rights(id: Int): [Right]
search(q: String, tags: [String]): [SearchResult]
settings(key: String): [Setting]
tags(key: String): [Tag]
translations(locale: String!, namespace: String!): [Translation]
users(id: Int, email: String, provider: String, providerId: String, role: UserRole): [User]
}
# Mutations (Create, Update, Delete)
type Mutation {
addRightToGroup(
groupId: Int!
path: String!
role: RightRole!
exact: Boolean!
allow: Boolean!
): Right
assignTagToDocument(
tagId: Int!
documentId: Int!
): OperationResult
assignUserToGroup(
userId: Int!
groupId: Int!
): OperationResult
createComment(
userId: Int!
documentId: Int!
content: String!
): Comment
createDocument(
path: String!
title: String!
subtitle: String
): Document
createFolder(
name: String!
): Folder
createGroup(
name: String!
): Group
createTag(
name: String!
): Tag
createUser(
email: String!
name: String
passwordRaw: String
provider: String!
providerId: String
role: UserRole!
): User
deleteComment(
id: Int!
): OperationResult
deleteDocument(
id: Int!
): OperationResult
deleteFile(
id: Int!
): OperationResult
deleteFolder(
id: Int!
): OperationResult
deleteGroup(
id: Int!
): OperationResult
deleteTag(
id: Int!
): OperationResult
deleteUser(
id: Int!
): OperationResult
login(
username: String!
password: String!
provider: String!
): LoginResult
loginTFA(
loginToken: String!
securityCode: String!
): OperationResult
modifyComment(
id: Int!
content: String!
): Document
modifyDocument(
id: Int!
title: String
subtitle: String
): Document
modifyUser(
id: Int!
email: String
name: String
provider: String
providerId: String
role: UserRole
): User
modifyRight(
id: Int!
path: String
role: RightRole
exact: Boolean
allow: Boolean
): Right
moveDocument(
id: Int!
path: String!
): OperationResult
moveFile(
id: Int!
folderId: Int!
): OperationResult
renameFile(
id: Int!
name: String!
): OperationResult
renameFolder(
id: Int!
name: String!
): OperationResult
renameGroup(
id: Int!
name: String!
): OperationResult
renameTag(
id: Int!
key: String!
): OperationResult
removeTagFromDocument(
tagId: Int!
documentId: Int!
): OperationResult
removeRightFromGroup(
rightId: Int!
): OperationResult
removeUserFromGroup(
userId: Int!
groupId: Int!
): OperationResult
resetUserPassword(
id: Int!
): OperationResult
setConfigEntry(
key: String!
value: String!
): OperationResult
setUserPassword(
id: Int!
passwordRaw: String!
): OperationResult
uploadFile(
category: FileType!
filename: String!
): File
}

View File

@@ -0,0 +1,3 @@
# SCALARS
scalar Date