diff --git a/.meteor/packages b/.meteor/packages
index 2921f6c..628ed8d 100644
--- a/.meteor/packages
+++ b/.meteor/packages
@@ -21,14 +21,14 @@ react-meteor-data
alanning:roles
fourseven:scss
twbs:bootstrap
-accounts-base
-accounts-password
-service-configuration
-accounts-facebook
-accounts-github
-accounts-google
+accounts-base@1.2.17
+accounts-password@1.3.6
+service-configuration@1.0.11
+accounts-facebook@1.1.1
+accounts-github@1.2.1
+accounts-google@1.1.2
themeteorchef:bert
fortawesome:fontawesome
-aldeed:collection2-core
-audit-argument-checks
-ddp-rate-limiter
+aldeed:collection2-core@2.0.0
+audit-argument-checks@1.0.7
+ddp-rate-limiter@1.0.7
diff --git a/.meteor/release b/.meteor/release
index fb6f3bc..01490b6 100644
--- a/.meteor/release
+++ b/.meteor/release
@@ -1 +1 @@
-METEOR@1.4.4.2
+METEOR@1.4.4.3
diff --git a/.meteor/versions b/.meteor/versions
index e690fd9..d151e1f 100644
--- a/.meteor/versions
+++ b/.meteor/versions
@@ -5,8 +5,7 @@ accounts-google@1.1.2
accounts-oauth@1.1.15
accounts-password@1.3.6
alanning:roles@1.2.16
-aldeed:collection2-core@1.2.0
-aldeed:simple-schema@1.5.3
+aldeed:collection2-core@2.0.1
allow-deny@1.0.5
audit-argument-checks@1.0.7
autoupdate@1.3.12
@@ -36,7 +35,7 @@ email@1.2.1
es5-shim@4.6.15
facebook-oauth@1.3.0
fastclick@1.0.13
-fortawesome:fontawesome@4.4.0_1
+fortawesome:fontawesome@4.7.0
fourseven:scss@4.5.0
geojson-utils@1.0.10
github-oauth@1.2.0
@@ -51,7 +50,6 @@ launch-screen@1.1.1
livedata@1.0.18
localstorage@1.0.12
logging@1.1.17
-mdg:validation-error@0.2.0
meteor@1.6.1
meteor-base@1.0.4
minifier-css@1.2.16
@@ -93,7 +91,7 @@ templating-compiler@1.3.2
templating-runtime@1.3.2
templating-tools@1.1.2
themeteorchef:bert@2.1.2
-tmeasday:check-npm-versions@0.2.0
+tmeasday:check-npm-versions@0.3.1
tracker@1.1.3
twbs:bootstrap@3.3.6
ui@1.0.13
diff --git a/imports/api/Documents/Documents.js b/imports/api/Documents/Documents.js
index f428830..4974aab 100644
--- a/imports/api/Documents/Documents.js
+++ b/imports/api/Documents/Documents.js
@@ -46,6 +46,6 @@ Documents.schema = new SimpleSchema({
},
});
-// Documents.attachSchema(Documents.schema);
+Documents.attachSchema(Documents.schema);
export default Documents;
diff --git a/imports/api/OAuth/server/methods.js b/imports/api/OAuth/server/methods.js
new file mode 100644
index 0000000..c3de385
--- /dev/null
+++ b/imports/api/OAuth/server/methods.js
@@ -0,0 +1,14 @@
+import { Meteor } from 'meteor/meteor';
+import { check } from 'meteor/check';
+import { ServiceConfiguration } from 'meteor/service-configuration';
+
+Meteor.methods({
+ 'oauth.verifyConfiguration': function oauthVerifyConfiguration(services) {
+ check(services, Array);
+ const verifiedServices = [];
+ services.forEach((service) => {
+ if (ServiceConfiguration.configurations.findOne({ service })) verifiedServices.push(service);
+ });
+ return verifiedServices.sort();
+ },
+});
diff --git a/imports/api/Users/server/publications.js b/imports/api/Users/server/publications.js
index 1b0acec..7728b4b 100644
--- a/imports/api/Users/server/publications.js
+++ b/imports/api/Users/server/publications.js
@@ -5,6 +5,7 @@ Meteor.publish('users.editProfile', function usersProfile() {
fields: {
emails: 1,
profile: 1,
+ services: 1,
},
});
});
diff --git a/imports/startup/server/accounts.js b/imports/startup/server/accounts/email-templates.js
similarity index 100%
rename from imports/startup/server/accounts.js
rename to imports/startup/server/accounts/email-templates.js
diff --git a/imports/startup/server/accounts/index.js b/imports/startup/server/accounts/index.js
new file mode 100644
index 0000000..c7a0cba
--- /dev/null
+++ b/imports/startup/server/accounts/index.js
@@ -0,0 +1,2 @@
+import './oauth';
+import './email-templates';
diff --git a/imports/startup/server/accounts/oauth.js b/imports/startup/server/accounts/oauth.js
new file mode 100644
index 0000000..545519a
--- /dev/null
+++ b/imports/startup/server/accounts/oauth.js
@@ -0,0 +1,13 @@
+import { Meteor } from 'meteor/meteor';
+import { ServiceConfiguration } from 'meteor/service-configuration';
+
+const OAuthSettings = Meteor.settings.private.OAuth;
+
+if (OAuthSettings) {
+ Object.keys(OAuthSettings).forEach((service) => {
+ ServiceConfiguration.configurations.upsert(
+ { service },
+ { $set: OAuthSettings[service] },
+ );
+ });
+}
diff --git a/imports/startup/server/accounts/on-create-user.js b/imports/startup/server/accounts/on-create-user.js
new file mode 100644
index 0000000..ede5150
--- /dev/null
+++ b/imports/startup/server/accounts/on-create-user.js
@@ -0,0 +1,7 @@
+import { Accounts } from 'meteor/accounts-base';
+
+Accounts.onCreateUser((options, user) => {
+ const userToCreate = user;
+ if (options.profile) userToCreate.profile = options.profile;
+ return userToCreate;
+});
diff --git a/imports/startup/server/api.js b/imports/startup/server/api.js
index c39fc72..18a93a0 100644
--- a/imports/startup/server/api.js
+++ b/imports/startup/server/api.js
@@ -1,5 +1,7 @@
import '../../api/Documents/methods';
import '../../api/Documents/server/publications';
+import '../../api/OAuth/server/methods';
+
import '../../api/Users/server/methods';
import '../../api/Users/server/publications';
diff --git a/imports/ui/components/Authenticated/Authenticated.js b/imports/ui/components/Authenticated/Authenticated.js
index 442d0eb..83dccc3 100644
--- a/imports/ui/components/Authenticated/Authenticated.js
+++ b/imports/ui/components/Authenticated/Authenticated.js
@@ -8,7 +8,7 @@ const Authenticated = ({ loggingIn, authenticated, component, ...rest }) => (
if (loggingIn) return
;
return authenticated ?
(React.createElement(component, { ...props, loggingIn, authenticated })) :
- ();
+ ();
}}
/>
);
diff --git a/imports/ui/components/DocumentEditor/DocumentEditor.js b/imports/ui/components/DocumentEditor/DocumentEditor.js
index ff66cbd..4a42df7 100644
--- a/imports/ui/components/DocumentEditor/DocumentEditor.js
+++ b/imports/ui/components/DocumentEditor/DocumentEditor.js
@@ -86,7 +86,7 @@ class DocumentEditor extends React.Component {
}
DocumentEditor.defaultProps = {
- doc: PropTypes.object,
+ doc: { title: '', body: '' },
};
DocumentEditor.propTypes = {
diff --git a/imports/ui/components/Navigation/Navigation.js b/imports/ui/components/Navigation/Navigation.js
index 2993b39..ffc3020 100644
--- a/imports/ui/components/Navigation/Navigation.js
+++ b/imports/ui/components/Navigation/Navigation.js
@@ -7,7 +7,7 @@ import AuthenticatedNavigation from '../AuthenticatedNavigation/AuthenticatedNav
import './Navigation.scss';
-const Navigation = ({ authenticated, name }) => (
+const Navigation = props => (
@@ -16,18 +16,17 @@ const Navigation = ({ authenticated, name }) => (
- {!authenticated ? : }
+ {!props.authenticated ? : }
);
Navigation.defaultProps = {
- name: PropTypes.string,
+ name: '',
};
Navigation.propTypes = {
authenticated: PropTypes.bool.isRequired,
- name: PropTypes.string,
};
export default Navigation;
diff --git a/imports/ui/components/OAuthLoginButton/OAuthLoginButton.js b/imports/ui/components/OAuthLoginButton/OAuthLoginButton.js
index b30e90e..24cca9e 100644
--- a/imports/ui/components/OAuthLoginButton/OAuthLoginButton.js
+++ b/imports/ui/components/OAuthLoginButton/OAuthLoginButton.js
@@ -5,58 +5,54 @@ import { Bert } from 'meteor/themeteorchef:bert';
import './OAuthLoginButton.scss';
-const handleLogin = (service, options, callback) => {
- const defaultOptions = {
+const handleLogin = (service, callback) => {
+ const options = {
facebook: {
requestPermissions: ['email'],
- loginStyle: 'redirect',
+ loginStyle: 'popup',
+ },
+ github: {
+ requestPermissions: ['user:email'],
+ loginStyle: 'popup',
},
google: {
requestPermissions: ['email'],
requestOfflineToken: true,
- loginStyle: 'redirect',
- },
- github: {
- requestPermissions: ['user:email'],
- loginStyle: 'redirect',
+ loginStyle: 'popup',
},
}[service];
- const defaultCallback = (error) => {
- if (error) Bert.alert(error.reason, 'danger');
- };
-
return {
facebook: Meteor.loginWithFacebook,
- google: Meteor.loginWithGoogle,
github: Meteor.loginWithGithub,
- }[service](options || defaultOptions, callback || defaultCallback);
+ google: Meteor.loginWithGoogle,
+ }[service](options, callback);
};
const serviceLabel = {
facebook: Log In with Facebook,
- google: Log In with Google,
github: Log In with GitHub,
+ google: Log In with Google,
};
-const OAuthLoginButton = ({ service, options, callback }) => (
+const OAuthLoginButton = ({ service, callback }) => (
);
OAuthLoginButton.defaultProps = {
- options: PropTypes.object,
- callback: PropTypes.func,
+ callback: (error) => {
+ if (error) Bert.alert(error.message, 'danger');
+ },
};
OAuthLoginButton.propTypes = {
service: PropTypes.string.isRequired,
- options: PropTypes.object,
callback: PropTypes.func,
};
diff --git a/imports/ui/components/OAuthLoginButtons/OAuthLoginButtons.js b/imports/ui/components/OAuthLoginButtons/OAuthLoginButtons.js
new file mode 100644
index 0000000..60dc857
--- /dev/null
+++ b/imports/ui/components/OAuthLoginButtons/OAuthLoginButtons.js
@@ -0,0 +1,42 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Meteor } from 'meteor/meteor';
+import { createContainer } from 'meteor/react-meteor-data';
+import { ReactiveVar } from 'meteor/reactive-var';
+import OAuthLoginButton from '../OAuthLoginButton/OAuthLoginButton';
+
+import './OAuthLoginButtons.scss';
+
+const OAuthLoginButtons = ({ services, emailMessage }) => (services.length ? (
+
+ {services.map(service =>
)}
+ {emailMessage ?
+ {emailMessage.text}
+
: ''}
+
+) : );
+
+OAuthLoginButtons.propTypes = {
+ services: PropTypes.array.isRequired,
+ emailMessage: PropTypes.object.isRequired,
+};
+
+const verificationComplete = new ReactiveVar(false);
+const verifiedServices = new ReactiveVar([]);
+
+export default createContainer(({ services }) => {
+ if (!verificationComplete.get()) {
+ Meteor.call('oauth.verifyConfiguration', services, (error, response) => {
+ if (error) {
+ console.warn(error);
+ } else {
+ verifiedServices.set(response);
+ verificationComplete.set(true);
+ }
+ });
+ }
+
+ return {
+ services: verifiedServices.get(),
+ };
+}, OAuthLoginButtons);
diff --git a/imports/ui/pages/Signup/Signup.scss b/imports/ui/components/OAuthLoginButtons/OAuthLoginButtons.scss
similarity index 51%
rename from imports/ui/pages/Signup/Signup.scss
rename to imports/ui/components/OAuthLoginButtons/OAuthLoginButtons.scss
index d3e9bac..673e347 100644
--- a/imports/ui/pages/Signup/Signup.scss
+++ b/imports/ui/components/OAuthLoginButtons/OAuthLoginButtons.scss
@@ -1,20 +1,20 @@
@import '../../stylesheets/colors';
-.Signup {
- form {
- position: relative;
- border-top: 1px solid $gray-lighter;
- margin-top: 15px;
- padding-top: 25px;
+.OAuthLoginButtons {
+ margin-bottom: 25px;
- .SignupWithEmail {
+ &.WithEmailMessage {
+ position: relative;
+ border-bottom: 1px solid $gray-lighter;
+ padding-bottom: 30px;
+
+ .EmailMessage {
display: inline-block;
background: #fff;
padding: 0 10px;
position: absolute;
- top: -12px;
+ bottom: -19px;
left: 50%;
- margin-left: -106px;
}
}
}
diff --git a/imports/ui/layouts/App/App.js b/imports/ui/layouts/App/App.js
index 014d9b4..0d189d9 100644
--- a/imports/ui/layouts/App/App.js
+++ b/imports/ui/layouts/App/App.js
@@ -15,6 +15,7 @@ import ViewDocument from '../../pages/ViewDocument/ViewDocument';
import EditDocument from '../../pages/EditDocument/EditDocument';
import Signup from '../../pages/Signup/Signup';
import Login from '../../pages/Login/Login';
+import Logout from '../../pages/Logout/Logout';
import RecoverPassword from '../../pages/RecoverPassword/RecoverPassword';
import ResetPassword from '../../pages/ResetPassword/ResetPassword';
import Profile from '../../pages/Profile/Profile';
@@ -34,6 +35,7 @@ const App = props => (
+
@@ -47,17 +49,24 @@ App.propTypes = {
loading: PropTypes.bool.isRequired,
};
+const getUserName = name => ({
+ string: name,
+ object: `${name.first} ${name.last}`,
+}[typeof name]);
+
export default createContainer(() => {
const loggingIn = Meteor.loggingIn();
const user = Meteor.user();
const userId = Meteor.userId();
const loading = !Roles.subscription.ready();
+ const name = user && user.profile && user.profile.name && getUserName(user.profile.name);
+ const emailAddress = user && user.emails && user.emails[0].address;
return {
loading,
loggingIn,
authenticated: !loggingIn && !!userId,
- name: user && user.profile ? `${user.profile.name.first} ${user.profile.name.last}` : '',
+ name: name || emailAddress,
roles: !loading && Roles.getRolesForUser(userId),
};
}, App);
diff --git a/imports/ui/pages/Documents/Documents.js b/imports/ui/pages/Documents/Documents.js
index 1abffa6..e084e58 100644
--- a/imports/ui/pages/Documents/Documents.js
+++ b/imports/ui/pages/Documents/Documents.js
@@ -73,6 +73,7 @@ Documents.propTypes = {
export default createContainer(() => {
const subscription = Meteor.subscribe('documents');
+ console.log(DocumentsCollection.find().fetch());
return {
loading: !subscription.ready(),
documents: DocumentsCollection.find().fetch(),
diff --git a/imports/ui/pages/Index/Index.js b/imports/ui/pages/Index/Index.js
index 212b840..7db421b 100644
--- a/imports/ui/pages/Index/Index.js
+++ b/imports/ui/pages/Index/Index.js
@@ -1,17 +1,20 @@
import React from 'react';
-import { Jumbotron } from 'react-bootstrap';
+import { Button } from 'react-bootstrap';
import './Index.scss';
const Index = () => (
-
-
- Need help building your app? Check out our mentorship service.
-
+

+
Pup
+
A boilerplate for products.
+
+
+
+
);
diff --git a/imports/ui/pages/Index/Index.scss b/imports/ui/pages/Index/Index.scss
index e69de29..218d2ab 100644
--- a/imports/ui/pages/Index/Index.scss
+++ b/imports/ui/pages/Index/Index.scss
@@ -0,0 +1,58 @@
+@import '../../stylesheets/mixins';
+@import '../../stylesheets/colors';
+
+.Index {
+ padding: 20px;
+ background: $cb-blue;
+ text-align: center;
+ border-radius: 3px;
+ color: #fff;
+
+ img {
+ width: 100px;
+ height: auto;
+ }
+
+ h1 {
+ font-size: 28px;
+ }
+
+ p {
+ font-size: 18px;
+ color: lighten($cb-blue, 25%);
+ }
+
+ > div {
+ display: inline-block;
+ margin: 10px 0 0;
+
+ .btn:first-child {
+ margin-right: 10px;
+ }
+
+ .btn {
+ border: none;
+ }
+
+ .btn:last-child {
+ background: darken($cb-blue, 20%);
+ color: lighten($cb-blue, 30%);
+
+ &:hover {
+ color: #fff;
+ }
+ }
+ }
+}
+
+@include breakpoint(tablet) {
+ .Index {
+ padding: 30px;
+ }
+}
+
+@include breakpoint(desktop) {
+ .Index {
+ padding: 40px;
+ }
+}
diff --git a/imports/ui/pages/Login/Login.js b/imports/ui/pages/Login/Login.js
index c1ef3aa..29f4fa2 100644
--- a/imports/ui/pages/Login/Login.js
+++ b/imports/ui/pages/Login/Login.js
@@ -4,12 +4,10 @@ import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import { Meteor } from 'meteor/meteor';
import { Bert } from 'meteor/themeteorchef:bert';
-import OAuthLoginButton from '../../components/OAuthLoginButton/OAuthLoginButton';
+import OAuthLoginButtons from '../../components/OAuthLoginButtons/OAuthLoginButtons';
import AccountPageFooter from '../../components/AccountPageFooter/AccountPageFooter';
import validate from '../../../modules/validate';
-import './Login.scss';
-
class Login extends React.Component {
constructor(props) {
super(props);
@@ -62,15 +60,16 @@ class Login extends React.Component {
Log In
-
-
-
-
-
+