Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic Links\Reducers #437

Closed
odesey opened this issue Nov 4, 2020 · 4 comments
Closed

Dynamic Links\Reducers #437

odesey opened this issue Nov 4, 2020 · 4 comments

Comments

@odesey
Copy link

odesey commented Nov 4, 2020

Thanks for this great package, it's been a life saver!

The title might be a little miss-leading, but here is the problem I have.

I have two collections, Threads and Messages
Threads is basically a meta-data document that has information about the messages
Messages has the actual data displayed to the user, and each message has a userId field (important)

When I retrieve the messages that belong to a thread, I have a link that looks like this:

Messages.addLinks({
    user: {
        type: 'one',
        collection: Meteor.users,
        field: 'userId'
    }
});

I also have a reducer that looks like this:

Meteor.users.addReducers({
    name: {
        body: {
            profile: {
                firstName: 1
            }
        },
        reduce(object) {
            const { profile } = object;

            return profile.firstName;
        }
    }
});

Finally I have my query that looks like this:

const query = Messages.createQuery(
            {
                $filters: {
                    threadId
                },
                $options: {
                    sort: { createdAt: -1 }
                },
                lastUpdate: 1,
                createdAt: 1,
                text: 1,  //message text
                user: {
                    name: 1
                }
            }
        );
        return query.fetch();

Each thread and it's messages are accessible by 2 parties. The user who created the thread (public), and the business that the message was sent to. Everything works great except for one thing I would like to change.

When a business loads the messages, the app shows the names of everyone who created a message in the thread, public user and employees in the business.

This is the problem I am having here: When the user (public) loads the messages, I want the messages sent from the business to have the word Business instead of the user's real name's in the name field. Maybe a dynamic Link or Reducer?

Just for clarity:
Business should see: javascript {text: 'message text here', name: {firstName: 'John'}

Public user should see: javascript {text: 'message text here', name: {firstName: 'Business'}
NOT
javascript {text: 'message text here', name: {firstName: 'John'}

Is this something I can do easily with the grapher package?

Thanks.

@vparpoil
Copy link
Contributor

vparpoil commented Nov 5, 2020

To do this securely (i.e. not sending the real username of your business user to the client), you need to call the grapher query from a method.
This method will use this.userId to determine the status of the user : Public user or Business.
Then, for the business user, return the query results as is and for the public user you either use a different query (safer) or you update the data before sending it back to the client.

@odesey
Copy link
Author

odesey commented Nov 5, 2020

Thanks for responding @vparpoil

I am already using two different methods, one for the public and one for the business and two different queries as well.
The business query works perfectly, I am not sure how to configure the public query to send back Business for only the messages that do not match the this.userId

The query in my initial question is the business query, how would I modify it to change the documents on the fly that do not match the this.userId check?

Thanks.

@vparpoil
Copy link
Contributor

vparpoil commented Nov 6, 2020

If you can access the userId of the user querying data inside the reducer, you can achieve what you want (ie: the reducer will compute a different value based on the user identity).
Apparently this.userId is unavailable, but have you tried using Meteor.userId() ?

Other way to deal with this would be to alter the results of the fetch() in your method before returning the array of results to the client

[Edit] Other answer :
Use Params-aware reducers => see here in grapher doc, and pass the curent userId as a param of the query.

And some more context :

Meteor.users.addReducers({
    name: {
        body: {
            _id: 1,
            profile: {
                firstName: 1
            }
        },
        reduce(object, params) {
            if (isPublicUser(params.userId) && object._id !== params.userId){
                   return "Business"
            }
            return object.profile.firstName;
        }
    }
});

@odesey
Copy link
Author

odesey commented Nov 6, 2020

Thanks @vparpoil this worked and is exactly what I was looking for, very much appreciated!

@odesey odesey closed this as completed Nov 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants