What Happened
I have been working on an esports news submission web application for the last 2 months now (with a hearty break during December, so maybe closer to a month). Recently, I completed the article submission component. I mounted this component through a submit article page on the site. After getting the functionality running I wanted to make it so only users could submit an article. And, rather than having them write out the article to only be denied, I thought "why not let them know upfront you have to be logged in to submit an article?"
I started working through this process. My initial idea was to run a current user query within the component to get access to the current user's id. If this didn't return any data then I would know that the user was not logged in. After writing this up I could not find a way to encapsulate the submission Mutation within a user Query. After trying a few different methods everyone returned errors. Taking a step back I saw a solution.
The Solution
Taking that step back I saw a solution on the Next.js page that is used to mount the article submission component. By utilizing the <User>
component, I could wrap the <Submit>
component within the <User>
component's returned data. For further clarity, here is the full <User>
component:
import { Query } from "react-apollo";
import gql from "graphql-tag";
import PropTypes from "prop-types";
const CURRENT_USER_QUERY = gql`
query {
me {
id
email
name
permissions
}
}
`;
const User = props => (
<Query {...props} query={CURRENT_USER_QUERY}>
{payload => props.children(payload)}
</Query>
);
User.propTypes = {
children: PropTypes.func.isRequired
};
export default User;
export { CURRENT_USER_QUERY };
So, if we take that payload
returned from the component we can pass this to the <Submit>
component via a prop. Taking this approach we can change our submit.js
page from
import React, { Component } from "react";
import Submit from "../components/Submit";
const submit = () => <Submit />;
export default submit;
To something that will gather data from the <User>
component.
import React, { Component } from "react";
import { Query } from "react-apollo";
import Submit from "../components/Submit";
import User from "../components/User";
import Signin from "../components/Signin";
const submit = () => <User>{({ data }) => <Submit isLoggedIn={data} />}</User>;
export default submit;
The payload here is then passed to <Submit>
within the isLoggedIn
prop. Taking that prop, we can use some if/else statements to either render the submission form or render a login page, depending on what the current user status is.
render() {
if (this.props.isLoggedIn.me) {
return (
Submission form code here
)
} else {
login form, message, or redirect here
}
}
So, if isLoggedIn.me
exists, then the user is logged in. The me
part of this comes from the CURRENT_USER_QUERY. The query returns id, email, name, permission
. We could use any one of these, including isLoggedIn.me.permission
to make sure they are part of a group authorized to access this, but within the web application, any logged-in user is allowed to submit an article.
The Conclusion
This strategy could be utilized for any level of authorization. If this was an admin form I could take the returned data and look for the permission part of the object (this is defined in the query from <User>
and stored in the database for each user). This particular time, I only look for any data at all. As long as that data exists, the user is logged in. This is another excellent lesson in always taking a step back in what we are doing. I spent longer on this then I should but it was because I tried so many different iterations of how I thought it was supposed to work, rather than taking a few minutes to review my thought process and take a different approach.
Thank you for reading. As always, feel free to leave any comments about the code, my thought process, what I could be doing better, or just saying hey.
Top comments (0)