Browse Source

Add change email address

Set allow email change in admin panel
nztqa 7 năm trước cách đây
mục cha
commit
6a10257fd7

+ 2 - 1
.eslintrc.json

@@ -129,6 +129,7 @@
     "JsonRoutes": true,
     "JsonRoutes": true,
     "Authentication": true,
     "Authentication": true,
     "Integrations": true,
     "Integrations": true,
-    "HTTP": true
+    "HTTP": true,
+    "AccountSettings": true
   }
   }
 }
 }

+ 16 - 0
client/components/settings/settingBody.jade

@@ -12,6 +12,8 @@ template(name="setting")
               a.js-setting-menu(data-id="registration-setting") {{_ 'registration'}}
               a.js-setting-menu(data-id="registration-setting") {{_ 'registration'}}
             li
             li
               a.js-setting-menu(data-id="email-setting") {{_ 'email'}}
               a.js-setting-menu(data-id="email-setting") {{_ 'email'}}
+            li
+              a.js-setting-menu(data-id="account-setting") {{_ 'accounts'}}
         .main-body
         .main-body
           if loading.get
           if loading.get
             +spinner
             +spinner
@@ -19,6 +21,8 @@ template(name="setting")
             +general
             +general
           else if emailSetting.get
           else if emailSetting.get
             +email
             +email
+          else if accountSetting.get
+            +accountSettings
 
 
 template(name="general")
 template(name="general")
   ul#registration-setting.setting-detail
   ul#registration-setting.setting-detail
@@ -80,3 +84,15 @@ template(name='email')
 
 
     li
     li
       button.js-save.primary {{_ 'save'}}
       button.js-save.primary {{_ 'save'}}
+
+template(name='accountSettings')
+  ul#account-setting.setting-detail
+    li.smtp-form
+      .title {{_ 'accounts-allowEmailChange'}}
+      .form-group.flex
+        input.form-control#accounts-allowEmailChange(type="radio" name="allowEmailChange" value="true" checked="{{#if allowEmailChange}}checked{{/if}}")
+        span {{_ 'yes'}}
+        input.form-control#accounts-allowEmailChange(type="radio" name="allowEmailChange" value="false" checked="{{#unless allowEmailChange}}checked{{/unless}}")
+        span {{_ 'no'}}
+    li
+      button.js-accounts-save.primary {{_ 'save'}}

+ 22 - 0
client/components/settings/settingBody.js

@@ -1,5 +1,6 @@
 Meteor.subscribe('setting');
 Meteor.subscribe('setting');
 Meteor.subscribe('mailServer');
 Meteor.subscribe('mailServer');
+Meteor.subscribe('accountSettings');
 
 
 BlazeComponent.extendComponent({
 BlazeComponent.extendComponent({
   onCreated() {
   onCreated() {
@@ -7,6 +8,7 @@ BlazeComponent.extendComponent({
     this.loading = new ReactiveVar(false);
     this.loading = new ReactiveVar(false);
     this.generalSetting = new ReactiveVar(true);
     this.generalSetting = new ReactiveVar(true);
     this.emailSetting = new ReactiveVar(false);
     this.emailSetting = new ReactiveVar(false);
+    this.accountSetting = new ReactiveVar(false);
   },
   },
 
 
   setError(error) {
   setError(error) {
@@ -62,6 +64,7 @@ BlazeComponent.extendComponent({
       const targetID = target.data('id');
       const targetID = target.data('id');
       this.generalSetting.set('registration-setting' === targetID);
       this.generalSetting.set('registration-setting' === targetID);
       this.emailSetting.set('email-setting' === targetID);
       this.emailSetting.set('email-setting' === targetID);
+      this.accountSetting.set('account-setting' === targetID);
     }
     }
   },
   },
 
 
@@ -130,3 +133,22 @@ BlazeComponent.extendComponent({
     }];
     }];
   },
   },
 }).register('setting');
 }).register('setting');
+
+BlazeComponent.extendComponent({
+  saveAllowEmailChange() {
+    const allowEmailChange = ($('input[name=allowEmailChange]:checked').val() === 'true');
+    AccountSettings.update('accounts-allowEmailChange', {
+      $set: { 'booleanValue': allowEmailChange },
+    });
+  },
+
+  allowEmailChange() {
+    return AccountSettings.findOne('accounts-allowEmailChange').booleanValue;
+  },
+
+  events() {
+    return [{
+      'click button.js-accounts-save': this.saveAllowEmailChange,
+    }];
+  },
+}).register('accountSettings');

+ 8 - 0
client/components/users/userHeader.jade

@@ -36,6 +36,14 @@ template(name="editProfilePopup")
     label
     label
       | {{_ 'initials'}}
       | {{_ 'initials'}}
       input.js-profile-initials(type="text" value=profile.initials)
       input.js-profile-initials(type="text" value=profile.initials)
+    label
+      | {{_ 'email'}}
+      span.error.hide.email-taken
+        | {{_ 'error-email-taken'}}
+      if allowEmailChange
+        input.js-profile-email(type="email" value="{{emails.[0].address}}")
+      else
+        input.js-profile-email(type="email" value="{{emails.[0].address}}" readonly)
     input.primary.wide(type="submit" value="{{_ 'save'}}")
     input.primary.wide(type="submit" value="{{_ 'save'}}")
 
 
 template(name="editNotificationPopup")
 template(name="editNotificationPopup")

+ 41 - 2
client/components/users/userHeader.js

@@ -20,18 +20,47 @@ Template.memberMenuPopup.events({
   },
   },
 });
 });
 
 
+Template.editProfilePopup.helpers({
+  allowEmailChange() {
+    return AccountSettings.findOne('accounts-allowEmailChange').booleanValue;
+  },
+});
+
 Template.editProfilePopup.events({
 Template.editProfilePopup.events({
   submit(evt, tpl) {
   submit(evt, tpl) {
     evt.preventDefault();
     evt.preventDefault();
     const fullname = tpl.find('.js-profile-fullname').value.trim();
     const fullname = tpl.find('.js-profile-fullname').value.trim();
     const username = tpl.find('.js-profile-username').value.trim();
     const username = tpl.find('.js-profile-username').value.trim();
     const initials = tpl.find('.js-profile-initials').value.trim();
     const initials = tpl.find('.js-profile-initials').value.trim();
+    const email = tpl.find('.js-profile-email').value.trim();
+    let isChangeUserName = false;
+    let isChangeEmail = false;
     Users.update(Meteor.userId(), {$set: {
     Users.update(Meteor.userId(), {$set: {
       'profile.fullname': fullname,
       'profile.fullname': fullname,
       'profile.initials': initials,
       'profile.initials': initials,
     }});
     }});
-
-    if (username !== Meteor.user().username) {
+    isChangeUserName = username !== Meteor.user().username;
+    isChangeEmail = email.toLowerCase() !== Meteor.user().emails[0].address.toLowerCase();
+    if (isChangeUserName && isChangeEmail) {
+      Meteor.call('setUsernameAndEmail', username, email.toLowerCase(), function(error) {
+        const usernameMessageElement = tpl.$('.username-taken');
+        const emailMessageElement = tpl.$('.email-taken');
+        if (error) {
+          const errorElement = error.error;
+          if (errorElement === 'username-already-taken') {
+            usernameMessageElement.show();
+            emailMessageElement.hide();
+          } else if (errorElement === 'email-already-taken') {
+            usernameMessageElement.hide();
+            emailMessageElement.show();
+          }
+        } else {
+          usernameMessageElement.hide();
+          emailMessageElement.hide();
+          Popup.back();
+        }
+      });
+    } else if (isChangeUserName) {
       Meteor.call('setUsername', username, function(error) {
       Meteor.call('setUsername', username, function(error) {
         const messageElement = tpl.$('.username-taken');
         const messageElement = tpl.$('.username-taken');
         if (error) {
         if (error) {
@@ -41,6 +70,16 @@ Template.editProfilePopup.events({
           Popup.back();
           Popup.back();
         }
         }
       });
       });
+    } else if (isChangeEmail) {
+      Meteor.call('setEmail', email.toLowerCase(), function(error) {
+        const messageElement = tpl.$('.email-taken');
+        if (error) {
+          messageElement.show();
+        } else {
+          messageElement.hide();
+          Popup.back();
+        }
+      });
     } else Popup.back();
     } else Popup.back();
   },
   },
 });
 });

+ 6 - 1
i18n/en.i18n.json

@@ -191,6 +191,7 @@
     "error-user-notAllowSelf": "You can not invite yourself",
     "error-user-notAllowSelf": "You can not invite yourself",
     "error-user-notCreated": "This user is not created",
     "error-user-notCreated": "This user is not created",
     "error-username-taken": "This username is already taken",
     "error-username-taken": "This username is already taken",
+    "error-email-taken": "Email has already been taken",
     "export-board": "Export board",
     "export-board": "Export board",
     "filter": "Filter",
     "filter": "Filter",
     "filter-cards": "Filter Cards",
     "filter-cards": "Filter Cards",
@@ -379,5 +380,9 @@
     "OS_Uptime": "OS Uptime",
     "OS_Uptime": "OS Uptime",
     "hours": "hours",
     "hours": "hours",
     "minutes": "minutes",
     "minutes": "minutes",
-    "seconds": "seconds"
+    "seconds": "seconds",
+    "yes": "Yes",
+    "no": "No",
+    "accounts": "accounts",
+    "accounts-allowEmailChange": "Allow Email Change"
 }
 }

+ 33 - 0
models/accountSettings.js

@@ -0,0 +1,33 @@
+AccountSettings = new Mongo.Collection('accountSettings');
+
+AccountSettings.attachSchema(new SimpleSchema({
+  _id: {
+    type: String,
+  },
+  booleanValue: {
+    type: Boolean,
+    optional: true,
+  },
+  sort: {
+    type: Number,
+    decimal: true,
+  },
+}));
+
+AccountSettings.allow({
+  update(userId) {
+    const user = Users.findOne(userId);
+    return user && user.isAdmin;
+  },
+});
+
+if (Meteor.isServer) {
+  Meteor.startup(() => {
+    AccountSettings.upsert({ _id: 'accounts-allowEmailChange' }, {
+      $setOnInsert: {
+        booleanValue: false,
+        sort: 0,
+      },
+    });
+  });
+}

+ 22 - 0
models/users.js

@@ -334,6 +334,28 @@ Meteor.methods({
     check(limit, Number);
     check(limit, Number);
     Meteor.user().setShowCardsCountAt(limit);
     Meteor.user().setShowCardsCountAt(limit);
   },
   },
+  setEmail(email) {
+    check(email, String);
+    const existingUser = Users.findOne({ 'emails.address': email }, { fields: { _id: 1 } });
+    if (existingUser) {
+      throw new Meteor.Error('email-already-taken');
+    } else {
+      Users.update(this.userId, {
+        $set: {
+          emails: [{
+            address: email,
+            verified: false,
+          }],
+        },
+      });
+    }
+  },
+  setUsernameAndEmail(username, email) {
+    check(username, String);
+    check(email, String);
+    Meteor.call('setUsername', username);
+    Meteor.call('setEmail', email);
+  },
 });
 });
 
 
 if (Meteor.isServer) {
 if (Meteor.isServer) {

+ 3 - 0
server/publications/accountSettings.js

@@ -0,0 +1,3 @@
+Meteor.publish('accountSettings', function() {
+  return AccountSettings.find();
+});