132 lines
3.7 KiB
JavaScript
132 lines
3.7 KiB
JavaScript
import { Observable } from 'rx';
|
|
// import debug from 'debug';
|
|
import dedent from 'dedent';
|
|
|
|
import {
|
|
getSocialProvider,
|
|
getUsernameFromProvider,
|
|
createUserUpdatesFromProfile
|
|
} from '../../server/utils/auth';
|
|
import { observeMethod, observeQuery } from '../../server/utils/rx';
|
|
import { wrapHandledError } from '../../server/utils/create-handled-error.js';
|
|
|
|
// const log = debug('fcc:models:userIdent');
|
|
|
|
export default function(UserIdent) {
|
|
UserIdent.on('dataSourceAttached', () => {
|
|
UserIdent.findOne$ = observeMethod(UserIdent, 'findOne');
|
|
});
|
|
// original source
|
|
// github.com/strongloop/loopback-component-passport
|
|
// find identity if it exist
|
|
// if not redirect to email signup
|
|
// if yes and github
|
|
// update profile
|
|
// update username
|
|
// update picture
|
|
UserIdent.login = function(
|
|
_provider,
|
|
authScheme,
|
|
profile,
|
|
credentials,
|
|
options,
|
|
cb
|
|
) {
|
|
const User = UserIdent.app.models.User;
|
|
const AccessToken = UserIdent.app.models.AccessToken;
|
|
const provider = getSocialProvider(_provider);
|
|
options = options || {};
|
|
if (typeof options === 'function' && !cb) {
|
|
cb = options;
|
|
options = {};
|
|
}
|
|
profile.id = profile.id || profile.openid;
|
|
const query = {
|
|
where: {
|
|
provider: provider,
|
|
externalId: profile.id
|
|
},
|
|
include: 'user'
|
|
};
|
|
return UserIdent.findOne$(query)
|
|
.flatMap(identity => {
|
|
if (!identity) {
|
|
throw wrapHandledError(
|
|
new Error('user identity account not found'),
|
|
{
|
|
message: dedent`
|
|
New accounts can only be created using an email address.
|
|
Please create an account below
|
|
`,
|
|
type: 'info',
|
|
redirectTo: '/signup'
|
|
}
|
|
);
|
|
}
|
|
const modified = new Date();
|
|
const user = identity.user();
|
|
if (!user) {
|
|
const username = getUsernameFromProvider(provider, profile);
|
|
return observeQuery(
|
|
identity,
|
|
'updateAttributes',
|
|
{
|
|
isOrphaned: username || true
|
|
}
|
|
)
|
|
.do(() => {
|
|
throw wrapHandledError(
|
|
new Error('user identity is not associated with a user'),
|
|
{
|
|
type: 'info',
|
|
redirectTo: '/signup',
|
|
message: dedent`
|
|
The user account associated with the ${provider} user ${username || 'Anon'}
|
|
no longer exists.
|
|
`
|
|
}
|
|
);
|
|
});
|
|
}
|
|
const updateUser = User.update$(
|
|
{ id: user.id },
|
|
createUserUpdatesFromProfile(provider, profile)
|
|
).map(() => user);
|
|
// identity already exists
|
|
// find user and log them in
|
|
identity.credentials = credentials;
|
|
const attributes = {
|
|
// we no longer want to keep the profile
|
|
// this is information we do not need or use
|
|
profile: null,
|
|
credentials: credentials,
|
|
modified
|
|
};
|
|
const updateIdentity = observeQuery(
|
|
identity,
|
|
'updateAttributes',
|
|
attributes
|
|
);
|
|
const createToken = observeQuery(
|
|
AccessToken,
|
|
'create',
|
|
{
|
|
userId: user.id,
|
|
created: new Date(),
|
|
ttl: user.constructor.settings.ttl
|
|
}
|
|
);
|
|
return Observable.combineLatest(
|
|
updateUser,
|
|
updateIdentity,
|
|
createToken,
|
|
(user, identity, token) => ({ user, identity, token })
|
|
);
|
|
})
|
|
.subscribe(
|
|
({ user, identity, token }) => cb(null, user, identity, token),
|
|
cb
|
|
);
|
|
};
|
|
}
|