Commit ff976df496e33f361138c9cde5a52d80a4634dea
1 parent
6a2e30e8d0
Exists in
master
added orgs publications
Showing
22 changed files
with
797 additions
and
60 deletions
Show diff stats
.meteor/.finished-upgraders
.meteor/packages
... | ... | @@ -6,21 +6,21 @@ |
6 | 6 | |
7 | 7 | meteor-base@1.0.4 # Packages every Meteor app needs to have |
8 | 8 | mobile-experience@1.0.4 # Packages for a great mobile UX |
9 | -mongo@1.1.14 # The database Meteor supports right now | |
9 | +mongo@1.1.15 # The database Meteor supports right now | |
10 | 10 | reactive-var@1.0.11 # Reactive variable for tracker |
11 | 11 | session@1.1.7 |
12 | -tracker@1.1.1 # Meteor's client-side reactive programming library | |
12 | +tracker@1.1.2 # Meteor's client-side reactive programming library | |
13 | 13 | |
14 | -standard-minifier-css@1.3.2 # CSS minifier run for production mode | |
15 | -standard-minifier-js@1.2.1 # JS minifier run for production mode | |
14 | +standard-minifier-css@1.3.3 # CSS minifier run for production mode | |
15 | +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 | -ecmascript@0.6.1 # Enable ECMAScript2015+ syntax in app code | |
17 | +ecmascript@0.6.3 # Enable ECMAScript2015+ syntax in app code | |
18 | 18 | |
19 | -accounts-password@1.3.3 | |
19 | +accounts-password@1.3.4 | |
20 | 20 | accounts-base@1.2.14 |
21 | -check@1.2.4 | |
21 | +check | |
22 | 22 | audit-argument-checks@1.0.7 |
23 | -browser-policy@1.0.9 | |
23 | +browser-policy@1.1.0 | |
24 | 24 | |
25 | 25 | fourseven:scss |
26 | 26 | aldeed:collection2 |
... | ... | @@ -33,4 +33,5 @@ xolvio:backdoor |
33 | 33 | mdg:validated-method |
34 | 34 | dburles:factory@1.0.0 |
35 | 35 | ddp-rate-limiter@1.0.6 |
36 | -shell-server@0.2.1 | |
36 | +shell-server@0.2.2 | |
37 | +aldeed:simple-schema | ... | ... |
.meteor/release
.meteor/versions
1 | 1 | accounts-base@1.2.14 |
2 | -accounts-password@1.3.3 | |
3 | -alanning:roles@1.2.15 | |
2 | +accounts-password@1.3.4 | |
3 | +alanning:roles@1.2.16 | |
4 | 4 | aldeed:collection2@2.10.0 |
5 | 5 | aldeed:collection2-core@1.2.0 |
6 | 6 | aldeed:schema-deny@1.1.0 |
... | ... | @@ -9,65 +9,65 @@ aldeed:simple-schema@1.5.3 |
9 | 9 | allow-deny@1.0.5 |
10 | 10 | audit-argument-checks@1.0.7 |
11 | 11 | autoupdate@1.3.12 |
12 | -babel-compiler@6.13.0 | |
12 | +babel-compiler@6.14.1 | |
13 | 13 | babel-runtime@1.0.1 |
14 | 14 | base64@1.0.10 |
15 | 15 | binary-heap@1.0.10 |
16 | -blaze@2.2.0 | |
16 | +blaze@2.3.0 | |
17 | 17 | blaze-tools@1.0.10 |
18 | 18 | boilerplate-generator@1.0.11 |
19 | -browser-policy@1.0.9 | |
19 | +browser-policy@1.1.0 | |
20 | 20 | browser-policy-common@1.0.11 |
21 | -browser-policy-content@1.0.12 | |
22 | -browser-policy-framing@1.0.12 | |
21 | +browser-policy-content@1.1.0 | |
22 | +browser-policy-framing@1.1.0 | |
23 | 23 | caching-compiler@1.1.9 |
24 | -caching-html-compiler@1.0.7 | |
24 | +caching-html-compiler@1.1.0 | |
25 | 25 | callback-hook@1.0.10 |
26 | -check@1.2.4 | |
27 | -coffeescript@1.11.1_4 | |
26 | +check@1.2.5 | |
27 | +coffeescript@1.12.3_1 | |
28 | 28 | dburles:factory@1.1.0 |
29 | 29 | ddp@1.2.5 |
30 | -ddp-client@1.3.2 | |
30 | +ddp-client@1.3.3 | |
31 | 31 | ddp-common@1.2.8 |
32 | 32 | ddp-rate-limiter@1.0.6 |
33 | -ddp-server@1.3.12 | |
33 | +ddp-server@1.3.13 | |
34 | 34 | deps@1.0.12 |
35 | 35 | diff-sequence@1.0.7 |
36 | -ecmascript@0.6.1 | |
36 | +ecmascript@0.6.3 | |
37 | 37 | ecmascript-runtime@0.3.15 |
38 | 38 | ejson@1.0.13 |
39 | 39 | email@1.1.18 |
40 | 40 | es5-shim@4.6.15 |
41 | 41 | fastclick@1.0.13 |
42 | 42 | fortawesome:fontawesome@4.7.0 |
43 | -fourseven:scss@3.10.1 | |
43 | +fourseven:scss@3.13.0 | |
44 | 44 | geojson-utils@1.0.10 |
45 | 45 | hot-code-push@1.0.4 |
46 | 46 | html-tools@1.0.11 |
47 | 47 | htmljs@1.0.11 |
48 | -http@1.2.10 | |
48 | +http@1.2.11 | |
49 | 49 | id-map@1.0.9 |
50 | 50 | jquery@1.11.10 |
51 | -launch-screen@1.1.0 | |
51 | +launch-screen@1.1.1 | |
52 | 52 | livedata@1.0.18 |
53 | 53 | localstorage@1.0.12 |
54 | -logging@1.1.16 | |
54 | +logging@1.1.17 | |
55 | 55 | mdg:validated-method@1.1.0 |
56 | 56 | mdg:validation-error@0.5.1 |
57 | -meteor@1.6.0 | |
57 | +meteor@1.6.1 | |
58 | 58 | meteor-base@1.0.4 |
59 | -minifier-css@1.2.15 | |
60 | -minifier-js@1.2.15 | |
61 | -minimongo@1.0.19 | |
59 | +minifier-css@1.2.16 | |
60 | +minifier-js@1.2.18 | |
61 | +minimongo@1.0.20 | |
62 | 62 | mobile-experience@1.0.4 |
63 | -mobile-status-bar@1.0.13 | |
64 | -modules@0.7.7 | |
65 | -modules-runtime@0.7.7 | |
66 | -mongo@1.1.14 | |
63 | +mobile-status-bar@1.0.14 | |
64 | +modules@0.7.9 | |
65 | +modules-runtime@0.7.9 | |
66 | +mongo@1.1.15 | |
67 | 67 | mongo-id@1.0.6 |
68 | 68 | npm-bcrypt@0.9.2 |
69 | -npm-mongo@2.2.11_2 | |
70 | -observe-sequence@1.0.14 | |
69 | +npm-mongo@2.2.16_1 | |
70 | +observe-sequence@1.0.15 | |
71 | 71 | ordered-dict@1.0.9 |
72 | 72 | practicalmeteor:chai@2.1.0_1 |
73 | 73 | practicalmeteor:loglevel@1.2.0_2 |
... | ... | @@ -86,24 +86,24 @@ routepolicy@1.0.12 |
86 | 86 | service-configuration@1.0.11 |
87 | 87 | session@1.1.7 |
88 | 88 | sha@1.0.9 |
89 | -shell-server@0.2.1 | |
89 | +shell-server@0.2.3 | |
90 | 90 | spacebars@1.0.13 |
91 | -spacebars-compiler@1.0.13 | |
91 | +spacebars-compiler@1.1.0 | |
92 | 92 | srp@1.0.10 |
93 | -standard-minifier-css@1.3.2 | |
94 | -standard-minifier-js@1.2.1 | |
95 | -static-html@1.1.13 | |
96 | -templating@1.2.15 | |
97 | -templating-compiler@1.2.15 | |
98 | -templating-runtime@1.2.15 | |
99 | -templating-tools@1.0.5 | |
93 | +standard-minifier-css@1.3.4 | |
94 | +standard-minifier-js@1.2.3 | |
95 | +static-html@1.2.0 | |
96 | +templating@1.3.0 | |
97 | +templating-compiler@1.3.0 | |
98 | +templating-runtime@1.3.0 | |
99 | +templating-tools@1.1.0 | |
100 | 100 | themeteorchef:bert@2.1.1 |
101 | 101 | tmeasday:test-reporter-helpers@0.2.1 |
102 | -tracker@1.1.1 | |
102 | +tracker@1.1.2 | |
103 | 103 | ui@1.0.12 |
104 | 104 | underscore@1.0.10 |
105 | -url@1.0.11 | |
106 | -webapp@1.3.12 | |
105 | +url@1.1.0 | |
106 | +webapp@1.3.13 | |
107 | 107 | webapp-hashing@1.0.9 |
108 | 108 | xolvio:backdoor@0.2.1 |
109 | 109 | xolvio:cleaner@0.3.1 | ... | ... |
imports/client/components/ActionButton.js
... | ... | @@ -0,0 +1,41 @@ |
1 | +// import { ActionButton } from '/imports/client/components/actionButton/actionButton'; | |
2 | +import _ from 'lodash'; | |
3 | +import React, { Component } from 'react'; | |
4 | +import { Loading } from '/imports/client/components/Loading'; | |
5 | + | |
6 | +import classNames from 'classnames'; | |
7 | + | |
8 | +/* | |
9 | + <ActionButton | |
10 | + loading = {this.state.loading} | |
11 | + onAction = {() => this.onSend()} | |
12 | + // error = {this.state.error} | |
13 | + > | |
14 | + Send invite | |
15 | + </ActionButton> | |
16 | +*/ | |
17 | + | |
18 | +export class ActionButton extends Component { | |
19 | + | |
20 | + | |
21 | + render() { | |
22 | + if(this.props.loading) { | |
23 | + return ( | |
24 | + <div className = {this.props.className || ""}> | |
25 | + <Loading/> | |
26 | + </div> | |
27 | + ); | |
28 | + } | |
29 | + | |
30 | + return ( | |
31 | + <div | |
32 | + className = {this.props.className || ""} | |
33 | + onClick = {() => (this.props.onAction && this.props.onAction())} | |
34 | + > | |
35 | + {this.props.children} | |
36 | + </div> | |
37 | + ); | |
38 | + }; | |
39 | +}; | |
40 | + | |
41 | + | ... | ... |
imports/client/components/Avatar.js
... | ... | @@ -0,0 +1,30 @@ |
1 | +// import { Avatar } from '/imports/client/components/Avatar'; | |
2 | +import _ from 'lodash'; | |
3 | +import React, { Component } from 'react'; | |
4 | +import classNames from 'classnames'; | |
5 | + | |
6 | + | |
7 | + | |
8 | +export class Avatar extends Component { | |
9 | + | |
10 | + | |
11 | + render() { | |
12 | + const user = this.props.user; | |
13 | + | |
14 | + return ( | |
15 | + <div | |
16 | + className = {classNames( | |
17 | + "avatar-box", | |
18 | + this.props.small && "avatar-small" | |
19 | + )} | |
20 | + style={_.assign({ | |
21 | + backgroundImage: `url(${user.getAvatarUrl()})`, | |
22 | + width: this.props.size + 'px', | |
23 | + height: this.props.size + 'px', | |
24 | + }, this.props.style || {})} | |
25 | + /> | |
26 | + ); | |
27 | + }; | |
28 | +}; | |
29 | + | |
30 | + | ... | ... |
imports/client/components/Icon.js
... | ... | @@ -0,0 +1,15 @@ |
1 | +import React, { Component } from 'react'; | |
2 | + | |
3 | +export class Icon extends Component { | |
4 | + render() { | |
5 | + if(this.props.fa) | |
6 | + return <i className = {"icon icon-fa icon-fa-" + this.props.fa}></i> | |
7 | + if(this.props.ion) | |
8 | + return <i className = {"icon icon-ion icon-ion-" + this.props.ion}></i> | |
9 | + if(this.props.material) | |
10 | + return <i className = {"icon icon-material icon-material-" + this.props.material}></i> | |
11 | + if(this.props.simple) | |
12 | + return <i className = {"icon icon-simple icon-" + this.props.simple}></i> | |
13 | + return <i></i> | |
14 | + }; | |
15 | +}; | ... | ... |
imports/client/components/Loading.js
... | ... | @@ -0,0 +1,44 @@ |
1 | +// import { Loading } from '/imports/client/components/Loading'; | |
2 | +import React from 'react'; | |
3 | + | |
4 | + | |
5 | + | |
6 | +export class Loading extends React.Component { | |
7 | + | |
8 | + render() { | |
9 | + return ( | |
10 | + <div className = "loading-box"> | |
11 | + <div className = "loading-content"> | |
12 | + <svg | |
13 | + version = "1.1" | |
14 | + className = "loading-icon" | |
15 | + xmlns = "http://www.w3.org/2000/svg" | |
16 | + x = "0px" | |
17 | + y = "0px" | |
18 | + width = "40px" | |
19 | + height = "40px" | |
20 | + viewBox = "0 0 40 40" | |
21 | + enableBackground = "new 0 0 40 40" | |
22 | + > | |
23 | + <path | |
24 | + opacity = "1.0" | |
25 | + fill = "#fff" | |
26 | + d = "M20.201,5.169c-8.254,0-14.946,6.692-14.946,14.946c0,8.255,6.692,14.946, | |
27 | + 14.946,14.946s14.946-6.691,14.946-14.946C35.146,11.861,28.455,5.169,20.201, | |
28 | + 5.169z M20.201,31.749c-6.425,0-11.634-5.208-11.634-11.634c0-6.425, | |
29 | + 5.209-11.634,11.634-11.634c6.425,0,11.633,5.209,11.633,11.634C31.834, | |
30 | + 26.541,26.626,31.749,20.201,31.749z" | |
31 | + /> | |
32 | + <path | |
33 | + fill = "#0080ff" | |
34 | + d = "M26.013,10.047l1.654-2.866c-2.198-1.272-4.743-2.012-7.466-2.012h0v3.312h0 | |
35 | + C22.32,8.481,24.301,9.057,26.013,10.047z" | |
36 | + /> | |
37 | + </svg> | |
38 | + </div> | |
39 | + </div> | |
40 | + ); | |
41 | + }; | |
42 | + | |
43 | +}; | |
44 | + | ... | ... |
imports/client/components/Logic.js
... | ... | @@ -0,0 +1,34 @@ |
1 | +import _ from 'lodash'; | |
2 | +import React, { Component } from 'react'; | |
3 | + | |
4 | + | |
5 | +const instance = (value) => ( | |
6 | + _.isFunction(value) ? value() : (value || null) | |
7 | +); | |
8 | + | |
9 | + | |
10 | +export class If extends Component { | |
11 | + | |
12 | + render() { | |
13 | + return this.props.if ? instance(this.props.then) : instance(this.props.else); | |
14 | + }; | |
15 | + | |
16 | +}; | |
17 | + | |
18 | + | |
19 | +export class Case extends Component { | |
20 | + | |
21 | + render() { | |
22 | + const val = this.props.switch; | |
23 | + for(let i = 0; i < 999; ++i) { | |
24 | + if(this.props['case' + i] === undefined) return instance(this.props.else); | |
25 | + if(this.props['case' + i] === val) return instance(this.props['then' + i]); | |
26 | + } | |
27 | + return null; | |
28 | + }; | |
29 | + | |
30 | +}; | |
31 | + | |
32 | + | |
33 | + | |
34 | + | ... | ... |
imports/client/components/VerificationNeeded.js
... | ... | @@ -0,0 +1,20 @@ |
1 | + | |
2 | +import React, { Component } from 'react'; | |
3 | + | |
4 | +export class VerificationNeeded extends Component { | |
5 | + | |
6 | + render() { | |
7 | + if(! this.props.verify) { | |
8 | + return ( | |
9 | + <div> | |
10 | + {this.props.message} | |
11 | + </div> | |
12 | + ); | |
13 | + } | |
14 | + | |
15 | + return this.props.children; | |
16 | + }; | |
17 | + | |
18 | +}; | |
19 | + | |
20 | + | ... | ... |
imports/client/components/validationMethods.js
... | ... | @@ -0,0 +1,69 @@ |
1 | +export default class Validation{ | |
2 | + | |
3 | + validateEmail (value) { | |
4 | + // regex from http://stackoverflow.com/questions/46155/validate-email-address-in-javascript | |
5 | + var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; | |
6 | + return re.test(value); | |
7 | + }; | |
8 | + | |
9 | + | |
10 | + noSpecialChars(str){ | |
11 | + str = String(str); | |
12 | + return !/[~`!#$%\^&*+=\-\[\]\\';,/{}|\\":<>\?]/g.test(str); | |
13 | + } | |
14 | + | |
15 | + noQwertysAllowed (str){ | |
16 | + str = String(str); | |
17 | + str = str.toLowerCase(); | |
18 | + if(str.toLowerCase().IndexOf("qwerty") >-1){ | |
19 | + return false; | |
20 | + } else{ | |
21 | + return true; | |
22 | + } | |
23 | + } | |
24 | + | |
25 | + passwordValidation (str){ | |
26 | + str = String(str); | |
27 | + if(str.length <6){ | |
28 | + return false; | |
29 | + } else{ | |
30 | + return true; | |
31 | + } | |
32 | + } | |
33 | + | |
34 | + isNumberOnly(str){ | |
35 | + str = String(str); | |
36 | + if(!/^\d+$/.test(str)){ | |
37 | + return false; | |
38 | + }else { | |
39 | + return true; | |
40 | + } | |
41 | + } | |
42 | + | |
43 | + isValidACN(str){ | |
44 | + str = String(str); | |
45 | + console.log(str); | |
46 | + if(/^\d+$/.test(str) && str.length ==9){ | |
47 | + return true; | |
48 | + } else{ | |
49 | + return false; | |
50 | + } | |
51 | + } | |
52 | + containsNumbers(str){ | |
53 | + str = String(str); | |
54 | + if(/\d/g.test(str)){ | |
55 | + return true; | |
56 | + }else{ | |
57 | + return false; | |
58 | + } | |
59 | + } | |
60 | + | |
61 | + isValidShortCode(str){ | |
62 | + str = String(str); | |
63 | + if(containsNoSpecialCharacters(str) && !containsNumbers(str) && str.length <5){ | |
64 | + return true; | |
65 | + } else{ | |
66 | + return false; | |
67 | + } | |
68 | + } | |
69 | +}; | ... | ... |
imports/collections/orgs/index.js
... | ... | @@ -0,0 +1,113 @@ |
1 | +// import { Orgs } from '/imports/collections/orgs/index'; | |
2 | + | |
3 | +import _ from 'lodash'; | |
4 | +import { Mongo } from 'meteor/mongo'; | |
5 | +import { SimpleSchema } from 'meteor/aldeed:simple-schema'; | |
6 | + | |
7 | +import { Users } from '/imports/collections/users/index'; | |
8 | + | |
9 | +class Org { | |
10 | + constructor(doc) { | |
11 | + _.assign(this, doc); | |
12 | + }; | |
13 | + | |
14 | + getUserIds() { | |
15 | + return _.filter(_.map(this.users, 'userId')); | |
16 | + }; | |
17 | + | |
18 | + getInvitationIds() { | |
19 | + return _.filter(_.map(this.users, 'invitationId')); | |
20 | + }; | |
21 | + | |
22 | + areDetailsDone() { | |
23 | + return ( | |
24 | + this.name && this.name.length && | |
25 | + this.shortCode && this.shortCode.length && | |
26 | + this.acn && this.acn.length | |
27 | + ); | |
28 | + }; | |
29 | + | |
30 | + ifCurrentUserIsAdmin(){ | |
31 | + const user = Users.current(); | |
32 | + if(!user) return null; | |
33 | + for(let i = 0; i < this.users.length; ++i) { | |
34 | + if( | |
35 | + (this.users[i].role == "SECRETARY") | |
36 | + && this.users[i].userId == user._id | |
37 | + ) { | |
38 | + return true; | |
39 | + } | |
40 | + } | |
41 | + return false; | |
42 | + } | |
43 | + | |
44 | + | |
45 | +}; | |
46 | +export { Org }; | |
47 | + | |
48 | +class OrgsCollection extends Mongo.Collection { | |
49 | + insert(item, callback) { | |
50 | + _.assign(item, { | |
51 | + createdAt: new Date().getTime(), | |
52 | + }); | |
53 | + return super.insert(item, callback); | |
54 | + }; | |
55 | +}; | |
56 | + | |
57 | +export const Orgs = new OrgsCollection('Orgs', { | |
58 | + transform: (item) => { | |
59 | + return new Org(item); | |
60 | + }, | |
61 | +}); | |
62 | + | |
63 | +_.assign(Orgs, { | |
64 | + allOrgsCurrentUser: () => { | |
65 | + const user = Users.current(); | |
66 | + if(!user) return null; | |
67 | + return Orgs.find({'users.userId': user._id}); | |
68 | + }, | |
69 | + current: () => { | |
70 | + const user = Users.current(); | |
71 | + if(!user) return null; | |
72 | + return Orgs.findOne({_id: user.orgId}); | |
73 | + }, | |
74 | + currentOrgUsers: () => { | |
75 | + const OrgsArr = Orgs.current(); | |
76 | + if(!OrgsArr) return null; | |
77 | + return OrgsArr.users; | |
78 | + }, | |
79 | + | |
80 | +}); | |
81 | + | |
82 | +Orgs.deny({ | |
83 | + insert() { return true; }, | |
84 | + update() { return true; }, | |
85 | + remove() { return true; }, | |
86 | +}); | |
87 | + | |
88 | +Orgs.schema = new SimpleSchema({ | |
89 | + | |
90 | + name: { type: String, }, | |
91 | + slug: { type: String, optional: true}, | |
92 | + address: { type: String, optional: true}, | |
93 | + users: { | |
94 | + type: [new SimpleSchema({ | |
95 | + userId: { type: String, optional: true}, | |
96 | + invitationId: { type: String, optional: true}, | |
97 | + role: { type: String, }, | |
98 | + email: { type: String, optional: true}, | |
99 | + })], | |
100 | + }, | |
101 | + createdAt: { type: Date, autoValue: function(){return new Date();}}, | |
102 | + | |
103 | +}); | |
104 | + | |
105 | + | |
106 | + | |
107 | +Orgs.attachSchema(Orgs.schema); | |
108 | + | |
109 | +Orgs.publicFields = { | |
110 | + name: 1, | |
111 | + slug: 1, | |
112 | + createdAt: 1, | |
113 | +}; | ... | ... |
imports/collections/orgs/publications.js
... | ... | @@ -0,0 +1,17 @@ |
1 | +import { Meteor } from 'meteor/meteor'; | |
2 | +import { check, Match } from 'meteor/check' | |
3 | + | |
4 | +import { Orgs } from '/imports/collections/orgs/index'; | |
5 | +import { Users } from '/imports/collections/users/index'; | |
6 | + | |
7 | +Meteor.publish('orgs.current', function () { | |
8 | + const user = Users.findOne({_id: this.userId}); | |
9 | + if(!user) return []; | |
10 | + | |
11 | + return Orgs.find({_id: user.orgId}); | |
12 | +}); | |
13 | + | |
14 | +Meteor.publish('allOrgsSlug', function () { | |
15 | + console.log(Orgs.find({},{fields: Orgs.publicFields}).fetch()); | |
16 | + return Orgs.find({},{fields: Orgs.publicFields}); | |
17 | +}); | ... | ... |
imports/collections/users/index.js
... | ... | @@ -0,0 +1,207 @@ |
1 | +// import { Users } from '/imports/collections/users/index'; | |
2 | +// import { Users } from '/imports/collections/users/index'; | |
3 | + | |
4 | +import _ from 'lodash'; | |
5 | +import { Meteor } from 'meteor/meteor'; | |
6 | +import { Mongo } from 'meteor/mongo'; | |
7 | +import { SimpleSchema } from 'meteor/aldeed:simple-schema'; | |
8 | + | |
9 | +import { Orgs } from '/imports/collections/orgs/index'; | |
10 | + | |
11 | +class User { | |
12 | + | |
13 | + constructor(doc) { | |
14 | + _.assign(this, doc); | |
15 | + }; | |
16 | + | |
17 | + isEmailVerified() { | |
18 | + return !! _.find(this.emails, x => x.verified); | |
19 | + }; | |
20 | + | |
21 | + isPhoneVerified() { | |
22 | + return !! _.find(this.phones, x => x.verified); | |
23 | + }; | |
24 | + | |
25 | + isIdentityVerified() { | |
26 | + return !! _.find(this.identities, x => x.verified); | |
27 | + }; | |
28 | + | |
29 | + getRole() { | |
30 | + const org = Orgs.findOne({_id: this.orgId}); | |
31 | + if(!org) return null; | |
32 | + const connection = _.find(org.users, {userId: this._id}); | |
33 | + if(!connection) return null; | |
34 | + return connection.role; | |
35 | + }; | |
36 | + | |
37 | + getFullName() { | |
38 | + return `${this.firstName} ${this.lastName}`; | |
39 | + }; | |
40 | + getFirstName() { | |
41 | + return `${this.firstName}`; | |
42 | + }; | |
43 | + getLastName() { | |
44 | + return `${this.lastName}`; | |
45 | + }; | |
46 | + getEmail() { | |
47 | + return `${this.emails[0].address}`; | |
48 | + }; | |
49 | + getOrganization(){ | |
50 | + return `${this.orgId}`; | |
51 | + }; | |
52 | + | |
53 | + getNameByUserId(userId){ | |
54 | + var user = Users.findOne({"_id":userId}); | |
55 | + return user.firstName + " " + user.lastName; | |
56 | + } | |
57 | + getAvatarUrl() { | |
58 | + let random = parseInt(this._id.substr(0, 4), 36); | |
59 | + random = '' + (random % 32); | |
60 | + while(random.length < 3) random = '0' + random; | |
61 | + return `/files/random/random${ random }.png`; | |
62 | + }; | |
63 | +}; | |
64 | + | |
65 | +export { User }; | |
66 | + | |
67 | + | |
68 | +const transform = function(doc) { | |
69 | + return new User(doc); | |
70 | +}; | |
71 | + | |
72 | +export const Users = { | |
73 | + | |
74 | + current: function() { | |
75 | + return Meteor.users.findOne({_id: Meteor.userId()}, _.extend({transform: transform})); | |
76 | + }, | |
77 | + | |
78 | + find: function(selector, options) { | |
79 | + return Meteor.users.find(selector || {}, _.extend({transform: transform}, options)); | |
80 | + }, | |
81 | + | |
82 | + findOne: function(selector, options) { | |
83 | + return Meteor.users.findOne(selector || {}, _.extend({transform: transform}, options)); | |
84 | + }, | |
85 | + | |
86 | + insert: _.bind(Meteor.users.insert, Meteor.users), | |
87 | + update: _.bind(Meteor.users.update, Meteor.users), | |
88 | + remove: _.bind(Meteor.users.remove, Meteor.users), | |
89 | + allow: _.bind(Meteor.users.allow, Meteor.users), | |
90 | + deny: _.bind(Meteor.users.deny, Meteor.users), | |
91 | + attachSchema: _.bind(Meteor.users.attachSchema, Meteor.users), | |
92 | + | |
93 | +}; | |
94 | + | |
95 | + | |
96 | +Users.deny({ | |
97 | + insert() { return true; }, | |
98 | + update() { return true; }, | |
99 | + remove() { return true; }, | |
100 | +}); | |
101 | + | |
102 | +Users.roles = { | |
103 | + 'STUDENT': 'STUDENT', | |
104 | + 'TEACHER': 'TEACHER', | |
105 | + 'ADMIN': 'ADMIN', | |
106 | + 'PARENT': 'PARENT' | |
107 | +}; | |
108 | + | |
109 | + | |
110 | +Users.schema = new SimpleSchema({ | |
111 | + roles: { type: String }, | |
112 | + orgId: { type: String }, | |
113 | + admissionId: { type: String }, | |
114 | + enrollmentDate: { type: String, optional: true }, | |
115 | + address: { type: String, optional: true }, | |
116 | + prefix: { type: String, optional: true }, | |
117 | + firstName: { type: String, optional: true }, | |
118 | + middlename: { type: String, optional: true }, | |
119 | + lastName: { type: String, optional: true }, | |
120 | + gender: { type: String, optional: true }, | |
121 | + dob: { type: String, optional: true }, | |
122 | + rollNo: { type: String, optional: true }, | |
123 | + class: { type: String, optional: true }, | |
124 | + section: { type: String, optional: true }, | |
125 | + bloodGroup: { type: String, optional: true }, | |
126 | + community: { type: String, optional: true }, | |
127 | + nationality: { type: String, optional: true }, | |
128 | + motherTongue: { type: String, optional: true }, | |
129 | + motherTongue: { type: String, optional: true }, | |
130 | + religion: { type: String, optional: true }, | |
131 | + permanentAddress: { | |
132 | + type: new SimpleSchema({ | |
133 | + home: { type: String, optional: true }, | |
134 | + street: { type: String, optional: true }, | |
135 | + town: { type: String, optional: true }, | |
136 | + city: { type: String, optional: true }, | |
137 | + state: { type: String, optional: true }, | |
138 | + zip: { type: String, optional: true }, | |
139 | + }), | |
140 | + }, | |
141 | + parent: { | |
142 | + type: [new SimpleSchema({ | |
143 | + id: { type: String, }, | |
144 | + relatinship: { type: Boolean, }, | |
145 | + })], | |
146 | + minCount: 1, | |
147 | + }, | |
148 | + emails: { | |
149 | + type: [new SimpleSchema({ | |
150 | + address: { type: String, }, | |
151 | + verified: { type: Boolean, }, | |
152 | + })], | |
153 | + }, | |
154 | + prevInstitute: { | |
155 | + type: [new SimpleSchema({ | |
156 | + name: { type: String, }, | |
157 | + fromYear: { type: Boolean, }, | |
158 | + toYear: { type: Boolean, }, | |
159 | + ydId: { type: Boolean, }, | |
160 | + })], | |
161 | + optional: true | |
162 | + }, | |
163 | + | |
164 | + phones: { | |
165 | + type: [new SimpleSchema({ | |
166 | + country: { type: String, }, | |
167 | + prefix: { type: String, }, | |
168 | + number: { type: String, }, | |
169 | + verified: { type: Boolean, }, | |
170 | + })], | |
171 | + optional: true | |
172 | + }, | |
173 | + | |
174 | + services: { | |
175 | + type: Object, | |
176 | + optional: true, | |
177 | + blackbox: true, | |
178 | + }, | |
179 | + | |
180 | + isMetaUser: { type: Boolean, optional: true }, | |
181 | + | |
182 | + createdAt: { type: Date, autoValue: function(){return new Date();}} | |
183 | + | |
184 | +}); | |
185 | + | |
186 | +Users.attachSchema(Users.schema); | |
187 | + | |
188 | +Users.privateFields = { | |
189 | + orgId: 1, | |
190 | + address: 1, | |
191 | + | |
192 | + firstName: 1, | |
193 | + lastName: 1, | |
194 | + emails: 1, | |
195 | + phones: 1, | |
196 | + | |
197 | + isMetaUser: 1, | |
198 | + createdAt: 1, | |
199 | +}; | |
200 | + | |
201 | +Users.publicFields = { | |
202 | + firstName: 1, | |
203 | + lastName: 1, | |
204 | + emails: 1, | |
205 | + | |
206 | + createdAt: 1, | |
207 | +}; | ... | ... |
imports/modules/signup.js
1 | 1 | /* eslint-disable no-undef */ |
2 | 2 | |
3 | -import { browserHistory } from 'react-router'; | |
4 | -import { Accounts } from 'meteor/accounts-base'; | |
5 | -import { Bert } from 'meteor/themeteorchef:bert'; | |
6 | -import './validation.js'; | |
3 | +import { browserHistory } from 'react-router'; | |
4 | +import { Accounts } from 'meteor/accounts-base'; | |
5 | +import { Bert } from 'meteor/themeteorchef:bert'; | |
6 | +import { Loading } from '/imports/client/components/Loading'; | |
7 | +import './validation.js'; | |
7 | 8 | |
8 | 9 | let component; |
9 | 10 | ... | ... |
imports/server/accounts/creation.js
... | ... | @@ -0,0 +1,24 @@ |
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 | +import { Orgs } from '/imports/collections/orgs/index'; | |
6 | +import { Users } from '/imports/collections/users/index'; | |
7 | + | |
8 | + | |
9 | + | |
10 | +Accounts.validateNewUser((user) => { | |
11 | + return !!user; | |
12 | +}); | |
13 | + | |
14 | +Accounts.onCreateUser((options, user) => { | |
15 | + console.log(options); | |
16 | + _.assign(user, { | |
17 | + firstName: options.profile.firstName, | |
18 | + lastName: options.profile.lastName, | |
19 | + phones: [], | |
20 | + identities: [], | |
21 | + createdAt: new Date().getTime(), | |
22 | + }); | |
23 | + return user; | |
24 | +}); | ... | ... |
imports/startup/client/routes.js
... | ... | @@ -24,10 +24,18 @@ const authenticate = (nextState, replace) => { |
24 | 24 | }); |
25 | 25 | } |
26 | 26 | }; |
27 | +const detectOrg = () => { | |
28 | + var hostnameArray = document.location.hostname.split( "." ); | |
29 | + if(hostnameArray[1]=='localhost'){ | |
30 | + orgSlug = hostnameArray[0]; | |
31 | + }else{ | |
32 | + orgSlug = hostnameArray[0]; | |
33 | + } | |
34 | + | |
35 | +} | |
36 | + | |
27 | 37 | |
28 | 38 | Meteor.startup(() => { |
29 | - var hostnameArray = document.location.hostname.split( "." ); | |
30 | - | |
31 | 39 | |
32 | 40 | render( |
33 | 41 | <Router history={ browserHistory }> | ... | ... |
imports/startup/server/accounts/creation.js
... | ... | @@ -0,0 +1,14 @@ |
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 | + | |
7 | + | |
8 | +Accounts.validateNewUser((user) => { | |
9 | + return !!user; | |
10 | +}); | |
11 | + | |
12 | +Accounts.onCreateUser((options, user) => { | |
13 | + console.log(options); | |
14 | +}); | ... | ... |
imports/startup/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/startup/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 '[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/index.js
imports/ui/pages/Signup.js
1 | -import React from 'react'; | |
2 | -import { Link } from 'react-router'; | |
3 | -import { Row, Col, FormGroup, ControlLabel, FormControl, Button } from 'react-bootstrap'; | |
4 | -import handleSignup from '../../modules/signup'; | |
1 | +import React from 'react'; | |
2 | +import { Link } from 'react-router'; | |
3 | +import { Row, Col, FormGroup, | |
4 | + ControlLabel, FormControl, | |
5 | + InputGroup, Button } from 'react-bootstrap'; | |
6 | +import handleSignup from '../../modules/signup'; | |
7 | +import { Orgs } from '/imports/collections/orgs/index'; | |
5 | 8 | |
6 | 9 | export default class Signup extends React.Component { |
10 | + constructor(props) { | |
11 | + super(props); | |
12 | + this.state = { | |
13 | + newSlug: "" | |
14 | + }; | |
15 | + } | |
16 | + componentWillMount(){ | |
17 | + Meteor.subscribe('allOrgsSlug'); | |
18 | + } | |
19 | + | |
7 | 20 | componentDidMount() { |
8 | 21 | handleSignup({ component: this }); |
9 | 22 | } |
... | ... | @@ -11,7 +24,10 @@ export default class Signup extends React.Component { |
11 | 24 | handleSubmit(event) { |
12 | 25 | event.preventDefault(); |
13 | 26 | } |
14 | - | |
27 | + checkExistingOrgSlug(e) { | |
28 | + searchOrg = Orgs.find({}).fetch(); | |
29 | + console.log(searchOrg); | |
30 | + } | |
15 | 31 | render() { |
16 | 32 | return ( |
17 | 33 | <div className="Signup"> |
... | ... | @@ -22,6 +38,23 @@ export default class Signup extends React.Component { |
22 | 38 | ref={ form => (this.signupForm = form) } |
23 | 39 | onSubmit={ this.handleSubmit } |
24 | 40 | > |
41 | + <Row> | |
42 | + <Col xs={ 12 } sm={ 12 }> | |
43 | + <FormGroup controlId="formValidationError2"> | |
44 | + <ControlLabel>Organisation name</ControlLabel> | |
45 | + <InputGroup> | |
46 | + <FormControl | |
47 | + type="text" | |
48 | + ref="orgSlug" | |
49 | + name="orgSlug" | |
50 | + placeholder="School Name" | |
51 | + onChange = {(e) => this.checkExistingOrgSlug(e)} | |
52 | + /> | |
53 | + <InputGroup.Addon>@yd.com</InputGroup.Addon> | |
54 | + </InputGroup> | |
55 | + </FormGroup> | |
56 | + </Col> | |
57 | + </Row> | |
25 | 58 | <Row> |
26 | 59 | <Col xs={ 6 } sm={ 6 }> |
27 | 60 | <FormGroup> | ... | ... |