Commit b7054c9b204f88b7ebcc1f3853955e674a931b87
1 parent
c4d3e07d0f
Exists in
master
added specific organisation login
Showing
43 changed files
with
555 additions
and
656 deletions
Show diff stats
.meteor/packages
... | ... | @@ -16,7 +16,7 @@ standard-minifier-js@1.2.2 # JS minifier run for production mode |
16 | 16 | es5-shim@4.6.15 # ECMAScript 5 compatibility for older browsers. |
17 | 17 | ecmascript@0.6.3 # Enable ECMAScript2015+ syntax in app code |
18 | 18 | |
19 | -accounts-password@1.3.4 | |
19 | +accounts-password | |
20 | 20 | accounts-base@1.2.14 |
21 | 21 | check |
22 | 22 | audit-argument-checks@1.0.7 |
... | ... | @@ -35,3 +35,5 @@ dburles:factory@1.0.0 |
35 | 35 | ddp-rate-limiter@1.0.6 |
36 | 36 | shell-server@0.2.2 |
37 | 37 | aldeed:simple-schema |
38 | +momentjs:moment | |
39 | +meteorhacks:picker | ... | ... |
.meteor/versions
... | ... | @@ -56,6 +56,7 @@ mdg:validated-method@1.1.0 |
56 | 56 | mdg:validation-error@0.5.1 |
57 | 57 | meteor@1.6.1 |
58 | 58 | meteor-base@1.0.4 |
59 | +meteorhacks:picker@1.0.3 | |
59 | 60 | minifier-css@1.2.16 |
60 | 61 | minifier-js@1.2.18 |
61 | 62 | minimongo@1.0.20 |
... | ... | @@ -63,6 +64,7 @@ mobile-experience@1.0.4 |
63 | 64 | mobile-status-bar@1.0.14 |
64 | 65 | modules@0.7.9 |
65 | 66 | modules-runtime@0.7.9 |
67 | +momentjs:moment@2.17.1 | |
66 | 68 | mongo@1.1.15 |
67 | 69 | mongo-id@1.0.6 |
68 | 70 | npm-bcrypt@0.9.2 | ... | ... |
imports/api/documents/documents.js
... | ... | @@ -1,36 +0,0 @@ |
1 | -import { Mongo } from 'meteor/mongo'; | |
2 | -import { SimpleSchema } from 'meteor/aldeed:simple-schema'; | |
3 | -import { Factory } from 'meteor/dburles:factory'; | |
4 | - | |
5 | -const Documents = new Mongo.Collection('Documents'); | |
6 | -export default Documents; | |
7 | - | |
8 | -Documents.allow({ | |
9 | - insert: () => false, | |
10 | - update: () => false, | |
11 | - remove: () => false, | |
12 | -}); | |
13 | - | |
14 | -Documents.deny({ | |
15 | - insert: () => true, | |
16 | - update: () => true, | |
17 | - remove: () => true, | |
18 | -}); | |
19 | - | |
20 | -Documents.schema = new SimpleSchema({ | |
21 | - title: { | |
22 | - type: String, | |
23 | - label: 'The title of the document.', | |
24 | - }, | |
25 | - body: { | |
26 | - type: String, | |
27 | - label: 'The body of the document.', | |
28 | - }, | |
29 | -}); | |
30 | - | |
31 | -Documents.attachSchema(Documents.schema); | |
32 | - | |
33 | -Factory.define('document', Documents, { | |
34 | - title: () => 'Factory Title', | |
35 | - body: () => 'Factory Body', | |
36 | -}); |
imports/api/documents/documents.tests.js
... | ... | @@ -1,11 +0,0 @@ |
1 | -/* eslint-env mocha */ | |
2 | -/* eslint-disable func-names, prefer-arrow-callback */ | |
3 | - | |
4 | -import { assert } from 'meteor/practicalmeteor:chai'; | |
5 | -import Documents from './documents.js'; | |
6 | - | |
7 | -describe('Documents collection', function () { | |
8 | - it('registers the collection with Mongo properly', function () { | |
9 | - assert.equal(typeof Documents, 'object'); | |
10 | - }); | |
11 | -}); |
imports/api/documents/methods.js
... | ... | @@ -1,35 +0,0 @@ |
1 | -import { SimpleSchema } from 'meteor/aldeed:simple-schema'; | |
2 | -import { ValidatedMethod } from 'meteor/mdg:validated-method'; | |
3 | -import Documents from './documents'; | |
4 | -import rateLimit from '../../modules/rate-limit.js'; | |
5 | - | |
6 | -export const upsertDocument = new ValidatedMethod({ | |
7 | - name: 'documents.upsert', | |
8 | - validate: new SimpleSchema({ | |
9 | - _id: { type: String, optional: true }, | |
10 | - title: { type: String, optional: true }, | |
11 | - body: { type: String, optional: true }, | |
12 | - }).validator(), | |
13 | - run(document) { | |
14 | - return Documents.upsert({ _id: document._id }, { $set: document }); | |
15 | - }, | |
16 | -}); | |
17 | - | |
18 | -export const removeDocument = new ValidatedMethod({ | |
19 | - name: 'documents.remove', | |
20 | - validate: new SimpleSchema({ | |
21 | - _id: { type: String }, | |
22 | - }).validator(), | |
23 | - run({ _id }) { | |
24 | - Documents.remove(_id); | |
25 | - }, | |
26 | -}); | |
27 | - | |
28 | -rateLimit({ | |
29 | - methods: [ | |
30 | - upsertDocument, | |
31 | - removeDocument, | |
32 | - ], | |
33 | - limit: 5, | |
34 | - timeRange: 1000, | |
35 | -}); |
imports/api/documents/methods.tests.js
... | ... | @@ -1,47 +0,0 @@ |
1 | -/* eslint-env mocha */ | |
2 | -/* eslint-disable func-names, prefer-arrow-callback */ | |
3 | - | |
4 | -import { Meteor } from 'meteor/meteor'; | |
5 | -import { assert } from 'meteor/practicalmeteor:chai'; | |
6 | -import { resetDatabase } from 'meteor/xolvio:cleaner'; | |
7 | -import { Factory } from 'meteor/dburles:factory'; | |
8 | -import Documents from './documents.js'; | |
9 | -import { upsertDocument, removeDocument } from './methods.js'; | |
10 | - | |
11 | -describe('Documents methods', function () { | |
12 | - beforeEach(function () { | |
13 | - if (Meteor.isServer) { | |
14 | - resetDatabase(); | |
15 | - } | |
16 | - }); | |
17 | - | |
18 | - it('inserts a document into the Documents collection', function () { | |
19 | - upsertDocument.call({ | |
20 | - title: 'You can\'t arrest me, I\'m the Cake Boss!', | |
21 | - body: 'They went nuts!', | |
22 | - }); | |
23 | - | |
24 | - const getDocument = Documents.findOne({ title: 'You can\'t arrest me, I\'m the Cake Boss!' }); | |
25 | - assert.equal(getDocument.body, 'They went nuts!'); | |
26 | - }); | |
27 | - | |
28 | - it('updates a document in the Documents collection', function () { | |
29 | - const { _id } = Factory.create('document'); | |
30 | - | |
31 | - upsertDocument.call({ | |
32 | - _id, | |
33 | - title: 'You can\'t arrest me, I\'m the Cake Boss!', | |
34 | - body: 'They went nuts!', | |
35 | - }); | |
36 | - | |
37 | - const getDocument = Documents.findOne(_id); | |
38 | - assert.equal(getDocument.title, 'You can\'t arrest me, I\'m the Cake Boss!'); | |
39 | - }); | |
40 | - | |
41 | - it('removes a document from the Documents collection', function () { | |
42 | - const { _id } = Factory.create('document'); | |
43 | - removeDocument.call({ _id }); | |
44 | - const getDocument = Documents.findOne(_id); | |
45 | - assert.equal(getDocument, undefined); | |
46 | - }); | |
47 | -}); |
imports/api/documents/server/publications.js
... | ... | @@ -1,10 +0,0 @@ |
1 | -import { Meteor } from 'meteor/meteor'; | |
2 | -import { check } from 'meteor/check'; | |
3 | -import Documents from '../documents'; | |
4 | - | |
5 | -Meteor.publish('documents.list', () => Documents.find()); | |
6 | - | |
7 | -Meteor.publish('documents.view', (_id) => { | |
8 | - check(_id, String); | |
9 | - return Documents.find(_id); | |
10 | -}); |
imports/client/app/routes.js
... | ... | @@ -48,7 +48,7 @@ const detectOrg = () => { |
48 | 48 | if(orgSlug!=""){ |
49 | 49 | Meteor.call('checkExistingOrg', {slug:orgSlug}, function(err, res) { |
50 | 50 | if(res){ |
51 | - Session.set('orgId', res._id._str); | |
51 | + Session.set('orgId', res._id); | |
52 | 52 | Session.set('orgSlug', orgSlug); |
53 | 53 | render(getOrgRoutes(),document.getElementById('app')); |
54 | 54 | }else{ | ... | ... |
imports/client/assets/css/icons/icomoon/styles.css
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | font-family: 'icomoon'; |
3 | 3 | src:url('fonts/icomoon.eot?3p0rtw'); |
4 | 4 | src:url('fonts/icomoon.eot?#iefix3p0rtw') format('embedded-opentype'), |
5 | - url('fonts/icomoon.woff?3p0rtw') format('font-woff'), | |
5 | + url('fonts/icomoon.woff?3p0rtw') format('woff'), | |
6 | 6 | url('fonts/icomoon.ttf?3p0rtw') format('truetype'), |
7 | 7 | url('fonts/icomoon.svg?3p0rtw#icomoon') format('svg'); |
8 | 8 | font-weight: normal; | ... | ... |
imports/client/views/org/app/module/navigation/PublicNavigation.js
... | ... | @@ -18,7 +18,7 @@ render(){ |
18 | 18 | var signup = `http://${mainSite}/signup`; |
19 | 19 | return( |
20 | 20 | <Nav pullRight> |
21 | - <LinkContainer to={ setQueryParam(this.props.location, { enter: 'login' }) }> | |
21 | + <LinkContainer to="login"> | |
22 | 22 | <NavItem eventKey={ 2 } href="/login">Log In</NavItem> |
23 | 23 | </LinkContainer> |
24 | 24 | </Nav> | ... | ... |
imports/client/views/org/enter/module/EnterLayout.js
... | ... | @@ -37,6 +37,7 @@ export class EnterLayout extends React.Component { |
37 | 37 | error: '', |
38 | 38 | message: '', |
39 | 39 | }; |
40 | + this.onClearState = this.onClearState.bind(this); | |
40 | 41 | }; |
41 | 42 | |
42 | 43 | componentWillReceiveProps(nextProps) { |
... | ... | @@ -100,28 +101,39 @@ export class EnterLayout extends React.Component { |
100 | 101 | }; |
101 | 102 | |
102 | 103 | onLogin(e) { |
104 | + const self = this; | |
103 | 105 | e.preventDefault(); |
106 | + const email = this.state.email; | |
107 | + const password = this.state.password; | |
104 | 108 | this.onClearState(true); |
105 | - if(this.state.email.trim() == '' || !validation.validateEmail(this.state.email)){ | |
109 | + if(email.trim() == '' || !validation.validateEmail(this.state.email)){ | |
106 | 110 | this.onClearState(); |
107 | 111 | Bert.alert('Please enter a valid email address!', 'danger'); |
108 | 112 | return false; |
109 | 113 | } |
110 | - if(this.state.password.trim() == ''){ | |
114 | + if(password.trim() == ''){ | |
111 | 115 | Bert.alert('Please enter your password!', 'danger'); |
112 | 116 | this.onClearState(); |
113 | 117 | return false; |
114 | 118 | } |
115 | - Meteor.loginWithPassword( | |
116 | - this.state.email, | |
117 | - this.state.password, | |
118 | - (e, r) => { | |
119 | - this.onClearState(); | |
120 | - if(e) { | |
121 | - this.setState({error: 'Wrong email or password.'}) | |
122 | - } | |
119 | + Meteor.call('checkEmailInOrg', {email:email,orgId:Session.get('orgId')}, function (error, result) { | |
120 | + if(result.success){ | |
121 | + Meteor.loginWithPassword( | |
122 | + email, | |
123 | + password, | |
124 | + (e, r) => { | |
125 | + self.onClearState(); | |
126 | + if(e) { | |
127 | + self.setState({error: 'Wrong password.'}) | |
128 | + } | |
129 | + } | |
130 | + ); | |
131 | + }else{ | |
132 | + Bert.alert('This email is not associated to this Organisation!', 'danger'); | |
133 | + self.onClearState(); | |
123 | 134 | } |
124 | - ); | |
135 | + | |
136 | + }); | |
125 | 137 | }; |
126 | 138 | |
127 | 139 | render() { | ... | ... |
imports/collections/orgs/methods.js
... | ... | @@ -31,5 +31,24 @@ export const checkExistingOrg = new ValidatedMethod({ |
31 | 31 | org = Orgs.findOne({slug:slug}); |
32 | 32 | return org; |
33 | 33 | }, |
34 | +}); | |
35 | + | |
36 | +export const checkEmailInOrg = new ValidatedMethod({ | |
37 | + name: 'checkEmailInOrg', | |
38 | + | |
39 | + validate: new SimpleSchema({ | |
40 | + email: { type: String }, | |
41 | + orgId: { type: String }, | |
42 | + }).validator(), | |
43 | + | |
44 | + run({email, orgId}) { | |
45 | + console.log(orgId); | |
46 | + user = Users.findOne({"orgId":orgId, "emails.address":email}); | |
47 | + if(user){ | |
48 | + return {success:true} | |
49 | + }else{ | |
50 | + return {success:false} | |
51 | + } | |
52 | + }, | |
34 | 53 | |
35 | 54 | }); | ... | ... |
imports/modules/document-editor.js
... | ... | @@ -1,56 +0,0 @@ |
1 | -/* eslint-disable no-undef */ | |
2 | - | |
3 | -import { browserHistory } from 'react-router'; | |
4 | -import { Bert } from 'meteor/themeteorchef:bert'; | |
5 | -import { upsertDocument } from '../api/documents/methods.js'; | |
6 | -import './validation.js'; | |
7 | - | |
8 | -let component; | |
9 | - | |
10 | -const handleUpsert = () => { | |
11 | - const { doc } = component.props; | |
12 | - const confirmation = doc && doc._id ? 'Document updated!' : 'Document added!'; | |
13 | - const upsert = { | |
14 | - title: document.querySelector('[name="title"]').value.trim(), | |
15 | - body: document.querySelector('[name="body"]').value.trim(), | |
16 | - }; | |
17 | - | |
18 | - if (doc && doc._id) upsert._id = doc._id; | |
19 | - | |
20 | - upsertDocument.call(upsert, (error, response) => { | |
21 | - if (error) { | |
22 | - Bert.alert(error.reason, 'danger'); | |
23 | - } else { | |
24 | - component.documentEditorForm.reset(); | |
25 | - Bert.alert(confirmation, 'success'); | |
26 | - browserHistory.push(`/documents/${response.insertedId || doc._id}`); | |
27 | - } | |
28 | - }); | |
29 | -}; | |
30 | - | |
31 | -const validate = () => { | |
32 | - $(component.documentEditorForm).validate({ | |
33 | - rules: { | |
34 | - title: { | |
35 | - required: true, | |
36 | - }, | |
37 | - body: { | |
38 | - required: true, | |
39 | - }, | |
40 | - }, | |
41 | - messages: { | |
42 | - title: { | |
43 | - required: 'Need a title in here, Seuss.', | |
44 | - }, | |
45 | - body: { | |
46 | - required: 'This thneeds a body, please.', | |
47 | - }, | |
48 | - }, | |
49 | - submitHandler() { handleUpsert(); }, | |
50 | - }); | |
51 | -}; | |
52 | - | |
53 | -export default function documentEditor(options) { | |
54 | - component = options.component; | |
55 | - validate(); | |
56 | -} |
imports/modules/rate-limit.js
... | ... | @@ -1,18 +0,0 @@ |
1 | -import { Meteor } from 'meteor/meteor'; | |
2 | -import { DDPRateLimiter } from 'meteor/ddp-rate-limiter'; | |
3 | -import { _ } from 'meteor/underscore'; | |
4 | - | |
5 | -const fetchMethodNames = methods => _.pluck(methods, 'name'); | |
6 | - | |
7 | -const assignLimits = ({ methods, limit, timeRange }) => { | |
8 | - const methodNames = fetchMethodNames(methods); | |
9 | - | |
10 | - if (Meteor.isServer) { | |
11 | - DDPRateLimiter.addRule({ | |
12 | - name(name) { return _.contains(methodNames, name); }, | |
13 | - connectionId() { return true; }, | |
14 | - }, limit, timeRange); | |
15 | - } | |
16 | -}; | |
17 | - | |
18 | -export default function rateLimit(options) { return assignLimits(options); } |
imports/server/accounts.js
... | ... | @@ -0,0 +1,9 @@ |
1 | +import '/imports/server/emails/config'; | |
2 | +import './accounts/email-templates'; | |
3 | +import './accounts/verifyEmail'; | |
4 | +import './accounts/login'; | |
5 | +import './accounts/resetPassword'; | |
6 | +import '/imports/server/emails/invite'; | |
7 | +import '/imports/server/pages/verifyEmail'; | |
8 | + | |
9 | +import './accounts/creation'; | ... | ... |
imports/server/accounts/creation.js
... | ... | @@ -2,22 +2,32 @@ import _ from 'lodash'; |
2 | 2 | import { Accounts } from 'meteor/accounts-base'; |
3 | 3 | import { SimpleSchema } from 'meteor/aldeed:simple-schema'; |
4 | 4 | import { ValidatedMethod } from 'meteor/mdg:validated-method'; |
5 | + | |
5 | 6 | import { Orgs } from '/imports/collections/orgs/index'; |
6 | 7 | import { Users } from '/imports/collections/users/index'; |
7 | 8 | |
8 | 9 | |
9 | - | |
10 | 10 | Accounts.validateNewUser((user) => { |
11 | 11 | return !!user; |
12 | 12 | }); |
13 | 13 | |
14 | 14 | Accounts.onCreateUser((options, user) => { |
15 | - _.assign(user, { | |
16 | - firstName: options.profile.firstName, | |
17 | - lastName: options.profile.lastName, | |
18 | - phones: [], | |
19 | - identities: [], | |
20 | - createdAt: new Date().getTime(), | |
21 | - }); | |
22 | - return user; | |
15 | + if(options.orgSlug){ | |
16 | + orgId = Orgs.insert({ | |
17 | + slug: options.orgSlug, | |
18 | + name: options.orgName, | |
19 | + setup: 1, | |
20 | + users: [{ | |
21 | + userId: user._id, | |
22 | + role: Users.roles.ADMIN, | |
23 | + }], | |
24 | + }); | |
25 | + } | |
26 | + _.assign(user, { | |
27 | + role: Users.roles.ADMIN, | |
28 | + orgId: orgId, | |
29 | + firstName: options.profile.firstName, | |
30 | + lastName: options.profile.lastName, | |
31 | + }); | |
32 | + return user; | |
23 | 33 | }); | ... | ... |
imports/server/accounts/email-templates.js
... | ... | @@ -0,0 +1,25 @@ |
1 | +import { Accounts } from 'meteor/accounts-base'; | |
2 | + | |
3 | +const name = 'Application Name'; | |
4 | +const email = '<support@application.com>'; | |
5 | +const from = `${name} ${email}`; | |
6 | +const emailTemplates = Accounts.emailTemplates; | |
7 | + | |
8 | +emailTemplates.siteName = name; | |
9 | +emailTemplates.from = from; | |
10 | + | |
11 | +emailTemplates.resetPassword = { | |
12 | + subject() { | |
13 | + return `[${name}] Reset Your Password`; | |
14 | + }, | |
15 | + text(user, url) { | |
16 | + const userEmail = user.emails[0].address; | |
17 | + const urlWithoutHash = url.replace('#/', ''); | |
18 | + | |
19 | + return `A password reset has been requested for the account related to this | |
20 | + address (${userEmail}). To reset the password, visit the following link: | |
21 | + \n\n${urlWithoutHash}\n\n If you did not request this reset, please ignore | |
22 | + this email. If you feel something is wrong, please contact our support team: | |
23 | + ${email}.`; | |
24 | + }, | |
25 | +}; | ... | ... |
imports/server/accounts/login.js
imports/server/accounts/resetPassword.js
... | ... | @@ -0,0 +1,31 @@ |
1 | +import _ from 'lodash'; | |
2 | +import { Accounts } from 'meteor/accounts-base'; | |
3 | + | |
4 | + | |
5 | +Accounts.emailTemplates.resetPassword = { | |
6 | + subject() { | |
7 | + return '[Blok8] Reset Your Password'; | |
8 | + }, | |
9 | + text(user, url) { | |
10 | + const userEmail = user.emails[0].address; | |
11 | + const theUrl = Meteor.absoluteUrl(`?enter=reset&token=${_.last(url.split('/'))}`); | |
12 | + // const theUrl = decodeURI(`\u003D`); | |
13 | + | |
14 | + return ( | |
15 | +` | |
16 | +Hello, ${user.firstName}! | |
17 | + | |
18 | + | |
19 | +A password reset has been requested for the account related to this address. | |
20 | +To reset the password, visit the following link: | |
21 | + | |
22 | +${theUrl} | |
23 | + | |
24 | +If you did not request this reset, please ignore this email. | |
25 | + | |
26 | +` | |
27 | + ); | |
28 | + }, | |
29 | +}; | |
30 | + | |
31 | + | ... | ... |
imports/server/accounts/verifyEmail.js
... | ... | @@ -0,0 +1,29 @@ |
1 | +import _ from 'lodash'; | |
2 | +import { Accounts } from 'meteor/accounts-base'; | |
3 | + | |
4 | +Accounts.config({ | |
5 | + sendVerificationEmail: true | |
6 | +}); | |
7 | + | |
8 | +Accounts.emailTemplates.verifyEmail = { | |
9 | + subject() { | |
10 | + return '[YoungDesk] Verify Your Email Address'; | |
11 | + }, | |
12 | + text(user, url) { | |
13 | + const theUrl = Meteor.absoluteUrl(`back/verifyEmail/${_.last(url.split('/'))}`); | |
14 | + | |
15 | + return ( | |
16 | +` | |
17 | +Hello, ${user.firstName}! | |
18 | + | |
19 | + | |
20 | +To verify your email address, visit the following link: | |
21 | + | |
22 | +${theUrl} | |
23 | + | |
24 | +If you did not request this verification, please ignore this email. | |
25 | + | |
26 | +` | |
27 | + ); | |
28 | + }, | |
29 | +}; | ... | ... |
imports/server/browser-policy.js
... | ... | @@ -0,0 +1,14 @@ |
1 | +import { BrowserPolicy } from 'meteor/browser-policy-common'; | |
2 | +// e.g., BrowserPolicy.content.allowOriginForAll( 's3.amazonaws.com' ); | |
3 | +BrowserPolicy.content.allowFontOrigin("data:"); | |
4 | + | |
5 | +BrowserPolicy.content.disallowEval(); | |
6 | + | |
7 | +BrowserPolicy.framing.allowAll(); | |
8 | +BrowserPolicy.content.allowInlineScripts(); | |
9 | +BrowserPolicy.content.allowInlineStyles(); | |
10 | +BrowserPolicy.content.allowSameOriginForAll(); | |
11 | +BrowserPolicy.content.allowDataUrlForAll(); | |
12 | +BrowserPolicy.content.allowOriginForAll('*'); | |
13 | +BrowserPolicy.content.allowOriginForAll('http://*'); | |
14 | +BrowserPolicy.content.allowOriginForAll('https://*'); | ... | ... |
imports/server/collections.js
imports/server/emails/config.js
... | ... | @@ -0,0 +1,10 @@ |
1 | +// process.env.MAIL_URL = "smtp://postmaster%40sandboxdac306638463443cb5d8adc4380ea78d.mailgun.org:9a2131ff0360b37dae90faca340e6b8f@smtp.mailgun.org:587"; | |
2 | +// process.env.MAIL_URL = "smtp://block8:cfxJfbe7xI7qfTgE2DB22g@smtp.mandrillapp.com:587"; /* Test Mode */ | |
3 | + | |
4 | +import { Accounts } from 'meteor/accounts-base'; | |
5 | + | |
6 | +if(Meteor.settings.public.environment === 'production') { | |
7 | + process.env.MAIL_URL = "smtp://block8:Ih-DuTSHlO-bdiPE7FBl3Q@smtp.mandrillapp.com:587"; | |
8 | +} | |
9 | +Accounts.emailTemplates.siteName = 'YoungDesk'; | |
10 | +Accounts.emailTemplates.from = 'YoungDesk <support@youngdesk.com>'; | ... | ... |
imports/server/emails/invite.js
... | ... | @@ -0,0 +1,166 @@ |
1 | +import { Email } from 'meteor/email' | |
2 | +import {moment} from 'meteor/momentjs:moment' | |
3 | +moment.locale('en-au'); | |
4 | + | |
5 | +export const sendInviteEmail = ({email, firstName, orgName, token}) => { | |
6 | + const url = Meteor.absoluteUrl(`invite/${token}`); | |
7 | + const text = ` | |
8 | +Hello, ${firstName}! | |
9 | + | |
10 | +You have been invited to join the ${orgName} on Blok8 wallet. | |
11 | +To join, use the following link: | |
12 | + | |
13 | +${url} | |
14 | +`; | |
15 | + | |
16 | + Email.send({ | |
17 | + from: 'Blok 8 <support@mystake.io>', | |
18 | + to: email, | |
19 | + subject: `[Blok8] Invitation to ${orgName}`, | |
20 | + text: text, | |
21 | + }); | |
22 | + | |
23 | +}; | |
24 | + | |
25 | +export const sendChangeSharePriceEmail = ({orgName, firstName, lastName, price, email}) => { | |
26 | + const text = ` | |
27 | +Hi ${firstName}, | |
28 | + | |
29 | +The current share price has been changed to $A${price} for the company ${orgName}. | |
30 | +`; | |
31 | + | |
32 | + Email.send({ | |
33 | + from: 'Blok 8 <support@mystake.io>', | |
34 | + to: email, | |
35 | + subject: `[Blok8] Share price has changed for ${orgName}.`, | |
36 | + text: text, | |
37 | + }); | |
38 | + | |
39 | +}; | |
40 | + | |
41 | +export const sendChangeNameEmail = ({firstName, lastName, email}) => { | |
42 | + | |
43 | + console.log(firstName); | |
44 | + console.log(lastName); | |
45 | + console.log(email); | |
46 | + const text = ` | |
47 | +Hi ${firstName}, | |
48 | + | |
49 | +Your name has been changed to "${firstName} ${lastName}". | |
50 | + | |
51 | +If you did not change your name, please reset your password. | |
52 | +`; | |
53 | + | |
54 | + Email.send({ | |
55 | + from: 'Blok 8 <support@mystake.io>', | |
56 | + to: email, | |
57 | + subject: `[Blok8] - Name Change`, | |
58 | + text: text, | |
59 | + }); | |
60 | + | |
61 | +}; | |
62 | + | |
63 | +export const sendChangePasswordEmail = ({firstName, lastName, email}) => { | |
64 | + | |
65 | + console.log(firstName); | |
66 | + console.log(lastName); | |
67 | + console.log(email); | |
68 | + let date = moment().format('LLL'); | |
69 | + const text = ` | |
70 | +Hi ${firstName}, | |
71 | + | |
72 | +Your password was recently changed on ${date}. | |
73 | + | |
74 | +If you did not change your password, please reset your password immediately. | |
75 | +`; | |
76 | + | |
77 | + Email.send({ | |
78 | + from: 'Blok 8 <support@mystake.io>', | |
79 | + to: email, | |
80 | + subject: `[Blok8] - Password Change`, | |
81 | + text: text, | |
82 | + }); | |
83 | + | |
84 | +}; | |
85 | + | |
86 | +export const sendChangeEmail = ({firstName, lastName, email, newEmail}) => { | |
87 | + | |
88 | + console.log(firstName); | |
89 | + console.log(lastName); | |
90 | + console.log(email); | |
91 | + let date = moment().format('LLL'); | |
92 | + const text = ` | |
93 | +Hi ${firstName}, | |
94 | + | |
95 | +Your email address was recently changed on ${newEmail} on ${date}. | |
96 | + | |
97 | +If you did not change your email address, please contact us immediately by responding to this email. | |
98 | +`; | |
99 | + | |
100 | + Email.send({ | |
101 | + from: 'Blok 8 <support@mystake.io>', | |
102 | + to: email, | |
103 | + subject: `[Blok8] - Email Change`, | |
104 | + text: text, | |
105 | + }); | |
106 | + | |
107 | +}; | |
108 | + | |
109 | + | |
110 | +export const sendIssueSharesEmail = ({orgName, firstName, lastName, quantity, purchasePrice, shareClass,email}) => { | |
111 | + console.log(quantity); | |
112 | + console.log(purchasePrice); | |
113 | + console.log(shareClass); | |
114 | + console.log(email); | |
115 | + const text = ` | |
116 | +Hi ${firstName}, | |
117 | + | |
118 | +${quantity} ${shareClass} shares in ${orgName} have been issued to you for A$${purchasePrice} in total. | |
119 | + | |
120 | +`; | |
121 | + | |
122 | + Email.send({ | |
123 | + from: 'Blok 8 <support@mystake.io>', | |
124 | + to: email, | |
125 | + subject: `[Blok8] New shares have been issued to you in ${orgName}.`, | |
126 | + text: text, | |
127 | + }); | |
128 | + | |
129 | +}; | |
130 | + | |
131 | +export const sendNewAnnouncementsEmail = ({orgId, orgName, createdByUser, title, description, uniqueUrl, firstName, lastName, email}) => { | |
132 | + const text = ` | |
133 | +Hi ${firstName}, | |
134 | + | |
135 | +A new announcement has been issued by the company secretary! | |
136 | + | |
137 | +Title: ${title}. | |
138 | + | |
139 | +`; | |
140 | + | |
141 | + Email.send({ | |
142 | + from: 'Blok 8 <support@mystake.io>', | |
143 | + to: email, | |
144 | + subject: `[Blok8] ${orgName} - New Announcement`, | |
145 | + text: text, | |
146 | + }); | |
147 | + | |
148 | +}; | |
149 | + | |
150 | + | |
151 | +export const sendIssueDividendsEmail = ({ orgId, orgName, dividend, firstName, lastName, email }) => { | |
152 | + const text = ` | |
153 | +Hi ${firstName}! | |
154 | + | |
155 | +A new dividend has been issued at $A${dividend} per ordinary share for the company "${orgName}". | |
156 | + | |
157 | +`; | |
158 | + | |
159 | + Email.send({ | |
160 | + from: 'Blok 8 <support@mystake.io>', | |
161 | + to: email, | |
162 | + subject: `[Blok8] A new dividend has been issued by ${orgName}`, | |
163 | + text: text, | |
164 | + }); | |
165 | + | |
166 | +}; | ... | ... |
imports/server/fixtures.js
... | ... | @@ -0,0 +1,23 @@ |
1 | +import { Meteor } from 'meteor/meteor'; | |
2 | +import { Roles } from 'meteor/alanning:roles'; | |
3 | +import { Accounts } from 'meteor/accounts-base'; | |
4 | + | |
5 | +if (!Meteor.isProduction) { | |
6 | + const users = [{ | |
7 | + email: 'admin@admin.com', | |
8 | + password: 'password', | |
9 | + profile: { | |
10 | + name: { first: 'Carl', last: 'Winslow' }, | |
11 | + }, | |
12 | + roles: ['admin'], | |
13 | + }]; | |
14 | + | |
15 | + users.forEach(({ email, password, profile, roles }) => { | |
16 | + const userExists = Meteor.users.findOne({ 'emails.address': email }); | |
17 | + | |
18 | + if (!userExists) { | |
19 | + const userId = Accounts.createUser({ email, password, profile }); | |
20 | + Roles.addUsersToRoles(userId, roles); | |
21 | + } | |
22 | + }); | |
23 | +} | ... | ... |
imports/server/index.js
imports/server/pages/verifyEmail.js
... | ... | @@ -0,0 +1,164 @@ |
1 | +import React from 'react'; | |
2 | +import _ from 'lodash'; | |
3 | +import { Users } from '/imports/collections/users/index'; | |
4 | + | |
5 | + | |
6 | + | |
7 | + | |
8 | +const finishWithMessage = (res, message, redirect = "/") => { | |
9 | + | |
10 | + const output = ` | |
11 | +<html> | |
12 | +<head> | |
13 | +<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/simple-line-icons/2.4.1/css/simple-line-icons.css"> | |
14 | +<!-- Latest compiled and minified CSS --> | |
15 | +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> | |
16 | +<style type="text/css"> | |
17 | +.congo-wrap .header { | |
18 | + background: #379AC7; | |
19 | + background: -webkit-linear-gradient(-90deg, #379AC7, #0460D9); | |
20 | + background: linear-gradient(180deg, #379AC7, #0460D9); | |
21 | + height: 80px; | |
22 | + padding: 11px 0; | |
23 | +} | |
24 | + .logo img{ | |
25 | + width:170px; | |
26 | + } | |
27 | +.congo-wrap .header .container { | |
28 | + width: 100%; | |
29 | + padding:0 20px; | |
30 | +} | |
31 | +.congo-wrap{ | |
32 | + background:#f6f7f7; | |
33 | + height:100%; | |
34 | +} | |
35 | +.widgetbox-congrats { | |
36 | + max-width: 720px; | |
37 | + margin: 0px auto; | |
38 | + background: #fff; | |
39 | + position: relative; | |
40 | + top: 20px; | |
41 | + text-align: center; | |
42 | + border: 1px solid #eee; | |
43 | + font-size: 20px; | |
44 | +} | |
45 | + | |
46 | +body { | |
47 | + margin: 0; | |
48 | + padding: 0; | |
49 | +} | |
50 | + | |
51 | +.widgetbox-congrats .congo-msg { | |
52 | + padding: 90px 0; | |
53 | + border-bottom: 1px solid #eee; | |
54 | +} | |
55 | + | |
56 | +.widgetbox-congrats.congo-msg h4 {margin: 0 !important;padding: 0 !important;} | |
57 | + | |
58 | +.text-blue { | |
59 | + color: #0059ce; | |
60 | +} | |
61 | + | |
62 | +.widgetbox-congrats .congo-msg h4 { | |
63 | + margin: 8px 0; | |
64 | + font-size: 24px; | |
65 | +} | |
66 | + | |
67 | +.widgetbox-congrats .congo-msg .icon { | |
68 | + color: #0F67C8; | |
69 | + font-size: 90px; | |
70 | + font-weight: 100; | |
71 | + margin-bottom: 20px; | |
72 | + display: block; | |
73 | +} | |
74 | + | |
75 | +.widgetbox-congrats .widgetbox-footer { | |
76 | + padding: 31px 10px; | |
77 | +} | |
78 | + | |
79 | +.widgetbox-congrats .widgetbox-footer .btn { | |
80 | + background: #0e89d3; | |
81 | + color: #fff; | |
82 | + padding: 10px 30px; | |
83 | + text-transform: uppercase; | |
84 | +} | |
85 | +</style> | |
86 | + | |
87 | +</head> | |
88 | + | |
89 | +<body> | |
90 | +<div class="congo-wrap"> | |
91 | +<div class="header"> | |
92 | + <div class="container"> | |
93 | + <div class="logo"> | |
94 | + <img src="/files/images/svg/logo--white.svg" altt=""/> | |
95 | + </div> | |
96 | + </div> | |
97 | +</div> | |
98 | + <div class="container"> | |
99 | + <div class="widgetbox-congrats"> | |
100 | + <div class="congo-msg"> | |
101 | + <div class="text-blue"> | |
102 | + <i class="icon icon-simple icon-check"></i> | |
103 | + <h4>Congrats!</h4> | |
104 | + </div> | |
105 | + <p> ${message}</p> | |
106 | + </div> | |
107 | + <div class="widgetbox-footer"> | |
108 | + <a href="${redirect}" class="btn btn-lg btn-prmary">Continue</a> | |
109 | + </div> | |
110 | + | |
111 | + </div> | |
112 | + </div> | |
113 | +</div> | |
114 | + | |
115 | +</html> | |
116 | + `; | |
117 | + | |
118 | + res.writeHead(200, { | |
119 | + 'Content-Length': output.length, | |
120 | + 'Content-Type': 'text/html', | |
121 | + }); | |
122 | + res.end(output); | |
123 | +}; | |
124 | + | |
125 | + | |
126 | + | |
127 | +Picker.route('/back/verifyEmail/:token', function(params, req, res, next) { | |
128 | + | |
129 | + const user = Users.findOne({'services.email.verificationTokens.token': params.token}); | |
130 | + if(!user) return finishWithMessage(res, 'Invalid or outdated token.'); | |
131 | + | |
132 | + const token = _.find(user.services.email.verificationTokens, x => x.token === params.token); | |
133 | + if(new Date().getTime() - token.when.getTime() > 2 * 24 * 60 * 60 * 1000) return finishWithMessage(res, 'Invalid or outdated token.'); | |
134 | + | |
135 | + finishWithMessage(res, 'Email has been verified.',"/"); | |
136 | + const idx = _.findIndex(user.emails, x => x.address === token.address); | |
137 | + | |
138 | + Users.update({_id: user._id}, {$set: { | |
139 | + [`emails.${idx}.verified`]: true, | |
140 | + }}); | |
141 | + | |
142 | + | |
143 | + | |
144 | + | |
145 | +// "services": { | |
146 | +// "password": { | |
147 | +// "bcrypt": "$2a$10$FqOvMve/MonERrLIOCJbruvS9iHoz5ixknGfm/ZAiOt9EiF43W4Z6" | |
148 | +// }, | |
149 | +// "email": { | |
150 | +// "verificationTokens": [ | |
151 | +// { | |
152 | +// "token": "05T-Ht_BzprDSAOVIYC-yUvDQ3Hp0wNym4eTx2g1VmI", | |
153 | +// "address": "krowa@druga.je", | |
154 | +// "when": new Date(1479502106631) | |
155 | +// } | |
156 | +// ] | |
157 | +// }, | |
158 | + | |
159 | + | |
160 | + | |
161 | + | |
162 | + | |
163 | + | |
164 | +}); | ... | ... |
imports/startup/server/accounts/creation.js
... | ... | @@ -1,35 +0,0 @@ |
1 | -import _ from 'lodash'; | |
2 | -import { Accounts } from 'meteor/accounts-base'; | |
3 | -import { SimpleSchema } from 'meteor/aldeed:simple-schema'; | |
4 | -import { ValidatedMethod } from 'meteor/mdg:validated-method'; | |
5 | - | |
6 | -import { Orgs } from '/imports/collections/orgs/index'; | |
7 | -import { Users } from '/imports/collections/users/index'; | |
8 | - | |
9 | - | |
10 | -Accounts.validateNewUser((user) => { | |
11 | - return !!user; | |
12 | -}); | |
13 | - | |
14 | -Accounts.onCreateUser((options, user) => { | |
15 | - console.log(options); | |
16 | - if(options.orgSlug){ | |
17 | - orgId = Orgs.insert({ | |
18 | - slug: options.orgSlug, | |
19 | - name: options.orgName, | |
20 | - setup: 1, | |
21 | - users: [{ | |
22 | - userId: user._id, | |
23 | - role: Users.roles.ADMIN, | |
24 | - }], | |
25 | - }); | |
26 | - } | |
27 | - console.log(user); | |
28 | - _.assign(user, { | |
29 | - role: Users.roles.ADMIN, | |
30 | - orgId: orgId, | |
31 | - firstName: options.profile.firstName, | |
32 | - lastName: options.profile.lastName, | |
33 | - }); | |
34 | - return user; | |
35 | -}); |
imports/startup/server/accounts/email-templates.js
... | ... | @@ -1,25 +0,0 @@ |
1 | -import { Accounts } from 'meteor/accounts-base'; | |
2 | - | |
3 | -const name = 'Application Name'; | |
4 | -const email = '<support@application.com>'; | |
5 | -const from = `${name} ${email}`; | |
6 | -const emailTemplates = Accounts.emailTemplates; | |
7 | - | |
8 | -emailTemplates.siteName = name; | |
9 | -emailTemplates.from = from; | |
10 | - | |
11 | -emailTemplates.resetPassword = { | |
12 | - subject() { | |
13 | - return `[${name}] Reset Your Password`; | |
14 | - }, | |
15 | - text(user, url) { | |
16 | - const userEmail = user.emails[0].address; | |
17 | - const urlWithoutHash = url.replace('#/', ''); | |
18 | - | |
19 | - return `A password reset has been requested for the account related to this | |
20 | - address (${userEmail}). To reset the password, visit the following link: | |
21 | - \n\n${urlWithoutHash}\n\n If you did not request this reset, please ignore | |
22 | - this email. If you feel something is wrong, please contact our support team: | |
23 | - ${email}.`; | |
24 | - }, | |
25 | -}; |
imports/startup/server/accounts/resetPassword.js
... | ... | @@ -1,31 +0,0 @@ |
1 | -import _ from 'lodash'; | |
2 | -import { Accounts } from 'meteor/accounts-base'; | |
3 | - | |
4 | - | |
5 | -Accounts.emailTemplates.resetPassword = { | |
6 | - subject() { | |
7 | - return '[Blok8] Reset Your Password'; | |
8 | - }, | |
9 | - text(user, url) { | |
10 | - const userEmail = user.emails[0].address; | |
11 | - const theUrl = Meteor.absoluteUrl(`?enter=reset&token=${_.last(url.split('/'))}`); | |
12 | - // const theUrl = decodeURI(`\u003D`); | |
13 | - | |
14 | - return ( | |
15 | -` | |
16 | -Hello, ${user.firstName}! | |
17 | - | |
18 | - | |
19 | -A password reset has been requested for the account related to this address. | |
20 | -To reset the password, visit the following link: | |
21 | - | |
22 | -${theUrl} | |
23 | - | |
24 | -If you did not request this reset, please ignore this email. | |
25 | - | |
26 | -` | |
27 | - ); | |
28 | - }, | |
29 | -}; | |
30 | - | |
31 | - |
imports/startup/server/accounts/verifyEmail.js
... | ... | @@ -1,29 +0,0 @@ |
1 | -import _ from 'lodash'; | |
2 | -import { Accounts } from 'meteor/accounts-base'; | |
3 | - | |
4 | -Accounts.config({ | |
5 | - sendVerificationEmail: true | |
6 | -}); | |
7 | - | |
8 | -Accounts.emailTemplates.verifyEmail = { | |
9 | - subject() { | |
10 | - return '[Blok8] Verify Your Email Address'; | |
11 | - }, | |
12 | - text(user, url) { | |
13 | - const theUrl = Meteor.absoluteUrl(`back/verifyEmail/${_.last(url.split('/'))}`); | |
14 | - | |
15 | - return ( | |
16 | -` | |
17 | -Hello, ${user.firstName}! | |
18 | - | |
19 | - | |
20 | -To verify your email address, visit the following link: | |
21 | - | |
22 | -${theUrl} | |
23 | - | |
24 | -If you did not request this verification, please ignore this email. | |
25 | - | |
26 | -` | |
27 | - ); | |
28 | - }, | |
29 | -}; |
imports/startup/server/api.js
imports/startup/server/browser-policy.js
... | ... | @@ -1,14 +0,0 @@ |
1 | -import { BrowserPolicy } from 'meteor/browser-policy-common'; | |
2 | -// e.g., BrowserPolicy.content.allowOriginForAll( 's3.amazonaws.com' ); | |
3 | -BrowserPolicy.content.allowFontOrigin("data:"); | |
4 | - | |
5 | -BrowserPolicy.content.disallowEval(); | |
6 | - | |
7 | -BrowserPolicy.framing.allowAll(); | |
8 | -BrowserPolicy.content.allowInlineScripts(); | |
9 | -BrowserPolicy.content.allowInlineStyles(); | |
10 | -BrowserPolicy.content.allowSameOriginForAll(); | |
11 | -BrowserPolicy.content.allowDataUrlForAll(); | |
12 | -BrowserPolicy.content.allowOriginForAll('*'); | |
13 | -BrowserPolicy.content.allowOriginForAll('http://*'); | |
14 | -BrowserPolicy.content.allowOriginForAll('https://*'); |
imports/startup/server/fixtures.js
... | ... | @@ -1,23 +0,0 @@ |
1 | -import { Meteor } from 'meteor/meteor'; | |
2 | -import { Roles } from 'meteor/alanning:roles'; | |
3 | -import { Accounts } from 'meteor/accounts-base'; | |
4 | - | |
5 | -if (!Meteor.isProduction) { | |
6 | - const users = [{ | |
7 | - email: 'admin@admin.com', | |
8 | - password: 'password', | |
9 | - profile: { | |
10 | - name: { first: 'Carl', last: 'Winslow' }, | |
11 | - }, | |
12 | - roles: ['admin'], | |
13 | - }]; | |
14 | - | |
15 | - users.forEach(({ email, password, profile, roles }) => { | |
16 | - const userExists = Meteor.users.findOne({ 'emails.address': email }); | |
17 | - | |
18 | - if (!userExists) { | |
19 | - const userId = Accounts.createUser({ email, password, profile }); | |
20 | - Roles.addUsersToRoles(userId, roles); | |
21 | - } | |
22 | - }); | |
23 | -} |
imports/startup/server/index.js
imports/ui/pages/Documents.js
... | ... | @@ -1,25 +0,0 @@ |
1 | -import React from 'react'; | |
2 | -import { Link } from 'react-router'; | |
3 | -import { Row, Col, Button } from 'react-bootstrap'; | |
4 | -import DocumentsList from '../containers/DocumentsList.js'; | |
5 | - | |
6 | -const Documents = () => ( | |
7 | - <div className="Documents"> | |
8 | - <Row> | |
9 | - <Col xs={ 12 }> | |
10 | - <div className="page-header clearfix"> | |
11 | - <h4 className="pull-left">Documents</h4> | |
12 | - <Link to="/documents/new"> | |
13 | - <Button | |
14 | - bsStyle="success" | |
15 | - className="pull-right" | |
16 | - >New Document</Button> | |
17 | - </Link> | |
18 | - </div> | |
19 | - <DocumentsList /> | |
20 | - </Col> | |
21 | - </Row> | |
22 | - </div> | |
23 | -); | |
24 | - | |
25 | -export default Documents; |
imports/ui/pages/EditDocument.js
... | ... | @@ -1,15 +0,0 @@ |
1 | -import React from 'react'; | |
2 | -import DocumentEditor from '../components/DocumentEditor.js'; | |
3 | - | |
4 | -const EditDocument = ({ doc }) => ( | |
5 | - <div className="EditDocument"> | |
6 | - <h4 className="page-header">Editing "{ doc.title }"</h4> | |
7 | - <DocumentEditor doc={ doc } /> | |
8 | - </div> | |
9 | -); | |
10 | - | |
11 | -EditDocument.propTypes = { | |
12 | - doc: React.PropTypes.object, | |
13 | -}; | |
14 | - | |
15 | -export default EditDocument; |
imports/ui/pages/Login.js
... | ... | @@ -1,54 +0,0 @@ |
1 | -import React from 'react'; | |
2 | -import { Link } from 'react-router'; | |
3 | -import { Row, Col, FormGroup, ControlLabel, FormControl, Button } from 'react-bootstrap'; | |
4 | -import handleLogin from '../../modules/login'; | |
5 | - | |
6 | -export default class Login extends React.Component { | |
7 | - componentDidMount() { | |
8 | - handleLogin({ component: this }); | |
9 | - } | |
10 | - | |
11 | - handleSubmit(event) { | |
12 | - event.preventDefault(); | |
13 | - } | |
14 | - | |
15 | - render() { | |
16 | - return ( | |
17 | - <div className="Login"> | |
18 | - <Row> | |
19 | - <Col xs={ 12 } sm={ 6 } md={ 4 }> | |
20 | - <h4 className="page-header">Login</h4> | |
21 | - <form | |
22 | - ref={ form => (this.loginForm = form) } | |
23 | - className="login" | |
24 | - onSubmit={ this.handleSubmit } | |
25 | - > | |
26 | - <FormGroup> | |
27 | - <ControlLabel>Email Address</ControlLabel> | |
28 | - <FormControl | |
29 | - type="email" | |
30 | - ref="emailAddress" | |
31 | - name="emailAddress" | |
32 | - placeholder="Email Address" | |
33 | - /> | |
34 | - </FormGroup> | |
35 | - <FormGroup> | |
36 | - <ControlLabel> | |
37 | - <span className="pull-left">Password</span> | |
38 | - <Link className="pull-right" to="/recover-password">Forgot Password?</Link> | |
39 | - </ControlLabel> | |
40 | - <FormControl | |
41 | - type="password" | |
42 | - ref="password" | |
43 | - name="password" | |
44 | - placeholder="Password" | |
45 | - /> | |
46 | - </FormGroup> | |
47 | - <Button type="submit" bsStyle="success">Login</Button> | |
48 | - </form> | |
49 | - </Col> | |
50 | - </Row> | |
51 | - </div> | |
52 | - ); | |
53 | - } | |
54 | -} |
imports/ui/pages/NewDocument.js
... | ... | @@ -1,11 +0,0 @@ |
1 | -import React from 'react'; | |
2 | -import DocumentEditor from '../components/DocumentEditor.js'; | |
3 | - | |
4 | -const NewDocument = () => ( | |
5 | - <div className="NewDocument"> | |
6 | - <h4 className="page-header">New Document</h4> | |
7 | - <DocumentEditor /> | |
8 | - </div> | |
9 | -); | |
10 | - | |
11 | -export default NewDocument; |
imports/ui/pages/RecoverPassword.js
... | ... | @@ -1,43 +0,0 @@ |
1 | -import React from 'react'; | |
2 | -import { Row, Col, Alert, FormGroup, FormControl, Button } from 'react-bootstrap'; | |
3 | -import handleRecoverPassword from '../../modules/recover-password'; | |
4 | - | |
5 | -export default class RecoverPassword extends React.Component { | |
6 | - componentDidMount() { | |
7 | - handleRecoverPassword({ component: this }); | |
8 | - } | |
9 | - | |
10 | - handleSubmit(event) { | |
11 | - event.preventDefault(); | |
12 | - } | |
13 | - | |
14 | - render() { | |
15 | - return ( | |
16 | - <div className="RecoverPassword"> | |
17 | - <Row> | |
18 | - <Col xs={ 12 } sm={ 6 } md={ 4 }> | |
19 | - <h4 className="page-header">Recover Password</h4> | |
20 | - <Alert bsStyle="info"> | |
21 | - Enter your email address below to receive a link to reset your password. | |
22 | - </Alert> | |
23 | - <form | |
24 | - ref={ form => (this.recoverPasswordForm = form) } | |
25 | - className="recover-password" | |
26 | - onSubmit={ this.handleSubmit } | |
27 | - > | |
28 | - <FormGroup> | |
29 | - <FormControl | |
30 | - type="email" | |
31 | - ref="emailAddress" | |
32 | - name="emailAddress" | |
33 | - placeholder="Email Address" | |
34 | - /> | |
35 | - </FormGroup> | |
36 | - <Button type="submit" bsStyle="success">Recover Password</Button> | |
37 | - </form> | |
38 | - </Col> | |
39 | - </Row> | |
40 | - </div> | |
41 | - ); | |
42 | - } | |
43 | -} |
imports/ui/pages/ResetPassword.js
... | ... | @@ -1,58 +0,0 @@ |
1 | -import React from 'react'; | |
2 | -import { Row, Col, Alert, FormGroup, ControlLabel, FormControl, Button } from 'react-bootstrap'; | |
3 | -import handleResetPassword from '../../modules/reset-password'; | |
4 | - | |
5 | -export default class ResetPassword extends React.Component { | |
6 | - componentDidMount() { | |
7 | - handleResetPassword({ component: this, token: this.props.params.token }); | |
8 | - } | |
9 | - | |
10 | - handleSubmit(event) { | |
11 | - event.preventDefault(); | |
12 | - } | |
13 | - | |
14 | - render() { | |
15 | - return ( | |
16 | - <div className="ResetPassword"> | |
17 | - <Row> | |
18 | - <Col xs={ 12 } sm={ 6 } md={ 4 }> | |
19 | - <h4 className="page-header">Reset Password</h4> | |
20 | - <Alert bsStyle="info"> | |
21 | - To reset your password, enter a new one below. You will be logged in | |
22 | - with your new password. | |
23 | - </Alert> | |
24 | - <form | |
25 | - ref={ form => (this.resetPasswordForm = form) } | |
26 | - className="reset-password" | |
27 | - onSubmit={ this.handleSubmit } | |
28 | - > | |
29 | - <FormGroup> | |
30 | - <ControlLabel>New Password</ControlLabel> | |
31 | - <FormControl | |
32 | - type="password" | |
33 | - ref="newPassword" | |
34 | - name="newPassword" | |
35 | - placeholder="New Password" | |
36 | - /> | |
37 | - </FormGroup> | |
38 | - <FormGroup> | |
39 | - <ControlLabel>Repeat New Password</ControlLabel> | |
40 | - <FormControl | |
41 | - type="password" | |
42 | - ref="repeatNewPassword" | |
43 | - name="repeatNewPassword" | |
44 | - placeholder="Repeat New Password" | |
45 | - /> | |
46 | - </FormGroup> | |
47 | - <Button type="submit" bsStyle="success">Reset Password & Login</Button> | |
48 | - </form> | |
49 | - </Col> | |
50 | - </Row> | |
51 | - </div> | |
52 | - ); | |
53 | - } | |
54 | -} | |
55 | - | |
56 | -ResetPassword.propTypes = { | |
57 | - params: React.PropTypes.object, | |
58 | -}; |
imports/ui/pages/ViewDocument.js
... | ... | @@ -1,43 +0,0 @@ |
1 | -import React from 'react'; | |
2 | -import { ButtonToolbar, ButtonGroup, Button } from 'react-bootstrap'; | |
3 | -import { browserHistory } from 'react-router'; | |
4 | -import { Bert } from 'meteor/themeteorchef:bert'; | |
5 | -import { removeDocument } from '../../api/documents/methods.js'; | |
6 | - | |
7 | -const handleEdit = (_id) => { | |
8 | - browserHistory.push(`/documents/${_id}/edit`); | |
9 | -} | |
10 | - | |
11 | -const handleRemove = (_id) => { | |
12 | - if (confirm('Are you sure? This is permanent!')) { | |
13 | - removeDocument.call({ _id }, (error) => { | |
14 | - if (error) { | |
15 | - Bert.alert(error.reason, 'danger'); | |
16 | - } else { | |
17 | - Bert.alert('Document deleted!', 'success'); | |
18 | - browserHistory.push('/documents'); | |
19 | - } | |
20 | - }); | |
21 | - } | |
22 | -}; | |
23 | - | |
24 | -const ViewDocument = ({ doc }) => ( | |
25 | - <div className="ViewDocument"> | |
26 | - <div className="page-header clearfix"> | |
27 | - <h4 className="pull-left">{ doc && doc.title }</h4> | |
28 | - <ButtonToolbar className="pull-right"> | |
29 | - <ButtonGroup bsSize="small"> | |
30 | - <Button onClick={ () => handleEdit(doc._id) }>Edit</Button> | |
31 | - <Button onClick={ () => handleRemove(doc._id) } className="text-danger">Delete</Button> | |
32 | - </ButtonGroup> | |
33 | - </ButtonToolbar> | |
34 | - </div> | |
35 | - { doc && doc.body } | |
36 | - </div> | |
37 | -); | |
38 | - | |
39 | -ViewDocument.propTypes = { | |
40 | - doc: React.PropTypes.object, | |
41 | -}; | |
42 | - | |
43 | -export default ViewDocument; |
server/main.js