Pup

v1.x

AccountsUser Settings & GDPR

To help with the process of customizing your user's experience, Pup includes a User Settings convention that allows both you and individual users to manage their settings. Settings for users are stored in two places: the UserSettings collection, which acts as the "master" list for all settings in the app and on each individual user—in an array called settings—in the Meteor.users collection.

Settings for each user are stored as a single object in the user's settings array. Each setting stored on the user has a schema that's identical to the "master" setting in the UserSettings collection.

For administrators of the application (users with the role admin applied), user settings can be managed when viewing individual users via the /admin/users page. Learn more about the admin page here.

For non-adminstrative users looking to manage their own settings, these can be accessed via the user's /profile page.

Implied but not enforced schema for settings on users

Although the master UserSettings collection has its own schema, once settings are added to a user's settings array, a schema is no longer enforced.

While the User Settings admin panel described below should help to avoid any issues, keep this in mind if you intended to make changes to the data you keep in relation to settings.

Example Settings for a User
{
  "_id": "LtPBamXqg6iLQLcfP",
  [...]
  "settings": [
    {
      "_id": "xezY4GS7z4z57omRW",
      "key": "canSendMarketingEmails",
      "isGDPR": true,
      "label": "Can we send you marketing emails?",
      "type": "boolean",
      "value": false
    },
  ]
}

Default User Settings

While new settings can be added via the admin GUI described below, when you first deploy your application, you may want to seed your UserSettings collection with a set of default settings.

By default, Pup includes a file for helping with this located at /imports/startup/server/accounts/user-settings.js. This file is only intended to add settings in bulk to a new deployment. It should NOT serve as an alternative way to add new settings to users (meaning, do not expect this file to add each of the default settings to your existing user base).

Automatically, when new users sign up for your app, they current state of the UserSettings collection will be copied over to that user's settings array. So, if you have five settings globally in UserSettings, those five settings will be applied to each new user that signs up. This behavior can be customized or removed in /imports/startup/server/accounts/on-create-user.js.

/imports/startup/server/accounts/user-settings.js
// https://cleverbeagle.com/pup/v1/accounts/user-settings

import UserSettings from '../../../api/UserSettings/UserSettings';

const defaultUserSettings = [{
  isGDPR: true,
  key: 'canSendMarketingEmails',
  label: 'Can we send you marketing emails?',
  type: 'boolean',
  value: 'false', // Pass a string and allow schema to convert to a Boolean for us.
}];

defaultUserSettings.forEach((setting) => {
  if (!UserSettings.findOne({ key: setting.key })) {
    UserSettings.inser(setting);
  }
});

GDPR Settings

By default, Pup includes a single setting—showcased in "Default User Settings" above—that's automatically added to all new users for managing whether or not you should send them marketing emails. This value is intended to help you comply with the European Union's (EU) General Data Protection Regulation (GDPR).

To aid in the process of collecting each user's consent, after signing up, users are immediately presented with a "GDPR Consent" modal. This modal is only displayed if the user has not reviewed a setting that's flagged as isGDPR: true and has a lastUpdatedByUser value of null.

GDPR modal displayed when new user's login for the first time.
GDPR modal displayed when new user's login for the first time.

When displayed, the modal presents users with only the settings flagged as isGDPR—all others are excluded. Upon pressing "Save Settings" in the modal, all GDPR-related settings have their lastUpdatedByUser field updated with a timestamp for the current date and time.

Though not in use in anywhere in the application (Pup doesn't send any marketing emails on your behalf), you can access this value using the getUserSettings() module in your own app if you do decide to send marketing email to users. You can find more information on this module under Reading & Using User Settings below.

Setting Default GDPR Settings
UserSettings.insert({
  userId: user._id,
  settings: [{
    isGDPR: true,
    key: 'canSendMarketingEmails',
    label: 'Can we send you marketing emails?',
    value: false,
    lastUpdatedByUser: null,
    lastUpdatedByAdmin: (new Date()).toISOString(),
  }],
});

Creating, Editing, and Deleting Settings

To make creating, editing, and deleting settings easier, Pup ships with an admin panel for managing user settings via a GUI.

User Settings admin panel in Pup.
User Settings admin panel in Pup.

For users in the admin role, this page can be accessed in the app at /admin/users/settings. New and existing settings can be created and edited via a modal on the same page. Settings can also be deleted from the same page.

Adding User Settings in Pup.
Adding User Settings in Pup.

When creating a new setting, Pup stores the setting in the UserSettings collection in MongoDB and adds the setting to each user's settings field on their Meteor.users record.

A similar workflow is followed for editing existing settings—the UserSettings collection is updated and then all users with that setting—as well as deleting settings (the setting is removed from all users and then removed from the UserSettings collection).

Heads up: When you edit a user setting we will intentionally overwrite that setting for the user, meaning the default value you set will be applied for that user.

Editing User Settings in Pup.
Editing User Settings in Pup.

Though Pup includes a GUI for managing settings, it is your responsibility for wiring up new settings that you add to your UI. This also includes making sure to remove settings from your UI before you delete them so they do not break rendering.

Reading & Using User Settings

Although user settings can always be read directly from a user's settings array, to simplify this process, Pup includes a module called getUserSetting() which helps you to retrieve individual settings for a user.

The module can be passed three arguments: the name of the setting key that you'd like to retrieve for the user, whether or not you'd like the valueOnly returned (as opposed to the entire setting object), and optionally, a userId that isn't the currently logged in user (if you're retrieving a setting as an admin, this can come in handy).

As an example, on the right, we showcase using the getUserSetting() module which can be imported from /imports/modules/get-user-setting.js to retrieve the GDPR-related canSendMarketingEmails setting highlighted in the examples above.

Settings available globally

To avoid the need to import settings everywhere manually, Pup automatically loads the current user's settings globally in the app via the users.settings publication loaded in /imports/ui/layouts/App/App.js and defined in /imports/api/App/server/publications.js.

Example Usage of getUserSetting()
import { Meteor } from 'meteor/meteor';
import handleMethodException from '../../../modules/handle-method-exception';
import getUserSetting from '../../../modules/get-user-setting';

Meteor.methods({
  'users.sendNewsletter': function usersSendNewsletter() { // eslint-disable-line
    try {
      // Just an example. This is not an ideal way to send a mass newsletter email :)
      const users = Meteor.users.find({}, { fields: { emails: 1 } }).fetch();
      users.forEach(({ _id, emails }) => {
        const canSendMarketingEmails = getUserSetting('canSendMarketingEmails', true, _id);
        if (canSendMarketingEmails) {
          // Send the user an email.
        }
      });
    } catch (exception) {
      handleMethodException(exception);
    }
  },
});