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
501f0a9a
Commit
501f0a9a
authored
Sep 30, 2017
by
NGPixel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: auth strategies over GraphQL + svg loading
parent
51f5c236
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
157 additions
and
27 deletions
+157
-27
auth-icon-azure.svg
assets/svg/auth-icon-azure.svg
+0
-0
auth-icon-local.svg
assets/svg/auth-icon-local.svg
+8
-0
app.js
client/js/app.js
+10
-1
login.vue
client/js/components/login.vue
+28
-8
graphql.js
client/js/constants/graphql.js
+22
-0
index.js
client/js/constants/index.js
+5
-0
localization.js
client/js/modules/localization.js
+7
-12
button.scss
client/scss/components/button.scss
+5
-1
_login.scss
client/scss/pages/_login.scss
+27
-3
microsoft.js
server/authentication/microsoft.js
+1
-1
graphql.js
server/modules/graphql.js
+2
-0
resolvers-authentication.js
server/schemas/resolvers-authentication.js
+40
-0
types.graphql
server/schemas/types.graphql
+2
-1
No files found.
assets/svg/auth-icon-azure.svg
View file @
501f0a9a
This diff is collapsed.
Click to expand it.
assets/svg/auth-icon-local.svg
0 → 100644
View file @
501f0a9a
<svg
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
x=
"0px"
y=
"0px"
width=
"64px"
height=
"64px"
viewBox=
"0 0 64 64"
enable-background=
"new 0 0 64 64"
xml:space=
"preserve"
>
<path
d=
"M32,19c13.089,0,27-3.154,27-9S45.089,1,32,1S5,4.154,5,10S18.911,19,32,19z"
/>
<path
d=
"M32,41c13.089,0,27-3.154,27-9V14.436c-1.481,1.493-3.963,2.968-8.022,4.174C45.864,20.128,38.946,21,32,21
s-13.864-0.872-18.978-2.391C8.963,17.403,6.481,15.929,5,14.436V32C5,37.846,18.911,41,32,41z"
/>
<path
d=
"M32,63c13.089,0,27-3.154,27-9V36.436c-1.481,1.493-3.963,2.968-8.022,4.174C45.864,42.128,38.946,43,32,43
s-13.864-0.872-18.978-2.391C8.963,39.403,6.481,37.929,5,36.436V54C5,59.846,18.911,63,32,63z"
/>
</svg>
client/js/app.js
View file @
501f0a9a
...
...
@@ -3,6 +3,8 @@
/* global siteConfig */
/* eslint-disable no-new */
import
CONSTANTS
from
'./constants'
import
Vue
from
'vue'
import
VueResource
from
'vue-resource'
import
VueClipboards
from
'vue-clipboards'
...
...
@@ -55,10 +57,17 @@ import editorComponent from './components/editor.component.js'
import
sourceViewComponent
from
'./pages/source-view.component.js'
// ====================================
// Initialize Global Vars
// ====================================
window
.
wiki
=
null
window
.
CONSTANTS
=
CONSTANTS
// ====================================
// Initialize Apollo Client (GraphQL)
// ====================================
window
.
apollo
=
new
ApolloClient
({
window
.
graphQL
=
new
ApolloClient
({
networkInterface
:
createBatchingNetworkInterface
({
uri
:
window
.
location
.
protocol
+
'//'
+
window
.
location
.
host
+
siteConfig
.
path
+
'/graphql'
}),
...
...
client/js/components/login.vue
View file @
501f0a9a
...
...
@@ -7,11 +7,8 @@
|
{{
error
.
title
}}
span
{{
error
.
message
}}
.login-providers(v-show='strategies.length > 1')
button.is-active(:title='$t("auth:providers.local")')
i.nc-icon-outline.ui-1_database
span
{{
$t
(
'auth:providers.local'
)
}}
button(v-for='strategy in strategies', @onclick='selectProvider(strategy.key, strategy.useForm)', :title='strategy.title')
//-!= strategy.icon
button(v-for='strategy in strategies', :class='{ "is-active": strategy.key === selectedStrategy }', @click='selectStrategy(strategy.key, strategy.useForm)', :title='strategy.title')
em(v-html='strategy.icon')
span
{{
strategy
.
title
}}
.login-frame
h1
{{
siteTitle
}}
...
...
@@ -32,7 +29,8 @@ export default {
data
()
{
return
{
error
:
false
,
strategies
:
[]
strategies
:
[],
selectedStrategy
:
'local'
}
},
computed
:
{
...
...
@@ -41,9 +39,31 @@ export default {
}
},
methods
:
{
selectProvider
(
key
,
useForm
)
{
selectStrategy
(
key
,
useForm
)
{
this
.
selectedStrategy
=
key
if
(
!
useForm
)
{
window
.
location
.
assign
(
siteConfig
.
path
+
'/login/'
+
key
)
}
},
refreshStrategies
()
{
graphQL
.
query
({
query
:
CONSTANTS
.
GRAPHQL
.
GQL_QUERY_AUTHENTICATION
,
variables
:
{
mode
:
'active'
}
}).
then
(
resp
=>
{
if
(
resp
.
data
.
authentication
)
{
this
.
strategies
=
resp
.
data
.
authentication
}
else
{
throw
new
Error
(
'No authentication providers available!'
)
}
}).
catch
(
err
=>
{
console
.
error
(
err
)
})
}
},
mounted
()
{
this
.
refreshStrategies
()
}
}
</
script
>
...
...
client/js/constants/graphql.js
0 → 100644
View file @
501f0a9a
import
gql
from
'graphql-tag'
export
default
{
GQL_QUERY_AUTHENTICATION
:
gql
`
query($mode: String!) {
authentication(mode:$mode) {
key
useForm
title
icon
}
}
`
,
GQL_QUERY_TRANSLATIONS
:
gql
`
query($locale: String!, $namespace: String!) {
translations(locale:$locale, namespace:$namespace) {
key
value
}
}
`
}
client/js/constants/index.js
0 → 100644
View file @
501f0a9a
import
GRAPHQL
from
'./graphql'
export
default
{
GRAPHQL
}
client/js/modules/localization.js
View file @
501f0a9a
import
i18next
from
'i18next'
import
i18nextXHR
from
'i18next-xhr-backend'
import
i18nextCache
from
'i18next-localstorage-cache'
import
gql
from
'graphql-tag'
import
VueI18Next
from
'@panter/vue-i18next'
import
loSet
from
'lodash/set'
/* global siteConfig */
/* global siteConfig
, graphQL, CONSTANTS
*/
module
.
exports
=
{
VueI18Next
,
...
...
@@ -19,16 +18,12 @@ module.exports = {
parse
:
(
data
)
=>
data
,
ajax
:
(
url
,
opts
,
cb
,
data
)
=>
{
let
langParams
=
url
.
split
(
'/'
)
console
.
info
(
langParams
)
window
.
apollo
.
query
({
query
:
gql
`
{
translations(locale:"
${
langParams
[
0
]}
", namespace:"
${
langParams
[
1
]}
") {
key
value
}
}
`
graphQL
.
query
({
query
:
CONSTANTS
.
GRAPHQL
.
GQL_QUERY_TRANSLATIONS
,
variables
:
{
locale
:
langParams
[
0
],
namespace
:
langParams
[
1
]
}
}).
then
(
resp
=>
{
let
ns
=
{}
if
(
resp
.
data
.
translations
.
length
>
0
)
{
...
...
client/scss/components/button.scss
View file @
501f0a9a
...
...
@@ -61,7 +61,11 @@
background-color
:
mc
(
$color
,
'800'
);
color
:
#FFF
;
animation
:
none
;
}
}
&
:focus
{
box-shadow
:
inset
0
0
0
3px
rgba
(
255
,
255
,
255
,
.4
);
}
}
}
...
...
client/scss/pages/_login.scss
View file @
501f0a9a
...
...
@@ -35,6 +35,7 @@
.login-frame
{
border-radius
:
0
6px
6px
0
;
border-left
:
none
;
}
}
...
...
@@ -104,6 +105,10 @@
align-items
:
center
;
transition
:
all
.4s
ease
;
&
:focus
{
outline
:
none
;
}
@include
until
(
$tablet
)
{
justify-content
:
center
;
}
...
...
@@ -114,12 +119,24 @@
&
:first-child
{
border-top
:
none
;
&
.is-active
{
border-top
:
1px
solid
rgba
(
255
,
255
,
255
,
.5
);
}
}
&
.is-active
{
background-color
:
mc
(
'grey'
,
'100'
);
background-image
:
radial-gradient
(
circle
at
top
left
,
rgba
(
mc
(
'grey'
,
'200'
)
,
1
)
0%
,
rgba
(
255
,
255
,
255
,
1
)
100%
);
background-image
:
linear-gradient
(
to
right
,
rgba
(
255
,
255
,
255
,
1
)
0%
,
rgba
(
255
,
255
,
255
,.
77
)
100%
);
color
:
mc
(
'light-blue'
,
'700'
);
cursor
:
default
;
&
:hover
{
background-color
:
transparent
;
}
svg
path
{
fill
:
mc
(
'light-blue'
,
'800'
);
}
}
i
{
...
...
@@ -160,7 +177,8 @@
}
&
-frame
{
background-image
:
radial-gradient
(
circle
at
top
left
,
rgba
(
255
,
255
,
255
,
1
)
5%
,
rgba
(
240
,
240
,
240
,.
6
)
100%
);
background-image
:
radial-gradient
(
circle
at
top
center
,
rgba
(
255
,
255
,
255
,
1
)
5%
,
rgba
(
255
,
255
,
255
,.
6
)
100%
);
border
:
1px
solid
rgba
(
255
,
255
,
255
,
.5
);
border-radius
:
6px
;
width
:
400px
;
padding
:
1rem
;
...
...
@@ -178,6 +196,7 @@
font-size
:
2rem
;
font-weight
:
600
;
color
:
mc
(
'light-blue'
,
'700'
);
text-shadow
:
1px
1px
0
#FFF
;
padding
:
0
;
margin
:
0
;
}
...
...
@@ -186,6 +205,7 @@
font-size
:
1
.5rem
;
font-weight
:
300
;
color
:
mc
(
'grey'
,
'700'
);
text-shadow
:
1px
1px
0
#FFF
;
padding
:
0
;
margin
:
0
0
25px
0
;
}
...
...
@@ -200,6 +220,7 @@
border
:
1px
solid
#FFF
;
border-radius
:
3px
;
background-color
:
rgba
(
255
,
255
,
255
,.
9
);
box-shadow
:
inset
0
0
0
3px
rgba
(
255
,
255
,
255
,
.25
);
padding
:
0
15px
;
height
:
40px
;
margin
:
0
0
10px
0
;
...
...
@@ -212,6 +233,9 @@
&
:focus
{
outline
:
none
;
border-color
:
mc
(
'light-blue'
,
'500'
);
background-color
:
rgba
(
255
,
255
,
255
,
1
);
box-shadow
:
inset
0
0
0
3px
rgba
(
mc
(
'light-blue'
,
'500'
)
,
.25
);
color
:
mc
(
'light-blue'
,
'800'
);
}
}
...
...
server/authentication/microsoft.js
View file @
501f0a9a
...
...
@@ -14,7 +14,7 @@ module.exports = {
useForm
:
false
,
props
:
[
'clientId'
,
'clientSecret'
,
'callbackURL'
],
init
(
passport
,
conf
)
{
passport
.
use
(
'
windowslive
'
,
passport
.
use
(
'
microsoft
'
,
new
WindowsLiveStrategy
({
clientID
:
conf
.
clientId
,
clientSecret
:
conf
.
clientSecret
,
...
...
server/modules/graphql.js
View file @
501f0a9a
...
...
@@ -10,6 +10,7 @@ const _ = require('lodash')
const
typeDefs
=
fs
.
readFileSync
(
path
.
join
(
wiki
.
SERVERPATH
,
'schemas/types.graphql'
),
'utf8'
)
const
DateScalar
=
require
(
'../schemas/scalar-date'
)
const
AuthenticationResolvers
=
require
(
'../schemas/resolvers-authentication'
)
const
CommentResolvers
=
require
(
'../schemas/resolvers-comment'
)
const
DocumentResolvers
=
require
(
'../schemas/resolvers-document'
)
const
FileResolvers
=
require
(
'../schemas/resolvers-file'
)
...
...
@@ -21,6 +22,7 @@ const TranslationResolvers = require('../schemas/resolvers-translation')
const
UserResolvers
=
require
(
'../schemas/resolvers-user'
)
const
resolvers
=
_
.
merge
(
AuthenticationResolvers
,
CommentResolvers
,
DocumentResolvers
,
FileResolvers
,
...
...
server/schemas/resolvers-authentication.js
0 → 100644
View file @
501f0a9a
const
_
=
require
(
'lodash'
)
const
fs
=
require
(
'fs-extra'
)
const
path
=
require
(
'path'
)
/* global wiki */
module
.
exports
=
{
Query
:
{
authentication
(
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
}
}
},
Mutation
:
{},
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
})
}
}
}
server/schemas/types.graphql
View file @
501f0a9a
...
...
@@ -32,10 +32,11 @@ interface Base {
# TYPES
type
AuthenticationProvider
{
id
:
String
!
key
:
String
!
useForm
:
Boolean
!
title
:
String
!
props
:
[
String
]
icon
:
String
config
:
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