Merge branch 'rte-plugin' of github.com:coralproject/talk into rte-plugin

* 'rte-plugin' of github.com:coralproject/talk:
  moved lock file
  updated plugin reconciler, replaced docker commands
  Rm accident added file
  Fix CI
  added advisory excemption
  replaced custom loading with yarn workspaces
  Implement profile settings
  Refactor Profile
  add Google auth plugin
This commit is contained in:
okbel
2018-02-23 12:30:45 -03:00
53 changed files with 778 additions and 629 deletions
+3 -2
View File
@@ -21,8 +21,10 @@ public
!plugins/talk-plugin-moderation-actions
!plugins/talk-plugin-offtopic
!plugins/talk-plugin-permalink
!plugins/talk-plugin-profile-settings
!plugins/talk-plugin-remember-sort
!plugins/talk-plugin-respect
!plugins/talk-plugin-rte
!plugins/talk-plugin-sort-most-liked
!plugins/talk-plugin-sort-most-loved
!plugins/talk-plugin-sort-most-replied
@@ -31,5 +33,4 @@ public
!plugins/talk-plugin-sort-oldest
!plugins/talk-plugin-subscriber
!plugins/talk-plugin-toxic-comments
!plugins/talk-plugin-viewing-options
!plugins/talk-plugin-rte
!plugins/talk-plugin-viewing-options
+2
View File
@@ -25,6 +25,7 @@ plugins.json
plugins/*
!plugins/talk-plugin-akismet
!plugins/talk-plugin-facebook-auth
!plugins/talk-plugin-google-auth
!plugins/talk-plugin-auth
!plugins/talk-plugin-respect
!plugins/talk-plugin-offtopic
@@ -53,6 +54,7 @@ plugins/*
!plugins/talk-plugin-flag-details
!plugins/talk-plugin-slack-notifications
!plugins/talk-plugin-rte
!plugins/talk-plugin-profile-settings
**/node_modules/*
yarn-error.log
+2 -1
View File
@@ -1,6 +1,7 @@
{
"exceptions": [
"https://nodesecurity.io/advisories/531",
"https://nodesecurity.io/advisories/532"
"https://nodesecurity.io/advisories/532",
"https://nodesecurity.io/advisories/566"
]
}
-1
View File
@@ -18,7 +18,6 @@ ENV NODE_ENV production
# Install app dependencies and build static assets.
RUN yarn global add node-gyp && \
yarn install --frozen-lockfile && \
cli plugins reconcile && \
yarn build && \
yarn cache clean
+29 -97
View File
@@ -135,18 +135,11 @@ function reconcilePackages({ quiet = false, upgradeRemote = false }) {
return { local, fetchable, upgradable };
}
async function reconcileRemotePlugins({ skipLocal, dryRun, upgradeRemote }) {
console.log(
`\n[${skipLocal ? '1/2' : '2/3'}] ${emoji.get(
'mag'
)} Reconciling plugins...`.yellow
);
async function reconcileRemotePlugins({ dryRun, upgradeRemote }) {
console.log(`\n['1/2'] ${emoji.get('mag')} Reconciling plugins...`.yellow);
const { fetchable, upgradable } = reconcilePackages({ upgradeRemote });
console.log(
`[${skipLocal ? '2/2' : '3/3'}] ${emoji.get('truck')} Fetching plugins...\n`
.yellow
);
console.log(`['2/2'] ${emoji.get('truck')} Fetching plugins...\n`.yellow);
if (fetchable.length > 0) {
console.log(
@@ -206,98 +199,41 @@ async function reconcileRemotePlugins({ skipLocal, dryRun, upgradeRemote }) {
return { upgradable, fetchable };
}
async function reconcileLocalPlugins({ skipRemote, dryRun }) {
console.log(
`\n[${skipRemote ? '1/1' : '1/3'}] ${emoji.get(
'pick'
)} Installing local plugin dependencies...\n`.yellow
);
const { local } = reconcilePackages({ quiet: true });
for (let i in local) {
let { name } = local[i];
if (!fs.existsSync(path.join(dir, 'plugins', name, 'package.json'))) {
continue;
}
let wd = path.join(dir, 'plugins', name);
console.log(`$ cd ${wd.cyan} && yarn`);
if (!dryRun) {
let args = [];
let output = spawn.sync('yarn', args, {
stdio: ['ignore', 'pipe', 'inherit'],
cwd: wd,
});
if (output.status) {
throw new Error(
'Could not install local plugin dependencies, errors occurred during install'
);
}
console.log(output.stdout.toString());
}
}
}
// This traverses the local plugins and installs any dependencies listed there,
// this only is really needed for plugins that are installed via docker because
// core plugins will have their dependencies already included in core.
async function reconcilePluginDeps({
skipLocal,
skipRemote,
dryRun,
upgradeRemote,
}) {
async function reconcilePluginDeps({ dryRun, upgradeRemote }) {
try {
let startTime = new Date();
// We don't need to do anything if we skip everything....
if (skipLocal && skipRemote) {
return;
}
// Traverse local plugins and install dependencies if enabled.
if (!skipLocal) {
await reconcileLocalPlugins({ skipRemote, dryRun });
}
// Locate any external plugins and install them.
if (!skipRemote) {
const results = await reconcileRemotePlugins({
skipLocal,
skipRemote,
dryRun,
upgradeRemote,
});
const results = await reconcileRemotePlugins({
dryRun,
upgradeRemote,
});
let status;
if (dryRun) {
status = '[dry-run] success'.green;
} else {
status = 'success'.green;
}
let message;
if (results.upgradable.length === 0 && results.fetchable.length === 0) {
message = 'Already up-to-date.';
} else if (results.upgradable.length === 0) {
message = `Fetched ${results.fetchable.length} new plugins.`;
} else if (results.fetchable.length === 0) {
message = `Upgraded ${results.upgradable.length} new plugins.`;
} else {
message = `Fetched ${results.fetchable.length} new plugins, upgraded ${
results.upgradable.length
} plugins.`;
}
console.log(`\n${status} ${message}`);
let status;
if (dryRun) {
status = '[dry-run] success'.green;
} else {
status = 'success'.green;
}
let message;
if (results.upgradable.length === 0 && results.fetchable.length === 0) {
message = 'Already up-to-date.';
} else if (results.upgradable.length === 0) {
message = `Fetched ${results.fetchable.length} new plugins.`;
} else if (results.fetchable.length === 0) {
message = `Upgraded ${results.upgradable.length} new plugins.`;
} else {
message = `Fetched ${results.fetchable.length} new plugins, upgraded ${
results.upgradable.length
} plugins.`;
}
console.log(`\n${status} ${message}`);
let endTime = new Date();
let totalTime = ((endTime.getTime() - startTime.getTime()) / 1000).toFixed(
@@ -440,16 +376,12 @@ program
program
.command('reconcile')
.description(
'reconciles local plugin dependencies and downloads external plugins'
)
.description('reconciles dependencies by downloading external plugins')
.option('-u, --upgrade-remote', 'upgrades remote dependencies')
.option(
'-d, --dry-run',
'does not actually change anything on the filesystem acts only as a simulation'
)
.option('--skip-local', 'skips the local dependancy reconciliation')
.option('--skip-remote', 'skips the remote plugin reconciliation')
.action(reconcilePluginDeps);
program.parse(process.argv);
@@ -0,0 +1,3 @@
import * as actions from '../constants/profile';
export const setActiveTab = tab => ({ type: actions.SET_ACTIVE_TAB, tab });
@@ -9,16 +9,12 @@ import AutomaticAssetClosure from '../containers/AutomaticAssetClosure';
import ExtendableTabPanel from '../containers/ExtendableTabPanel';
import { Tab, TabPane } from 'coral-ui';
import ProfileContainer from '../tabs/profile/containers/ProfileContainer';
import Profile from '../tabs/profile/containers/Profile';
import Popup from 'coral-framework/components/Popup';
import IfSlotIsNotEmpty from 'coral-framework/components/IfSlotIsNotEmpty';
import cn from 'classnames';
export default class Embed extends React.Component {
changeTab = tab => {
this.props.setActiveTab(tab);
};
getTabs() {
const tabs = [
<Tab
@@ -53,6 +49,7 @@ export default class Embed extends React.Component {
render() {
const {
activeTab,
setActiveTab,
commentId,
root,
root: { asset },
@@ -65,6 +62,7 @@ export default class Embed extends React.Component {
parentUrl,
} = this.props;
const hasHighlightedComment = !!commentId;
const popupUrl = `login?parentUrl=${encodeURIComponent(parentUrl)}`;
return (
<div
@@ -75,7 +73,7 @@ export default class Embed extends React.Component {
<AutomaticAssetClosure asset={asset} />
<IfSlotIsNotEmpty slot="login">
<Popup
href={`login?parentUrl=${encodeURIComponent(parentUrl)}`}
href={popupUrl}
title="Login"
features="menubar=0,resizable=0,width=500,height=550,top=200,left=500"
open={showSignInDialog}
@@ -91,7 +89,7 @@ export default class Embed extends React.Component {
<ExtendableTabPanel
className="talk-embed-stream-tab-bar"
activeTab={activeTab}
setActiveTab={this.changeTab}
setActiveTab={setActiveTab}
fallbackTab="stream"
tabSlot="embedStreamTabs"
tabSlotPrepend="embedStreamTabsPrepend"
@@ -112,7 +110,7 @@ export default class Embed extends React.Component {
tabId="profile"
className="talk-embed-stream-profile-tab-pane"
>
<ProfileContainer />
<Profile />
</TabPane>,
<TabPane
key="config"
@@ -0,0 +1,2 @@
const prefix = 'TALK_EMBED_STREAM';
export const SET_ACTIVE_TAB = `${prefix}_SET_ACTIVE_TAB`;
@@ -3,6 +3,7 @@ import asset from './asset';
import embed from './embed';
import configure from './configure';
import stream from './stream';
import profile from './profile';
export default {
login,
@@ -10,4 +11,5 @@ export default {
embed,
configure,
stream,
profile,
};
@@ -0,0 +1,19 @@
import * as actions from '../constants/profile';
const initialState = {
activeTab: 'comments',
previousTab: '',
};
export default function stream(state = initialState, action) {
switch (action.type) {
case actions.SET_ACTIVE_TAB:
return {
...state,
activeTab: action.tab,
previousTab: state.activeTab,
};
default:
return state;
}
}
@@ -11,8 +11,18 @@ import { getTotalReactionsCount } from 'coral-framework/utils';
import t from 'coral-framework/services/i18n';
class Comment extends React.Component {
goToStory = () => {
this.props.navigate(this.props.comment.asset.url);
};
goToConversation = () => {
this.props.navigate(
`${this.props.comment.asset.url}?commentId=${this.props.comment.id}`
);
};
render() {
const { comment, link, data, root } = this.props;
const { comment, data, root } = this.props;
const reactionCount = getTotalReactionsCount(comment.action_summaries);
const queryData = { root, comment, asset: comment.asset };
@@ -67,7 +77,7 @@ class Comment extends React.Component {
<a
className={cn(styles.assetURL, 'my-comment-anchor')}
href="#"
onClick={link(`${comment.asset.url}`)}
onClick={this.goToStory}
>
{t('common.story')}:{' '}
{comment.asset.title ? comment.asset.title : comment.asset.url}
@@ -77,10 +87,7 @@ class Comment extends React.Component {
<div className={styles.sidebar}>
<ul>
<li>
<a
onClick={link(`${comment.asset.url}?commentId=${comment.id}`)}
className={styles.viewLink}
>
<a onClick={this.goToConversation} className={styles.viewLink}>
<Icon name="open_in_new" className={styles.iconView} />
{t('view_conversation')}
</a>
@@ -105,10 +112,10 @@ class Comment extends React.Component {
}
Comment.propTypes = {
comment: PropTypes.shape({
id: PropTypes.string,
body: PropTypes.string,
}).isRequired,
comment: PropTypes.object.isRequired,
navigate: PropTypes.func.isRequired,
data: PropTypes.object.isRequired,
root: PropTypes.object.isRequired,
};
export default Comment;
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import Comment from './Comment';
import Comment from '../containers/Comment';
import LoadMore from './LoadMore';
class CommentHistory extends React.Component {
@@ -21,9 +21,9 @@ class CommentHistory extends React.Component {
};
render() {
const { link, comments, data, root } = this.props;
const { navigate, comments, data, root } = this.props;
return (
<div>
<div className="talk-my-profile-comment-history">
<div className="commentHistory__list">
{comments.nodes.map((comment, i) => {
return (
@@ -32,7 +32,7 @@ class CommentHistory extends React.Component {
data={data}
root={root}
comment={comment}
link={link}
navigate={navigate}
/>
);
})}
@@ -51,7 +51,7 @@ class CommentHistory extends React.Component {
CommentHistory.propTypes = {
comments: PropTypes.object.isRequired,
loadMore: PropTypes.func,
link: PropTypes.func,
navigate: PropTypes.func,
data: PropTypes.object,
root: PropTypes.object,
};
@@ -0,0 +1,11 @@
.userInfo {
margin-bottom: 20px;
}
.email {
margin: 0;
}
.username {
margin-bottom: 4px;
}
@@ -0,0 +1,57 @@
import React from 'react';
import PropTypes from 'prop-types';
import Slot from 'coral-framework/components/Slot';
import CommentHistory from '../containers/CommentHistory';
import ExtendableTabPanel from '../../../containers/ExtendableTabPanel';
import { Tab, TabPane } from 'coral-ui';
import styles from './Profile.css';
import t from 'coral-framework/services/i18n';
const Profile = ({
username,
emailAddress,
data,
root,
activeTab,
setActiveTab,
}) => (
<div className="talk-my-profile talk-profile-container">
<div className={styles.userInfo}>
<h2 className={styles.username}>{username}</h2>
{emailAddress ? <p className={styles.email}>{emailAddress}</p> : null}
</div>
<Slot fill="profileSections" data={data} queryData={{ root }} />
<ExtendableTabPanel
activeTab={activeTab}
setActiveTab={setActiveTab}
fallbackTab="comments"
tabSlot="profileTabs"
tabSlotPrepend="profileTabsPrepend"
tabPaneSlot="profileTabPanes"
slotProps={{ data }}
queryData={{ root }}
tabs={[
<Tab key="comments" tabId="comments">
{t('framework.my_comments')}
</Tab>,
]}
tabPanes={[
<TabPane key="comments" tabId="comments">
<CommentHistory data={data} root={root} />
</TabPane>,
]}
sub
/>
</div>
);
Profile.propTypes = {
username: PropTypes.string,
emailAddress: PropTypes.string,
data: PropTypes.object,
root: PropTypes.object,
activeTab: PropTypes.string.isRequired,
setActiveTab: PropTypes.func.isRequired,
};
export default Profile;
@@ -0,0 +1,32 @@
import { gql, compose } from 'react-apollo';
import Comment from '../components/Comment';
import { withFragments } from 'coral-framework/hocs';
import { getSlotFragmentSpreads } from 'coral-framework/utils';
const slots = ['commentContent', 'historyCommentTimestamp'];
const withCommentFragments = withFragments({
comment: gql`
fragment TalkEmbedStream_ProfileComment_comment on Comment {
id
body
replyCount
action_summaries {
count
__typename
}
asset {
id
title
url
${getSlotFragmentSpreads(slots, 'asset')}
}
created_at
${getSlotFragmentSpreads(slots, 'comment')}
}
`,
});
const enhance = compose(withCommentFragments);
export default enhance(Comment);
@@ -0,0 +1,103 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { compose, gql } from 'react-apollo';
import CommentHistory from '../components/CommentHistory';
import Comment from './Comment';
import { withFragments } from 'coral-framework/hocs';
import { appendNewNodes } from 'plugin-api/beta/client/utils';
import update from 'immutability-helper';
import { getDefinitionName } from 'coral-framework/utils';
class CommentHistoryContainer extends Component {
navigate = url => {
this.context.pym.sendMessage('navigate', url);
};
loadMore = () => {
return this.props.data.fetchMore({
query: LOAD_MORE_QUERY,
variables: {
limit: 5,
cursor: this.props.root.me.comments.endCursor,
},
updateQuery: (previous, { fetchMoreResult: { me: { comments } } }) => {
const updated = update(previous, {
me: {
comments: {
nodes: {
$apply: nodes => appendNewNodes(nodes, comments.nodes),
},
hasNextPage: { $set: comments.hasNextPage },
endCursor: { $set: comments.endCursor },
},
},
});
return updated;
},
});
};
render() {
return (
<CommentHistory
comments={this.props.root.me.comments}
data={this.props.data}
root={this.props.root}
loadMore={this.loadMore}
navigate={this.navigate}
/>
);
}
}
CommentHistoryContainer.contextTypes = {
pym: PropTypes.object,
};
CommentHistoryContainer.propTypes = {
data: PropTypes.object,
root: PropTypes.object,
};
const LOAD_MORE_QUERY = gql`
query TalkEmbedStream_CommentHistory_LoadMoreComments($limit: Int, $cursor: Cursor) {
me {
comments(query: { limit: $limit, cursor: $cursor }) {
nodes {
...${getDefinitionName(Comment.fragments.comment)}
}
endCursor
hasNextPage
}
}
}
${Comment.fragments.comment}
`;
const withCommentHistoryFragments = withFragments({
root: gql`
fragment TalkEmbedStream_CommentHistory on RootQuery {
me {
comments(query: {limit: 10}) {
nodes {
...${getDefinitionName(Comment.fragments.comment)}
}
endCursor
hasNextPage
}
}
}
${Comment.fragments.comment}
`,
});
const mapStateToProps = state => ({
currentUser: state.auth.user,
});
export default compose(
connect(mapStateToProps, null),
withCommentHistoryFragments
)(CommentHistoryContainer);
@@ -0,0 +1,104 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { compose, gql } from 'react-apollo';
import { bindActionCreators } from 'redux';
import { withQuery } from 'coral-framework/hocs';
import NotLoggedIn from '../components/NotLoggedIn';
import { Spinner } from 'coral-ui';
import Profile from '../components/Profile';
import CommentHistory from './CommentHistory';
import { getDefinitionName } from 'coral-framework/utils';
import { showSignInDialog } from 'coral-embed-stream/src/actions/login';
import { setActiveTab } from '../../../actions/profile';
import { getSlotFragmentSpreads } from 'coral-framework/utils';
class ProfileContainer extends Component {
componentWillReceiveProps(nextProps) {
if (!this.props.currentUser && nextProps.currentUser) {
// Refetch after login.
this.props.data.refetch();
}
}
render() {
const { currentUser, showSignInDialog, root, data } = this.props;
const { me } = this.props.root;
const loading = this.props.data.loading;
if (this.props.data.error) {
return <div>{this.props.data.error.message}</div>;
}
if (!currentUser) {
return <NotLoggedIn showSignInDialog={showSignInDialog} />;
}
if (loading || !me) {
return <Spinner />;
}
const localProfile = currentUser.profiles.find(p => p.provider === 'local');
const emailAddress = localProfile && localProfile.id;
return (
<Profile
username={me.username}
emailAddress={emailAddress}
data={data}
root={root}
activeTab={this.props.activeTab}
setActiveTab={this.props.setActiveTab}
/>
);
}
}
ProfileContainer.propTypes = {
data: PropTypes.object,
root: PropTypes.object,
currentUser: PropTypes.object,
showSignInDialog: PropTypes.func,
activeTab: PropTypes.string.isRequired,
setActiveTab: PropTypes.func.isRequired,
};
const slots = [
'profileSections',
'profileTabs',
'profileTabsPrepend',
'profileTabPanes',
];
const withProfileQuery = withQuery(
gql`
query CoralEmbedStream_Profile {
me {
id
username
}
...${getDefinitionName(CommentHistory.fragments.root)}
${getSlotFragmentSpreads(slots, 'root')}
}
${CommentHistory.fragments.root}
`,
{
options: {
fetchPolicy: 'network-only',
},
}
);
const mapStateToProps = state => ({
currentUser: state.auth.user,
activeTab: state.profile.activeTab,
});
const mapDispatchToProps = dispatch =>
bindActionCreators({ showSignInDialog, setActiveTab }, dispatch);
export default compose(
connect(mapStateToProps, mapDispatchToProps),
withProfileQuery
)(ProfileContainer);
@@ -1,178 +0,0 @@
import { connect } from 'react-redux';
import { compose, gql } from 'react-apollo';
import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { withQuery } from 'coral-framework/hocs';
import Slot from 'coral-framework/components/Slot';
import cn from 'classnames';
import { link } from 'coral-framework/services/pym';
import NotLoggedIn from '../components/NotLoggedIn';
import { Spinner } from 'coral-ui';
import CommentHistory from '../components/CommentHistory';
import { showSignInDialog } from 'coral-embed-stream/src/actions/login';
import { appendNewNodes } from 'plugin-api/beta/client/utils';
import update from 'immutability-helper';
import { getSlotFragmentSpreads } from 'coral-framework/utils';
import t from 'coral-framework/services/i18n';
class ProfileContainer extends Component {
componentWillReceiveProps(nextProps) {
if (!this.props.currentUser && nextProps.currentUser) {
// Refetch after login.
this.props.data.refetch();
}
}
loadMore = () => {
return this.props.data.fetchMore({
query: LOAD_MORE_QUERY,
variables: {
limit: 5,
cursor: this.props.root.me.comments.endCursor,
},
updateQuery: (previous, { fetchMoreResult: { me: { comments } } }) => {
const updated = update(previous, {
me: {
comments: {
nodes: {
$apply: nodes => appendNewNodes(nodes, comments.nodes),
},
hasNextPage: { $set: comments.hasNextPage },
endCursor: { $set: comments.endCursor },
},
},
});
return updated;
},
});
};
render() {
const { currentUser, showSignInDialog, root, data } = this.props;
const { me } = this.props.root;
const loading = this.props.data.loading;
if (this.props.data.error) {
return <div>{this.props.data.error.message}</div>;
}
if (!currentUser) {
return <NotLoggedIn showSignInDialog={showSignInDialog} />;
}
if (loading || !me) {
return <Spinner />;
}
const localProfile = currentUser.profiles.find(p => p.provider === 'local');
const emailAddress = localProfile && localProfile.id;
return (
<div className="talk-my-profile talk-embed-stream-profile-container">
<h2>{me.username}</h2>
{emailAddress ? <p>{emailAddress}</p> : null}
<Slot fill="profileSections" data={data} queryData={{ root }} />
<hr />
<h3>{t('framework.my_comments')}</h3>
<div
className={cn('talk-my-profile-comment-history', {
'talk-my-profile-comment-history-no-comments': !me.comments.nodes
.length,
})}
>
{me.comments.nodes.length ? (
<CommentHistory
data={data}
root={root}
comments={me.comments}
link={link}
loadMore={this.loadMore}
/>
) : (
<p className="talk-my-profile-comment-history-no-comments-cta">
{t('user_no_comment')}
</p>
)}
</div>
</div>
);
}
}
const slots = [
'profileSections',
// TODO: These Slots should be included in `talk-plugin-history` instead.
'commentContent',
'historyCommentTimestamp',
];
const CommentFragment = gql`
fragment TalkSettings_CommentConnectionFragment on CommentConnection {
nodes {
id
body
replyCount
action_summaries {
count
__typename
}
asset {
id
title
url
${getSlotFragmentSpreads(slots, 'asset')}
}
created_at
${getSlotFragmentSpreads(slots, 'comment')}
}
endCursor
hasNextPage
}
`;
const LOAD_MORE_QUERY = gql`
query TalkSettings_LoadMoreComments($limit: Int, $cursor: Cursor) {
me {
comments(query: { limit: $limit, cursor: $cursor }) {
...TalkSettings_CommentConnectionFragment
}
}
}
${CommentFragment}
`;
const withProfileQuery = withQuery(
gql`
query CoralEmbedStream_Profile {
me {
id
username
comments(query: {limit: 10}) {
...TalkSettings_CommentConnectionFragment
}
}
${getSlotFragmentSpreads(slots, 'root')}
}
${CommentFragment}
`,
{
options: {
fetchPolicy: 'network-only',
},
}
);
const mapStateToProps = state => ({
currentUser: state.auth.user,
});
const mapDispatchToProps = dispatch =>
bindActionCreators({ showSignInDialog }, dispatch);
export default compose(
connect(mapStateToProps, mapDispatchToProps),
withProfileQuery
)(ProfileContainer);
+1 -5
View File
@@ -1,9 +1,5 @@
import Pym from 'pym.js';
const pym = new Pym.Child({ polling: 100 });
export default pym;
export const link = url => e => {
e.preventDefault();
pym.sendMessage('navigate', url);
};
export default pym;
+25 -1
View File
@@ -77,6 +77,30 @@ or by visiting the
guide. This is only required while the `talk-plugin-facebook-auth` plugin is
enabled.
## TALK_GOOGLE_CLIENT_ID
The Google OAuth2 client ID for your Google login web app. You can learn more
about getting a Google Client ID at the
[Google API Console](https://console.developers.google.com/apis/){:target="_blank"}.
You will need to enable the Google+ API in the dashboard and create credentials
for a new OAuth client ID web application. The authorized JavaScript origin
should be set to the Talk domain, and the authorized redirect URI should be set
to http://<example.com>/api/v1/auth/google/callback. This is only required while
the `talk-plugin-google-auth` plugin is enabled.
## TALK_GOOGLE_CLIENT_SECRET
The Google OAuth2 client ID for your Google login web app. You can learn more
about getting a Google Client ID at the
[Google API Console](https://console.developers.google.com/apis/){:target="_blank"}.
You will need to enable the Google+ API in the dashboard and create credentials
for a new OAuth client ID web application. The authorized JavaScript origin
should be set to the Talk domain, and the authorized redirect URI should be set
to http://<example.com>/api/v1/auth/google/callback. This is only required while
the `talk-plugin-google-auth` plugin is enabled.
## TALK_HELMET_CONFIGURATION
A JSON string representing the configuration passed to the
@@ -538,4 +562,4 @@ This is a **Build Variable** and must be consumed during build. If using the
[Docker-onbuild]({{ "/installation-from-docker/#onbuild" | relative_url }})
image you can specify it with `--build-arg TALK_REPLY_COMMENTS_LOAD_DEPTH=3`.
Specifies the initial replies to load for a comment. (Default `3`)
Specifies the initial replies to load for a comment. (Default `3`)
+3 -1
View File
@@ -5,7 +5,6 @@
"main": "app.js",
"private": true,
"scripts": {
"postinstall": "./bin/cli plugins reconcile --skip-remote",
"generate-introspection": "WEBPACK=TRUE NODE_ENV=test ./scripts/generateIntrospectionResult.js",
"clean": "rm -rf dist client/coral-framework/graphql/introspection.json",
"watch": "npm-run-all clean generate-introspection --parallel watch:*",
@@ -32,6 +31,9 @@
"minVersion": 1516920160
}
},
"workspaces": [
"plugins/*"
],
"repository": {
"type": "git",
"url": "git+https://github.com/coralproject/talk.git"
+2 -1
View File
@@ -21,6 +21,7 @@
"talk-plugin-sort-most-respected",
"talk-plugin-sort-newest",
"talk-plugin-sort-oldest",
"talk-plugin-viewing-options"
"talk-plugin-viewing-options",
"talk-plugin-profile-settings"
]
}
-141
View File
@@ -1,141 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
akismet-api@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/akismet-api/-/akismet-api-4.0.1.tgz#1c771442f09316847132aa16171bb4fb708b6519"
dependencies:
bluebird "^3.1.1"
superagent "^3.8.0"
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
bluebird@^3.1.1:
version "3.5.1"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9"
combined-stream@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
dependencies:
delayed-stream "~1.0.0"
component-emitter@^1.2.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
cookiejar@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.1.tgz#41ad57b1b555951ec171412a81942b1e8200d34a"
core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
debug@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
dependencies:
ms "2.0.0"
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
extend@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
form-data@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.1.tgz#6fb94fbd71885306d73d15cc497fe4cc4ecd44bf"
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.5"
mime-types "^2.1.12"
formidable@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.1.1.tgz#96b8886f7c3c3508b932d6bd70c4d3a88f35f1a9"
inherits@~2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
methods@^1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
mime-db@~1.30.0:
version "1.30.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01"
mime-types@^2.1.12:
version "2.1.17"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a"
dependencies:
mime-db "~1.30.0"
mime@^1.4.1:
version "1.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
process-nextick-args@~1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
qs@^6.5.1:
version "6.5.1"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
readable-stream@^2.0.5:
version "2.3.3"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c"
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.3"
isarray "~1.0.0"
process-nextick-args "~1.0.6"
safe-buffer "~5.1.1"
string_decoder "~1.0.3"
util-deprecate "~1.0.1"
safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
string_decoder@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab"
dependencies:
safe-buffer "~5.1.0"
superagent@^3.8.0:
version "3.8.2"
resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.2.tgz#e4a11b9d047f7d3efeb3bbe536d9ec0021d16403"
dependencies:
component-emitter "^1.2.0"
cookiejar "^2.1.0"
debug "^3.1.0"
extend "^3.0.0"
form-data "^2.3.1"
formidable "^1.1.1"
methods "^1.1.1"
mime "^1.4.1"
qs "^6.5.1"
readable-stream "^2.0.5"
util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
@@ -1,112 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
asap@~2.0.3:
version "2.0.5"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
core-js@^1.0.0:
version "1.2.7"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
encoding@^0.1.11:
version "0.1.12"
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
dependencies:
iconv-lite "~0.4.13"
fbjs@^0.8.9:
version "0.8.12"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
dependencies:
core-js "^1.0.0"
isomorphic-fetch "^2.1.1"
loose-envify "^1.0.0"
object-assign "^4.1.0"
promise "^7.1.1"
setimmediate "^1.0.5"
ua-parser-js "^0.7.9"
iconv-lite@~0.4.13:
version "0.4.18"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.18.tgz#23d8656b16aae6742ac29732ea8f0336a4789cf2"
is-stream@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
isomorphic-fetch@^2.1.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
dependencies:
node-fetch "^1.0.1"
whatwg-fetch ">=0.10.0"
js-tokens@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7"
linkify-it@^1.2.0:
version "1.2.4"
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-1.2.4.tgz#0773526c317c8fd13bd534ee1d180ff88abf881a"
dependencies:
uc.micro "^1.0.1"
loose-envify@^1.0.0, loose-envify@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
dependencies:
js-tokens "^3.0.0"
node-fetch@^1.0.1:
version "1.7.1"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.1.tgz#899cb3d0a3c92f952c47f1b876f4c8aeabd400d5"
dependencies:
encoding "^0.1.11"
is-stream "^1.0.1"
object-assign@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
promise@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf"
dependencies:
asap "~2.0.3"
prop-types@^15.5.8:
version "15.5.10"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154"
dependencies:
fbjs "^0.8.9"
loose-envify "^1.3.1"
react-linkify@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/react-linkify/-/react-linkify-0.2.1.tgz#b28d3f9544539a622fec8d42b4800eb9d23bf981"
dependencies:
linkify-it "^1.2.0"
prop-types "^15.5.8"
tlds "^1.57.0"
setimmediate@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
tlds@^1.57.0:
version "1.189.0"
resolved "https://registry.yarnpkg.com/tlds/-/tlds-1.189.0.tgz#b8cb46ea76dc2f4a01d45b8d907bf19a66e9f729"
ua-parser-js@^0.7.9:
version "0.7.12"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"
uc.micro@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192"
whatwg-fetch@>=0.10.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
@@ -1,34 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
oauth@0.9.x:
version "0.9.15"
resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1"
passport-facebook@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/passport-facebook/-/passport-facebook-2.1.1.tgz#c39d0b52ae4d59163245a4e21a7b9b6321303311"
dependencies:
passport-oauth2 "1.x.x"
passport-oauth2@1.x.x:
version "1.4.0"
resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.4.0.tgz#f62f81583cbe12609be7ce6f160b9395a27b86ad"
dependencies:
oauth "0.9.x"
passport-strategy "1.x.x"
uid2 "0.0.x"
utils-merge "1.x.x"
passport-strategy@1.x.x:
version "1.0.0"
resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4"
uid2@0.0.x:
version "0.0.3"
resolved "https://registry.yarnpkg.com/uid2/-/uid2-0.0.3.tgz#483126e11774df2f71b8b639dcd799c376162b82"
utils-merge@1.x.x:
version "1.0.0"
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8"
@@ -1,4 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
@@ -0,0 +1,3 @@
{
"extends": "@coralproject/eslint-config-talk"
}
@@ -0,0 +1,3 @@
{
"extends": "@coralproject/eslint-config-talk/client"
}
@@ -0,0 +1,7 @@
export const loginWithGoogle = () => (dispatch, _, { rest }) => {
window.open(
`${rest.uri}/auth/google`,
'Continue with Google',
'menubar=0,resizable=0,width=500,height=500,top=200,left=500'
);
};
@@ -0,0 +1,13 @@
.button {
background-color: #db3236;
border-color: #db3236;
color: rgb(255, 255, 255);
width: 100%;
box-sizing: border-box;
padding: 10px 20px;
}
.button:hover {
background-color: #c71e22;
border-color: #c71e22;
}
@@ -0,0 +1,11 @@
import React from 'react';
import { BareButton } from 'plugin-api/beta/client/components/ui';
import styles from './GoogleButton.css';
export default ({ onClick, children }) => {
return (
<BareButton className={styles.button} onClick={onClick}>
{children}
</BareButton>
);
};
@@ -0,0 +1,9 @@
import React from 'react';
import GoogleButton from '../containers/GoogleButton';
import { t } from 'plugin-api/beta/client/services';
export default () => {
return (
<GoogleButton>{t('talk-plugin-google-auth.sign_in')}</GoogleButton>
);
};
@@ -0,0 +1,9 @@
import React from 'react';
import GoogleButton from '../containers/GoogleButton';
import { t } from 'plugin-api/beta/client/services';
export default () => {
return (
<GoogleButton>{t('talk-plugin-google-auth.sign_up')}</GoogleButton>
);
};
@@ -0,0 +1,9 @@
import { connect } from 'plugin-api/beta/client/hocs';
import { bindActionCreators } from 'redux';
import { loginWithGoogle } from '../actions';
import GoogleButton from '../components/GoogleButton';
const mapDispatchToProps = dispatch =>
bindActionCreators({ onClick: loginWithGoogle }, dispatch);
export default connect(null, mapDispatchToProps)(GoogleButton);
@@ -0,0 +1,11 @@
import SignIn from './components/SignIn';
import SignUp from './components/SignUp';
import translations from './translations.yml';
export default {
translations,
slots: {
authExternalSignIn: [SignIn],
authExternalSignUp: [SignUp],
},
};
@@ -0,0 +1,20 @@
en:
talk-plugin-google-auth:
sign_in: "Sign in with Google"
sign_up: "Sign up with Google"
es:
talk-plugin-google-auth:
google_sign_in: "Entrar con Google"
google_sign_up: "Registrarse con Google"
fr:
talk-plugin-google-auth:
google_sign_in: "Connectez-vous avec Google"
google_sign_up: "Inscrivez-vous avec Google"
zh_CN:
talk-plugin-google-auth:
google_sign_in: "使用 Google 帐号"
google_sign_up: "使用 Google 帐号"
zh_TW:
talk-plugin-google-auth:
google_sign_in: "使用 Google 帳號"
google_sign_up: "使用 Google 帳號"
+7
View File
@@ -0,0 +1,7 @@
const passport = require('./server/passport');
const router = require('./server/router');
module.exports = {
passport,
router,
};
@@ -0,0 +1,9 @@
{
"name": "talk-plugin-google-auth",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"passport-google-oauth2": "^0.1.6"
}
}
@@ -0,0 +1,41 @@
const GoogleStrategy = require('passport-google-oauth2').Strategy;
const UsersService = require('services/users');
const { ValidateUserLogin } = require('services/passport');
let { ROOT_URL } = require('config');
if (ROOT_URL[ROOT_URL.length - 1] !== '/') {
ROOT_URL += '/';
}
module.exports = passport => {
if (
process.env.TALK_GOOGLE_CLIENT_ID &&
process.env.TALK_GOOGLE_CLIENT_SECRET &&
process.env.TALK_ROOT_URL
) {
passport.use(
new GoogleStrategy(
{
clientID: process.env.TALK_GOOGLE_CLIENT_ID,
clientSecret: process.env.TALK_GOOGLE_CLIENT_SECRET,
callbackURL: `${ROOT_URL}api/v1/auth/google/callback`,
passReqToCallback: true,
},
async (req, accessToken, refreshToken, profile, done) => {
let user;
try {
user = await UsersService.findOrCreateExternalUser(profile);
} catch (err) {
return done(err.toString());
}
return ValidateUserLogin(profile, user, done);
}
)
);
} else if (process.env.NODE_ENV !== 'test') {
throw new Error(
'Google cannot be enabled, missing one of TALK_GOOGLE_CLIENT_ID, TALK_GOOGLE_CLIENT_SECRET, TALK_ROOT_URL'
);
}
};
@@ -0,0 +1,29 @@
module.exports = router => {
const { passport, HandleAuthPopupCallback } = require('services/passport');
/**
* Google auth endpoint, this will redirect the user immediatly to google
* for authorization.
*/
router.get(
'/api/v1/auth/google',
passport.authenticate('google', {
display: 'popup',
authType: 'rerequest',
scope: ['profile'],
})
);
/**
* Google callback endpoint, this will send the user a html page designed to
* send back the user credentials upon sucesfull login.
*/
router.get('/api/v1/auth/google/callback', (req, res, next) => {
// Perform the google login flow and pass the data back through the opener.
passport.authenticate(
'google',
{ session: false },
HandleAuthPopupCallback(req, res, next)
)(req, res, next);
});
};
@@ -8,7 +8,7 @@ export default {
slots: {
authorMenuActions: [IgnoreUserAction],
ignoreUserConfirmation: [IgnoreUserConfirmation],
profileSections: [IgnoredUserSection],
profileSettings: [IgnoredUserSection],
},
translations,
mutations: {
-4
View File
@@ -1,4 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
@@ -0,0 +1,3 @@
{
"extends": "@coralproject/eslint-config-talk"
}
@@ -0,0 +1,3 @@
{
"extends": "@coralproject/eslint-config-talk/client"
}
@@ -0,0 +1,8 @@
import React from 'react';
import { t } from 'plugin-api/beta/client/services';
const Tab = () => {
return <span>{t('talk-plugin-profile-settings.tab')}</span>;
};
export default Tab;
@@ -0,0 +1,21 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Slot } from 'plugin-api/beta/client/components';
class TabPane extends React.Component {
render() {
const { data, root } = this.props;
return (
<div>
<Slot fill="profileSettings" data={data} queryData={{ root }} />
</div>
);
}
}
TabPane.propTypes = {
data: PropTypes.object,
root: PropTypes.object,
};
export default TabPane;
@@ -0,0 +1,26 @@
import React from 'react';
import { compose, gql } from 'react-apollo';
import TabPane from '../components/TabPane';
import { withFragments } from 'plugin-api/beta/client/hocs';
import { getSlotFragmentSpreads } from 'plugin-api/beta/client/utils';
const slots = ['profileSettings'];
class TabPaneContainer extends React.Component {
render() {
return <TabPane {...this.props} />;
}
}
const enhance = compose(
withFragments({
root: gql`
fragment TalkProfileSettings_TabPane_root on RootQuery {
__typename
${getSlotFragmentSpreads(slots, 'root')}
}
`,
})
);
export default enhance(TabPaneContainer);
@@ -0,0 +1,11 @@
import Tab from './components/Tab';
import TabPane from './containers/TabPane';
import translations from './translations.yml';
export default {
slots: {
profileTabs: [Tab],
profileTabPanes: [TabPane],
},
translations,
};
@@ -0,0 +1,27 @@
en:
talk-plugin-profile-settings:
tab: Settings
de:
talk-plugin-profile-settings:
tab: Einstellungen
es:
talk-plugin-profile-settings:
tab: Configuración
fr:
talk-plugin-profile-settings:
tab: Paramètres
nl_NL:
talk-plugin-profile-settings:
tab: Instellingen
da:
talk-plugin-profile-settings:
tab: Indstillinger
pt_PR:
talk-plugin-profile-settings:
tab: Configurações
zh_TW:
talk-plugin-profile-settings:
tab: 設置
zh_CN:
talk-plugin-profile-settings:
tab: 设置
@@ -0,0 +1 @@
module.exports = {};
-11
View File
@@ -1,11 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
moment@^2.18.1:
version "2.18.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f"
momentjs@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/momentjs/-/momentjs-2.0.0.tgz#73df904b4fa418f6e3c605e831cef6ed5518ebd4"
@@ -1,7 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
ms@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+68 -5
View File
@@ -210,6 +210,13 @@ ajv@^5.1.0, ajv@^5.1.5, ajv@^5.2.3, ajv@^5.3.0:
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.3.0"
akismet-api@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/akismet-api/-/akismet-api-4.0.1.tgz#1c771442f09316847132aa16171bb4fb708b6519"
dependencies:
bluebird "^3.1.1"
superagent "^3.8.0"
align-text@^0.1.1, align-text@^0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
@@ -1247,7 +1254,7 @@ bluebird@3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c"
bluebird@^3.0.6, bluebird@^3.3.4, bluebird@^3.4.6, bluebird@^3.5.0:
bluebird@^3.0.6, bluebird@^3.1.1, bluebird@^3.3.4, bluebird@^3.4.6, bluebird@^3.5.0:
version "3.5.1"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9"
@@ -2049,6 +2056,10 @@ cookiejar@2.0.x, cookiejar@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.0.6.tgz#0abf356ad00d1c5a219d88d44518046dd026acfe"
cookiejar@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.1.tgz#41ad57b1b555951ec171412a81942b1e8200d34a"
copy-concurrently@^1.0.0:
version "1.0.5"
resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0"
@@ -3421,7 +3432,7 @@ formatio@1.2.0, formatio@^1.2.0:
dependencies:
samsam "1.x"
formidable@^1.0.17:
formidable@^1.0.17, formidable@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.1.1.tgz#96b8886f7c3c3508b932d6bd70c4d3a88f35f1a9"
@@ -6471,6 +6482,10 @@ oauth-sign@~0.8.1, oauth-sign@~0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
oauth@0.9.x:
version "0.9.15"
resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1"
object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
@@ -6742,6 +6757,18 @@ parseurl@~1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3"
passport-facebook@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/passport-facebook/-/passport-facebook-2.1.1.tgz#c39d0b52ae4d59163245a4e21a7b9b6321303311"
dependencies:
passport-oauth2 "1.x.x"
passport-google-oauth2@^0.1.6:
version "0.1.6"
resolved "https://registry.yarnpkg.com/passport-google-oauth2/-/passport-google-oauth2-0.1.6.tgz#dfd7016ac7449fe27cfeb252ae974afc23257a0d"
dependencies:
passport-oauth2 "^1.1.2"
passport-jwt@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/passport-jwt/-/passport-jwt-3.0.1.tgz#e4f7276dad8bd251d43c6fc38883130b963272f6"
@@ -6755,6 +6782,15 @@ passport-local@^1.0.0:
dependencies:
passport-strategy "1.x.x"
passport-oauth2@1.x.x, passport-oauth2@^1.1.2:
version "1.4.0"
resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.4.0.tgz#f62f81583cbe12609be7ce6f160b9395a27b86ad"
dependencies:
oauth "0.9.x"
passport-strategy "1.x.x"
uid2 "0.0.x"
utils-merge "1.x.x"
passport-strategy@1.x.x, passport-strategy@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4"
@@ -7636,7 +7672,7 @@ q@^1.1.2:
version "1.5.0"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1"
qs@6.5.1, qs@^6.1.0, qs@^6.2.0, qs@~6.5.1:
qs@6.5.1, qs@^6.1.0, qs@^6.2.0, qs@^6.5.1, qs@~6.5.1:
version "6.5.1"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
@@ -7780,6 +7816,14 @@ react-input-autosize@^1.1.4:
create-react-class "^15.5.2"
prop-types "^15.5.8"
react-linkify@^0.2.1:
version "0.2.2"
resolved "https://registry.yarnpkg.com/react-linkify/-/react-linkify-0.2.2.tgz#55b99b1cc7244446a0f9bdebbe13b2c30f789e65"
dependencies:
linkify-it "^2.0.3"
prop-types "^15.5.8"
tlds "^1.57.0"
react-mdl-selectfield@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/react-mdl-selectfield/-/react-mdl-selectfield-0.2.0.tgz#36e1a97233036c057ab2bdb31ec09ad8d9988411"
@@ -8979,6 +9023,21 @@ superagent@^2.0.0:
qs "^6.1.0"
readable-stream "^2.0.5"
superagent@^3.8.0:
version "3.8.2"
resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.2.tgz#e4a11b9d047f7d3efeb3bbe536d9ec0021d16403"
dependencies:
component-emitter "^1.2.0"
cookiejar "^2.1.0"
debug "^3.1.0"
extend "^3.0.0"
form-data "^2.3.1"
formidable "^1.1.1"
methods "^1.1.1"
mime "^1.4.1"
qs "^6.5.1"
readable-stream "^2.0.5"
supports-color@3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5"
@@ -9168,7 +9227,7 @@ title-case-minors@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/title-case-minors/-/title-case-minors-1.0.0.tgz#51f17037c294747a1d1cda424b5004c86d8eb115"
tlds@^1.196.0:
tlds@^1.196.0, tlds@^1.57.0:
version "1.199.0"
resolved "https://registry.yarnpkg.com/tlds/-/tlds-1.199.0.tgz#a4fc8c3058216488a80aaaebb427925007e55217"
@@ -9381,6 +9440,10 @@ uid-number@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
uid2@0.0.x:
version "0.0.3"
resolved "https://registry.yarnpkg.com/uid2/-/uid2-0.0.3.tgz#483126e11774df2f71b8b639dcd799c376162b82"
ultron@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.0.tgz#b07a2e6a541a815fc6a34ccd4533baec307ca864"
@@ -9510,7 +9573,7 @@ util@0.10.3, "util@>=0.10.3 <1", util@^0.10.3:
dependencies:
inherits "2.0.1"
utils-merge@1.0.1:
utils-merge@1.0.1, utils-merge@1.x.x:
version "1.0.1"
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"