summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.eslintrc.json1
-rw-r--r--client/components/cards/labels.js4
-rwxr-xr-xi18n/en.i18n.json3
-rw-r--r--models/boards.js109
-rw-r--r--models/cardComments.js17
-rw-r--r--models/cards.js32
-rw-r--r--models/lists.js33
-rw-r--r--models/unsavedEdits.js9
-rw-r--r--models/users.js139
9 files changed, 242 insertions, 105 deletions
diff --git a/.eslintrc.json b/.eslintrc.json
index 939f7b46..87c2e2cf 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -74,6 +74,7 @@
"Avatars": true,
"BlazeComponent": false,
"BlazeLayout": false,
+ "CollectionHooks": false,
"DocHead": false,
"ESSearchResults": false,
"FastRender": false,
diff --git a/client/components/cards/labels.js b/client/components/cards/labels.js
index 20d95bc6..cdd5a700 100644
--- a/client/components/cards/labels.js
+++ b/client/components/cards/labels.js
@@ -9,9 +9,7 @@ BlazeComponent.extendComponent({
},
labels() {
- return labelColors.map((color) => {
- return { color, name: '' };
- });
+ return labelColors.map((color) => ({ color, name: '' }));
},
isSelected(color) {
diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json
index b171bdf9..2047d8e1 100755
--- a/i18n/en.i18n.json
+++ b/i18n/en.i18n.json
@@ -294,5 +294,8 @@
"watch": "Watch",
"watching": "Watching",
"watching-info": "You will be notified of any change in this board",
+ "welcome-board": "Welcome Board",
+ "welcome-list1": "Basics",
+ "welcome-list2": "Advanced",
"what-to-do": "What do you want to do?"
}
diff --git a/models/boards.js b/models/boards.js
index 52272cce..715bb838 100644
--- a/models/boards.js
+++ b/models/boards.js
@@ -6,25 +6,77 @@ Boards.attachSchema(new SimpleSchema({
},
slug: {
type: String,
+ autoValue() { // eslint-disable-line consistent-return
+ // XXX We need to improve slug management. Only the id should be necessary
+ // to identify a board in the code.
+ // XXX If the board title is updated, the slug should also be updated.
+ // In some cases (Chinese and Japanese for instance) the `getSlug` function
+ // return an empty string. This is causes bugs in our application so we set
+ // a default slug in this case.
+ if (this.isInsert && !this.isSet) {
+ let slug = 'board';
+ const title = this.field('title');
+ if (title.isSet) {
+ slug = getSlug(title.value) || slug;
+ }
+ return slug;
+ }
+ },
},
archived: {
type: Boolean,
+ autoValue() { // eslint-disable-line consistent-return
+ if (this.isInsert && !this.isSet) {
+ return false;
+ }
+ },
},
createdAt: {
type: Date,
- denyUpdate: true,
+ autoValue() { // eslint-disable-line consistent-return
+ if (this.isInsert) {
+ return new Date();
+ } else {
+ this.unset();
+ }
+ },
},
// XXX Inconsistent field naming
modifiedAt: {
type: Date,
- denyInsert: true,
optional: true,
+ autoValue() { // eslint-disable-line consistent-return
+ if (this.isUpdate) {
+ return new Date();
+ } else {
+ this.unset();
+ }
+ },
},
// De-normalized number of users that have starred this board
stars: {
type: Number,
+ autoValue() { // eslint-disable-line consistent-return
+ if (this.isInsert) {
+ return 0;
+ }
+ },
},
// De-normalized label system
+ 'labels': {
+ type: [Object],
+ autoValue() { // eslint-disable-line consistent-return
+ if (this.isInsert && !this.isSet) {
+ const colors = Boards.simpleSchema()._schema['labels.$.color'].allowedValues;
+ const defaultLabelsColors = _.clone(colors).splice(0, 6);
+ return defaultLabelsColors.map((color) => ({
+ color,
+ _id: Random.id(6),
+ name: '',
+ }));
+ }
+ },
+ },
'labels.$._id': {
// We don't specify that this field must be unique in the board because that
// will cause performance penalties and is not necessary since this field is
@@ -47,6 +99,19 @@ Boards.attachSchema(new SimpleSchema({
// XXX We might want to maintain more informations under the member sub-
// documents like de-normalized meta-data (the date the member joined the
// board, the number of contributions, etc.).
+ 'members': {
+ type: [Object],
+ autoValue() { // eslint-disable-line consistent-return
+ if (this.isInsert && !this.isSet) {
+ return [{
+ userId: this.userId,
+ isAdmin: true,
+ isActive: true,
+ isInvited: false,
+ }];
+ }
+ },
+ },
'members.$.userId': {
type: String,
},
@@ -70,6 +135,11 @@ Boards.attachSchema(new SimpleSchema({
'wisteria',
'midnight',
],
+ autoValue() { // eslint-disable-line consistent-return
+ if (this.isInsert && !this.isSet) {
+ return Boards.simpleSchema()._schema.color.allowedValues[0];
+ }
+ },
},
description: {
type: String,
@@ -338,41 +408,6 @@ if (Meteor.isServer) {
});
}
-Boards.before.insert((userId, doc) => {
- // XXX We need to improve slug management. Only the id should be necessary
- // to identify a board in the code.
- // XXX If the board title is updated, the slug should also be updated.
- // In some cases (Chinese and Japanese for instance) the `getSlug` function
- // return an empty string. This is causes bugs in our application so we set
- // a default slug in this case.
- doc.slug = doc.slug || getSlug(doc.title) || 'board';
- doc.createdAt = new Date();
- doc.archived = false;
- doc.members = doc.members || [{
- userId,
- isAdmin: true,
- isActive: true,
- }];
- doc.stars = 0;
- doc.color = Boards.simpleSchema()._schema.color.allowedValues[0];
-
- // Handle labels
- const colors = Boards.simpleSchema()._schema['labels.$.color'].allowedValues;
- const defaultLabelsColors = _.clone(colors).splice(0, 6);
- doc.labels = defaultLabelsColors.map((color) => {
- return {
- color,
- _id: Random.id(6),
- name: '',
- };
- });
-});
-
-Boards.before.update((userId, doc, fieldNames, modifier) => {
- modifier.$set = modifier.$set || {};
- modifier.$set.modifiedAt = new Date();
-});
-
if (Meteor.isServer) {
// Let MongoDB ensure that a member is not included twice in the same board
Meteor.startup(() => {
diff --git a/models/cardComments.js b/models/cardComments.js
index 224deb03..ce6edf3c 100644
--- a/models/cardComments.js
+++ b/models/cardComments.js
@@ -16,10 +16,22 @@ CardComments.attachSchema(new SimpleSchema({
createdAt: {
type: Date,
denyUpdate: false,
+ autoValue() { // eslint-disable-line consistent-return
+ if (this.isInsert) {
+ return new Date();
+ } else {
+ this.unset();
+ }
+ },
},
// XXX Should probably be called `authorId`
userId: {
type: String,
+ autoValue() { // eslint-disable-line consistent-return
+ if (this.isInsert && !this.isSet) {
+ return this.userId;
+ }
+ },
},
}));
@@ -44,11 +56,6 @@ CardComments.helpers({
CardComments.hookOptions.after.update = { fetchPrevious: false };
-CardComments.before.insert((userId, doc) => {
- doc.createdAt = new Date();
- doc.userId = userId;
-});
-
if (Meteor.isServer) {
CardComments.after.insert((userId, doc) => {
Activities.insert({
diff --git a/models/cards.js b/models/cards.js
index 09c86191..aa19a64a 100644
--- a/models/cards.js
+++ b/models/cards.js
@@ -9,6 +9,11 @@ Cards.attachSchema(new SimpleSchema({
},
archived: {
type: Boolean,
+ autoValue() { // eslint-disable-line consistent-return
+ if (this.isInsert && !this.isSet) {
+ return false;
+ }
+ },
},
listId: {
type: String,
@@ -25,10 +30,19 @@ Cards.attachSchema(new SimpleSchema({
},
createdAt: {
type: Date,
- denyUpdate: true,
+ autoValue() { // eslint-disable-line consistent-return
+ if (this.isInsert) {
+ return new Date();
+ } else {
+ this.unset();
+ }
+ },
},
dateLastActivity: {
type: Date,
+ autoValue() {
+ return new Date();
+ },
},
description: {
type: String,
@@ -46,6 +60,11 @@ Cards.attachSchema(new SimpleSchema({
// the `members` field?
userId: {
type: String,
+ autoValue() { // eslint-disable-line consistent-return
+ if (this.isInsert && !this.isSet) {
+ return this.userId;
+ }
+ },
},
sort: {
type: Number,
@@ -190,17 +209,6 @@ Cards.mutations({
},
});
-Cards.before.insert((userId, doc) => {
- doc.createdAt = new Date();
- doc.dateLastActivity = new Date();
- if(!doc.hasOwnProperty('archived')){
- doc.archived = false;
- }
- if (!doc.userId) {
- doc.userId = userId;
- }
-});
-
if (Meteor.isServer) {
Cards.after.insert((userId, doc) => {
Activities.insert({
diff --git a/models/lists.js b/models/lists.js
index 4e4a1134..a4938f67 100644
--- a/models/lists.js
+++ b/models/lists.js
@@ -6,13 +6,24 @@ Lists.attachSchema(new SimpleSchema({
},
archived: {
type: Boolean,
+ autoValue() { // eslint-disable-line consistent-return
+ if (this.isInsert && !this.isSet) {
+ return false;
+ }
+ },
},
boardId: {
type: String,
},
createdAt: {
type: Date,
- denyUpdate: true,
+ autoValue() { // eslint-disable-line consistent-return
+ if (this.isInsert) {
+ return new Date();
+ } else {
+ this.unset();
+ }
+ },
},
sort: {
type: Number,
@@ -22,8 +33,14 @@ Lists.attachSchema(new SimpleSchema({
},
updatedAt: {
type: Date,
- denyInsert: true,
optional: true,
+ autoValue() { // eslint-disable-line consistent-return
+ if (this.isUpdate) {
+ return new Date();
+ } else {
+ this.unset();
+ }
+ },
},
}));
@@ -73,18 +90,6 @@ Lists.mutations({
Lists.hookOptions.after.update = { fetchPrevious: false };
-Lists.before.insert((userId, doc) => {
- doc.createdAt = new Date();
- doc.archived = false;
- if (!doc.userId)
- doc.userId = userId;
-});
-
-Lists.before.update((userId, doc, fieldNames, modifier) => {
- modifier.$set = modifier.$set || {};
- modifier.$set.modifiedAt = new Date();
-});
-
if (Meteor.isServer) {
Lists.after.insert((userId, doc) => {
Activities.insert({
diff --git a/models/unsavedEdits.js b/models/unsavedEdits.js
index 87a70e22..25952fb5 100644
--- a/models/unsavedEdits.js
+++ b/models/unsavedEdits.js
@@ -14,6 +14,11 @@ UnsavedEditCollection.attachSchema(new SimpleSchema({
},
userId: {
type: String,
+ autoValue() { // eslint-disable-line consistent-return
+ if (this.isInsert && !this.isSet) {
+ return this.userId;
+ }
+ },
},
}));
@@ -28,7 +33,3 @@ if (Meteor.isServer) {
fetch: ['userId'],
});
}
-
-UnsavedEditCollection.before.insert((userId, doc) => {
- doc.userId = userId;
-});
diff --git a/models/users.js b/models/users.js
index b45dedd2..790ee0a1 100644
--- a/models/users.js
+++ b/models/users.js
@@ -1,5 +1,95 @@
Users = Meteor.users;
+Users.attachSchema(new SimpleSchema({
+ username: {
+ type: String,
+ optional: true,
+ autoValue() { // eslint-disable-line consistent-return
+ if (this.isInsert && !this.isSet) {
+ const name = this.field('profile.fullname');
+ if (name.isSet) {
+ return name.value.toLowerCase().replace(/\s/g, '');
+ }
+ }
+ },
+ },
+ emails: {
+ type: [Object],
+ optional: true,
+ },
+ 'emails.$.address': {
+ type: String,
+ regEx: SimpleSchema.RegEx.Email,
+ },
+ 'emails.$.verified': {
+ type: Boolean,
+ },
+ createdAt: {
+ type: Date,
+ autoValue() { // eslint-disable-line consistent-return
+ if (this.isInsert) {
+ return new Date();
+ } else {
+ this.unset();
+ }
+ },
+ },
+ profile: {
+ type: Object,
+ optional: true,
+ autoValue() { // eslint-disable-line consistent-return
+ if (this.isInsert && !this.isSet) {
+ return {};
+ }
+ },
+ },
+ 'profile.avatarUrl': {
+ type: String,
+ optional: true,
+ },
+ 'profile.emailBuffer': {
+ type: [String],
+ optional: true,
+ },
+ 'profile.fullname': {
+ type: String,
+ optional: true,
+ },
+ 'profile.initials': {
+ type: String,
+ optional: true,
+ },
+ 'profile.invitedBoards': {
+ type: [String],
+ optional: true,
+ },
+ 'profile.language': {
+ type: String,
+ optional: true,
+ },
+ 'profile.notifications': {
+ type: [String],
+ optional: true,
+ },
+ 'profile.starredBoards': {
+ type: [String],
+ optional: true,
+ },
+ 'profile.tags': {
+ type: [String],
+ optional: true,
+ },
+ services: {
+ type: Object,
+ optional: true,
+ blackbox: true,
+ },
+ heartbeat: {
+ type: Date,
+ optional: true,
+ },
+}));
+
// Search a user in the complete server database by its name or username. This
// is used for instance to add a new user to a board.
const searchInFields = ['username', 'profile.fullname'];
@@ -259,14 +349,6 @@ if (Meteor.isServer) {
});
}
-Users.before.insert((userId, doc) => {
- doc.profile = doc.profile || {};
-
- if (!doc.username && doc.profile.fullname) {
- doc.username = doc.profile.fullname.toLowerCase().replace(/\s/g, '');
- }
-});
-
if (Meteor.isServer) {
// Let mongoDB ensure username unicity
Meteor.startup(() => {
@@ -306,32 +388,29 @@ if (Meteor.isServer) {
incrementBoards(_.difference(newIds, oldIds), +1);
});
- // XXX i18n
+ const fakeUserId = new Meteor.EnvironmentVariable();
+ const getUserId = CollectionHooks.getUserId;
+ CollectionHooks.getUserId = () => {
+ return fakeUserId.get() || getUserId();
+ };
+
Users.after.insert((userId, doc) => {
- const ExampleBoard = {
- title: 'Welcome Board',
- userId: doc._id,
- permission: 'private',
+ const fakeUser = {
+ extendAutoValueContext: {
+ userId: doc._id,
+ },
};
- // Insert the Welcome Board
- Boards.insert(ExampleBoard, (err, boardId) => {
-
- ['Basics', 'Advanced'].forEach((title) => {
- const list = {
- title,
- boardId,
- userId: ExampleBoard.userId,
-
- // XXX Not certain this is a bug, but we except these fields get
- // inserted by the Lists.before.insert collection-hook. Since this
- // hook is not called in this case, we have to dublicate the logic and
- // set them here.
- archived: false,
- createdAt: new Date(),
- };
+ fakeUserId.withValue(doc._id, () => {
+ // Insert the Welcome Board
+ Boards.insert({
+ title: TAPi18n.__('welcome-board'),
+ permission: 'private',
+ }, fakeUser, (err, boardId) => {
- Lists.insert(list);
+ ['welcome-list1', 'welcome-list2'].forEach((title) => {
+ Lists.insert({ title: TAPi18n.__(title), boardId }, fakeUser);
+ });
});
});
});