Commit f5fb21aa authored by NGPixel's avatar NGPixel

feat: vue-apollo + auth providers resolver (wip)

parent 91b57552
...@@ -10,10 +10,9 @@ import VueClipboards from 'vue-clipboards' ...@@ -10,10 +10,9 @@ import VueClipboards from 'vue-clipboards'
import VueSimpleBreakpoints from 'vue-simple-breakpoints' import VueSimpleBreakpoints from 'vue-simple-breakpoints'
import VeeValidate from 'vee-validate' import VeeValidate from 'vee-validate'
import { ApolloClient } from 'apollo-client' import { ApolloClient } from 'apollo-client'
import { ApolloLink } from 'apollo-link'
import { createApolloFetch } from 'apollo-fetch'
import { BatchHttpLink } from 'apollo-link-batch-http' import { BatchHttpLink } from 'apollo-link-batch-http'
import { InMemoryCache } from 'apollo-cache-inmemory' import { InMemoryCache } from 'apollo-cache-inmemory'
import VueApollo from 'vue-apollo'
import Vuetify from 'vuetify' import Vuetify from 'vuetify'
import Velocity from 'velocity-animate' import Velocity from 'velocity-animate'
import Hammer from 'hammerjs' import Hammer from 'hammerjs'
...@@ -36,7 +35,7 @@ import helpers from './helpers' ...@@ -36,7 +35,7 @@ import helpers from './helpers'
// Initialize Global Vars // Initialize Global Vars
// ==================================== // ====================================
window.wiki = null window.WIKI = null
window.boot = boot window.boot = boot
window.CONSTANTS = CONSTANTS window.CONSTANTS = CONSTANTS
window.Hammer = Hammer window.Hammer = Hammer
...@@ -47,31 +46,11 @@ window.Hammer = Hammer ...@@ -47,31 +46,11 @@ window.Hammer = Hammer
const graphQLEndpoint = window.location.protocol + '//' + window.location.host + siteConfig.path + 'graphql' const graphQLEndpoint = window.location.protocol + '//' + window.location.host + siteConfig.path + 'graphql'
const apolloFetch = createApolloFetch({
uri: graphQLEndpoint,
constructOptions: (requestOrRequests, options) => ({
...options,
method: 'POST',
body: JSON.stringify(requestOrRequests),
credentials: 'include'
})
})
window.graphQL = new ApolloClient({ window.graphQL = new ApolloClient({
link: ApolloLink.from([ link: new BatchHttpLink({
new ApolloLink((operation, forward) => { uri: graphQLEndpoint,
operation.setContext({ credentials: 'include'
headers: { }),
'Content-Type': 'application/json'
}
})
return forward(operation)
}),
new BatchHttpLink({
fetch: apolloFetch
})
]),
cache: new InMemoryCache(), cache: new InMemoryCache(),
connectToDevTools: (process.env.node_env === 'development') connectToDevTools: (process.env.node_env === 'development')
}) })
...@@ -81,6 +60,7 @@ window.graphQL = new ApolloClient({ ...@@ -81,6 +60,7 @@ window.graphQL = new ApolloClient({
// ==================================== // ====================================
Vue.use(VueRouter) Vue.use(VueRouter)
Vue.use(VueApollo)
Vue.use(VueClipboards) Vue.use(VueClipboards)
Vue.use(VueSimpleBreakpoints) Vue.use(VueSimpleBreakpoints)
Vue.use(localization.VueI18Next) Vue.use(localization.VueI18Next)
...@@ -121,15 +101,20 @@ let bootstrap = () => { ...@@ -121,15 +101,20 @@ let bootstrap = () => {
store.dispatch('startLoading') store.dispatch('startLoading')
}) })
const apolloProvider = new VueApollo({
defaultClient: window.graphQL
})
// ==================================== // ====================================
// Bootstrap Vue // Bootstrap Vue
// ==================================== // ====================================
const i18n = localization.init() const i18n = localization.init()
window.wiki = new Vue({ window.WIKI = new Vue({
el: '#app', el: '#app',
components: {}, components: {},
mixins: [helpers], mixins: [helpers],
provide: apolloProvider.provide(),
store, store,
i18n i18n
}) })
......
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
.subheading.grey--text Manage keys to access the API .subheading.grey--text Manage keys to access the API
v-card v-card
v-card-title v-card-title
v-btn(color='green', dark)
v-icon(left) power_settings_new
| Enable API
v-btn(color='primary', dark) v-btn(color='primary', dark)
v-icon(left) add v-icon(left) add
| New API Key | New API Key
......
...@@ -6,24 +6,12 @@ ...@@ -6,24 +6,12 @@
.subheading.grey--text Configure the authentication settings of your wiki .subheading.grey--text Configure the authentication settings of your wiki
v-tabs(color='grey lighten-4', grow, slider-color='primary', show-arrows) v-tabs(color='grey lighten-4', grow, slider-color='primary', show-arrows)
v-tab(key='settings'): v-icon settings v-tab(key='settings'): v-icon settings
v-tab(key='db') Local v-tab(v-for='provider in providers', :key='provider.key') {{ provider.title }}
v-tab(key='algolia') Auth0
v-tab(key='elasticsearch') Azure AD
v-tab(key='solr') Discord
v-tab(key='solr') Dropbox
v-tab(key='solr') Facebook
v-tab(key='solr') GitHub
v-tab(key='solr') Google
v-tab(key='solr') LDAP
v-tab(key='solr') Microsoft
v-tab(key='solr') OAuth2 Generic
v-tab(key='solr') Slack
v-tab(key='solr') Twitch
v-tab-item(key='settings') v-tab-item(key='settings')
v-card.pa-3 v-card.pa-3
v-form v-form
v-checkbox(v-for='(engine, n) in engines', v-model='auths', :key='n', :label='engine.text', :value='engine.value', color='primary') v-checkbox(v-for='(provider, n) in providers', v-model='auths', :key='provider.key', :label='provider.title', :value='provider.key', color='primary')
v-divider v-divider
v-btn(color='primary') v-btn(color='primary')
v-icon(left) chevron_right v-icon(left) chevron_right
...@@ -34,18 +22,20 @@ ...@@ -34,18 +22,20 @@
</template> </template>
<script> <script>
/* global CONSTANTS */
export default { export default {
data() { data() {
return { return {
engines: [ providers: [],
{ text: 'Local', value: 'local' },
{ text: 'Auth0', value: 'auth0' },
{ text: 'Algolia', value: 'algolia' },
{ text: 'Elasticsearch', value: 'elasticsearch' },
{ text: 'Solr', value: 'solr' }
],
auths: ['local'] auths: ['local']
} }
},
apollo: {
providers: {
query: CONSTANTS.GRAPH.AUTHENTICATION.QUERY_PROVIDERS,
update: (data) => data.authentication.providers
}
} }
} }
</script> </script>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
v-toolbar-title v-toolbar-title
span.subheading Wiki.js span.subheading Wiki.js
v-spacer v-spacer
v-progress-circular.mr-3(indeterminate, color='blue') v-progress-circular.mr-3(indeterminate, color='blue', v-if='$apollo.loading')
v-btn(icon) v-btn(icon)
v-icon(color='grey') search v-icon(color='grey') search
v-btn(icon, @click.native='darkTheme = !darkTheme') v-btn(icon, @click.native='darkTheme = !darkTheme')
......
import gql from 'graphql-tag' import gql from 'graphql-tag'
export default { export default {
GQL_QUERY_AUTHENTICATION: gql` AUTHENTICATION: {
query($mode: String!) { QUERY_PROVIDERS: gql`
authentication(mode:$mode) { query {
key authentication {
useForm providers {
title isEnabled
icon key
props
title
useForm
icon
config {
key
value
}
}
}
} }
} `
`, },
GQL_QUERY_TRANSLATIONS: gql` GQL_QUERY_TRANSLATIONS: gql`
query($locale: String!, $namespace: String!) { query($locale: String!, $namespace: String!) {
translations(locale:$locale, namespace:$namespace) { translations(locale:$locale, namespace:$namespace) {
......
import GRAPHQL from './graphql' import GRAPH from './graphql'
export default { export default {
GRAPHQL GRAPH
} }
...@@ -135,7 +135,6 @@ ...@@ -135,7 +135,6 @@
"yargs": "11.0.0" "yargs": "11.0.0"
}, },
"devDependencies": { "devDependencies": {
"@glimpse/glimpse": "0.22.15",
"@panter/vue-i18next": "0.9.1", "@panter/vue-i18next": "0.9.1",
"apollo-client-preset": "1.0.8", "apollo-client-preset": "1.0.8",
"apollo-fetch": "0.7.0", "apollo-fetch": "0.7.0",
...@@ -198,6 +197,7 @@ ...@@ -198,6 +197,7 @@
"vee-validate": "2.0.5", "vee-validate": "2.0.5",
"velocity-animate": "1.5.1", "velocity-animate": "1.5.1",
"vue": "2.5.13", "vue": "2.5.13",
"vue-apollo": "3.0.0-beta.4",
"vue-clipboards": "1.2.2", "vue-clipboards": "1.2.2",
"vue-codemirror": "4.0.3", "vue-codemirror": "4.0.3",
"vue-hot-reload-api": "2.3.0", "vue-hot-reload-api": "2.3.0",
...@@ -211,7 +211,7 @@ ...@@ -211,7 +211,7 @@
"vuex-persistedstate": "2.4.2", "vuex-persistedstate": "2.4.2",
"webpack": "3.11.0", "webpack": "3.11.0",
"webpack-bundle-analyzer": "2.11.1", "webpack-bundle-analyzer": "2.11.1",
"webpack-dev-middleware": "3.0.0", "webpack-dev-middleware": "2.0.3",
"webpack-hot-middleware": "2.21.2", "webpack-hot-middleware": "2.21.2",
"webpack-merge": "4.1.2", "webpack-merge": "4.1.2",
"whatwg-fetch": "2.0.3", "whatwg-fetch": "2.0.3",
......
...@@ -31,7 +31,7 @@ defaults: ...@@ -31,7 +31,7 @@ defaults:
public: false public: false
strategies: strategies:
local: local:
enabled: true isEnabled: true
allowSelfRegister: false allowSelfRegister: false
git: git:
enabled: false enabled: false
......
...@@ -4,6 +4,7 @@ const _ = require('lodash') ...@@ -4,6 +4,7 @@ const _ = require('lodash')
const passport = require('passport') const passport = require('passport')
const fs = require('fs-extra') const fs = require('fs-extra')
const path = require('path') const path = require('path')
const autoload = require('auto-load')
module.exports = { module.exports = {
strategies: {}, strategies: {},
...@@ -31,26 +32,29 @@ module.exports = { ...@@ -31,26 +32,29 @@ module.exports = {
// Load authentication strategies // Load authentication strategies
_.forOwn(_.omitBy(WIKI.config.auth.strategies, s => s.enabled === false), (strategyConfig, strategyKey) => { const modules = _.values(autoload(path.join(WIKI.SERVERPATH, 'modules/authentication')))
strategyConfig.callbackURL = `${WIKI.config.site.host}${WIKI.config.site.path}login/${strategyKey}/callback` _.forEach(modules, (strategy) => {
let strategy = require(`../modules/authentication/${strategyKey}`) const strategyConfig = _.get(WIKI.config.auth.strategies, strategy.key, {})
try { strategyConfig.callbackURL = `${WIKI.config.site.host}${WIKI.config.site.path}login/${strategy.key}/callback`
strategy.init(passport, strategyConfig) if (strategyConfig.isEnabled) {
} catch (err) { try {
WIKI.logger.error(`Authentication Provider ${strategyKey}: [ FAILED ]`) strategy.init(passport, strategyConfig)
WIKI.logger.error(err) } catch (err) {
WIKI.logger.error(`Authentication Provider ${strategy.title}: [ FAILED ]`)
WIKI.logger.error(err)
}
} }
fs.readFile(path.join(WIKI.ROOTPATH, `assets/svg/auth-icon-${strategyKey}.svg`), 'utf8').then(iconData => { fs.readFile(path.join(WIKI.ROOTPATH, `assets/svg/auth-icon-${strategy.key}.svg`), 'utf8').then(iconData => {
strategy.icon = iconData strategy.icon = iconData
}).catch(err => { }).catch(err => {
if (err.code === 'ENOENT') { if (err.code === 'ENOENT') {
strategy.icon = '[missing icon]' strategy.icon = '[missing icon]'
} else { } else {
WIKI.logger.error(err) WIKI.logger.warn(err)
} }
}) })
this.strategies[strategy.key] = strategy this.strategies[strategy.key] = strategy
WIKI.logger.info(`Authentication Provider ${strategyKey}: [ OK ]`) WIKI.logger.info(`Authentication Provider ${strategy.title}: [ OK ]`)
}) })
// Create Guest account for first-time // Create Guest account for first-time
......
...@@ -13,28 +13,19 @@ module.exports = { ...@@ -13,28 +13,19 @@ module.exports = {
}, },
AuthenticationQuery: { AuthenticationQuery: {
providers(obj, args, context, info) { providers(obj, args, context, info) {
switch (args.mode) { return _.chain(WIKI.auth.strategies).map(str => {
case 'active': return {
let strategies = _.chain(WIKI.auth.strategies).map(str => { isEnabled: true,
return { key: str.key,
key: str.key, title: str.title,
title: str.title, useForm: str.useForm
useForm: str.useForm }
} }).sortBy(['title']).value()
}).sortBy(['title']).value()
let localStrategy = _.remove(strategies, str => str.key === 'local')
return _.concat(localStrategy, strategies)
case 'all':
break
default:
return null
}
} }
}, },
AuthenticationProvider: { AuthenticationProvider: {
icon (ap, args) { icon (ap, args) {
return fs.readFileAsync(path.join(WIKI.ROOTPATH, `assets/svg/auth-icon-${ap.key}.svg`), 'utf8').catch(err => { return fs.readFile(path.join(WIKI.ROOTPATH, `assets/svg/auth-icon-${ap.key}.svg`), 'utf8').catch(err => {
if (err.code === 'ENOENT') { if (err.code === 'ENOENT') {
return null return null
} }
......
...@@ -10,7 +10,13 @@ type AuthenticationQuery { ...@@ -10,7 +10,13 @@ type AuthenticationQuery {
providers: [AuthenticationProvider] providers: [AuthenticationProvider]
} }
type AuthenticationMutation type AuthenticationMutation {
updateProvider(
provider: String!
isEnabled: Boolean!
config: [KeyValuePairInput]
): DefaultResponse
}
type AuthenticationProvider { type AuthenticationProvider {
isEnabled: Boolean! isEnabled: Boolean!
...@@ -19,5 +25,5 @@ type AuthenticationProvider { ...@@ -19,5 +25,5 @@ type AuthenticationProvider {
title: String! title: String!
useForm: Boolean! useForm: Boolean!
icon: String icon: String
config: String config: [KeyValuePair]
} }
...@@ -29,6 +29,26 @@ interface Base { ...@@ -29,6 +29,26 @@ interface Base {
# TYPES # TYPES
type KeyValuePair {
key: String!
value: String!
}
input KeyValuePairInput {
key: String!
value: String!
}
type DefaultResponse {
operation: ResponseStatus
}
type ResponseStatus {
succeeded: Boolean!
code: Int!
slug: String!
message: String
}
type Comment implements Base { type Comment implements Base {
id: Int! id: Int!
createdAt: Date createdAt: Date
......
...@@ -17,10 +17,6 @@ let WIKI = { ...@@ -17,10 +17,6 @@ let WIKI = {
} }
global.WIKI = WIKI global.WIKI = WIKI
// if (WIKI.IS_DEBUG) {
// require('@glimpse/glimpse').init()
// }
WIKI.configSvc.init() WIKI.configSvc.init()
// ---------------------------------------- // ----------------------------------------
......
This diff was suppressed by a .gitattributes entry.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment