Branden Ogata: Ask Me Anything (about Meteor)

This page provides answers to some of the questions about Meteor asked by students during Spring 2019 and Fall 20190.

Table of Contents

Walkthrough of System User Interface

Since the initial passwords for the template are stored in plain text in /config/settings.development.json, should projects based on this template be stored in a private repository?

No. The settings.development.json file provides an example to developers of how to define admin accounts on startup. As you will learn in the deployment module, you will define a different file named settings.production.json in which you store “real” account credentials for initial startup. For more details on settings files in Meteor, please see The Meteor Chef: Making use of settings.json.

More generally, you should always make repositories public unless there is a compelling reason to make them private. You should make as much of your professional work visible as possible: even “draft” versions of systems provide evidence to graduate schools and future employers that you are actually attempting to do development.

When should we use .jsx files instead of .js files and vice versa?

In general, use .jsx whenever you use (React) components in the file and .js otherwise.

Do the functions (ex. addData in /app/imports/startup/server/stuff.js) have to be in specific files?

Functions can be in any file that is imported where the function is used. However, if a function is only used on one file it makes sense to place the function in that one file. addData is only used in initializing the seed data for the Stuffs collection, so it is located in the file that handles the Stuffs collection on the server side.

How does if (this.userId) {…} check if the user is logged in or not? What does the this keyword refer to here?

The documentation for this.userId is here. If the user is logged in, this.userId exists and is a truthy value. If the user is not logged in, this.userId is undefined, which is a falsy value.

See the Meteor Guide for documentation on why this.userId works.

How does if (Meteor.settings.defaultData) work?

As with the previous question, Meteor.settings.defaultData will be a truthy value if it exists and a falsy value otherwise.

How would we make a Meteor project from scratch (that is, without using meteor-application-template-react)? What files would we have to create?

You have already done something like this; note though that the template basically includes everything that you would need on a site. Most websites that are complex enough to merit using Meteor will have some sort of user accounts and data associated with those accounts.

That said, it is typically not in your best interest to start a Meteor project without using some sort of boilerplate template. This is because templates help ensure that as your application grows in complexity, the organization of the system remains stable. Templates also implement a “design pattern”: a commonly recognized idiom for software development. meteor-application-template-react is not the only template available for Meteor, but it’s the one that will best serve you for developing your final project.

Are the names of the directories significant?

At the top-level, yes. Meteor has rules for where to place file in order for them to be automatically loaded. Essentially, anything covered in Example directory layout should be exactly as is; you have some flexibility in naming anything else.

Directory names are also useful as documentation: the files in /app/imports/startup should have something to do with what happens when the server starts up, /client directories are only visible on the client side, /server directories contain files only visible on the server side, etc. Something like the stuff directory for /app/imports/api/stuff/stuff.js could be named differently though; however, we name it stuff in accordance with convention and general common sense.

Is it safe to log in while already logged in?

Yes.

Can we just write HTML files in /app/client?

Technically yes, but this is a design-level error. Restricting yourself to only HTML means that you will not benefit from all the features that Meteor (and React) provide. All of your content should appear in the imports/ directory.

Is the landing page basically the home page?

No. In this class, we distinguish between the landing page, which is the page that all users see when they navigate to the site, and the home page, which is the page that users see immediately after successfully logging in.

So, the home page shows private content specific to a user, while the landing page shows public content to any visitor to the site.

What is the relationship between /app/client/main.html, /app/imports/startup/client/startup.jsx, and /app/imports/ui/layouts/App.jsx?

/app/client/main.html is the base of the HTML rendered in the browser. Although this main.html file does not directly load the main.js or style.css files, Meteor automatically loads everything in /app/client, and it is /app/client/main.js that imports all files in /app/imports/startup/client, including /app/imports/startup/client/startup.jsx. This startup.jsx file then imports and renders /app/imports/ui/layouts/App.jsx.

What is the difference between /app/client and /app/imports/startup/client? /app/server and /app/imports/startup/server?

/app/client/main.js and /app/server/main.js are defined as special files that load other files for the client and server sides respectively; see the relevant documentation here. The /app/imports directory is not directly loaded into the application by default, making it necessary to import files within those directories in /app/client/main.js and /app/server/main.js.

Why the split between /client and /server? Why not make all data visible on both sides?

Because server-side code has complete access to the database, and you almost never want every user to have access to all of the data (such as a list of all registered users and their email addresses).

What is the difference between meteor run and meteor npm run start?

meteor run is a built-in Meteor command that will start the application. meteor npm run start is a project-specific command that will start the application. You may have noticed that we used meteor run for the MongoDB experiences and many of the Meteor 1 experiences and meteor npm run start for the Meteor 2 experiences. This is because the latter command depends upon the files in the templates you have used.

If you look at the package.json file in meteor-application-template-react, you should see the following (with to truncate the parts not of immediate concern):

{
  "name": "meteor-application-template-react",
  "private": true,
  "dependencies": {
    ...
  },  
  "devDependencies": {
    ...
  },
  "scripts": {
    "start": "meteor --no-release-check --settings ../config/settings.development.json",
    "lint": "eslint --quiet --ext .jsx --ext .js ./imports"
  }
}

The "scripts" contain "start" and "lint" members. You may have noticed the similarity between meteor npm run start and meteor npm run lint. This is because both are shortcuts defined within package.json. By this definition, meteor npm run start will run the meteor --no-release-check --settings ../config/settings.development.json command.

If you are using the templates provided for this course, you will almost always want to use meteor npm run start to run your Meteor applications. (The one exception that your teaching assistant can think of is when you want to test your ./config/settings.production.json file before deploying to Galaxy.)

Data and Accounts: Structure and Initialization

How does the application remember the user accounts and other data even after terminating the Meteor process?

When you use a computer, you have to save your work before shutting down the computer. That data is stored in a file and you can open that file later to resume your work. Databases serve the same purpose: your application stores data in the database so the data is preserved even after the application has closed.

Where is all of the data stored?

The technically correct answer is /app/.meteor/local/db, though that is probably not of direct use to you since the data is not stored in a human-readable format. Aside from a tired attempt at sarcasm, this does show that the data is in the project directory, so you do not have to worry about data from one project intermingling with data from another project1.

The more useful answer is that you do not have to worry about where the data is stored: MongoDB takes care of preserving the data for you.

How are passwords stored? What prevents an attacker2 from accessing those passwords?

If we look at the users collection in the MongoDB console, we see:

meteor:PRIMARY> db.users.find()
{ "_id" : "RvkbtmXXDoRDYeohc", "createdAt" : ISODate("2019-03-11T01:48:08.812Z"), "services" : { "password" : { "bcrypt" : "$2a$10$mS4VO9apDZC.Ul6U1YtfHOtgsY8JwVlCNq7muej4GgCTGTRyiW9K6" } }, "username" : "admin@foo.com", "emails" : [ { "address" : "admin@foo.com", "verified" : false } ], "roles" : [ "admin" ] }
{ "_id" : "Bf2XizdLC5fRq4BCk", "createdAt" : ISODate("2019-03-11T01:48:09.014Z"), "services" : { "password" : { "bcrypt" : "$2a$10$OZh60hVYwNNBVJ.SZ4q6oegTEHdFRS4SSpDKbNMTxSZIa7y/pnE7." }, "resume" : { "loginTokens" : [ { "when" : ISODate("2019-03-11T02:24:40.264Z"), "hashedToken" : "Oz02OPH48WBQeyIJ3M6nIztlYHfok6V/uWBG9VDPuSM=" } ] } }, "username" : "john@foo.com", "emails" : [ { "address" : "john@foo.com", "verified" : false } ] }

In particular, note that the password field for the first user has a value of { "bcrypt" : "$2a$10$mS4VO9apDZC.Ul6U1YtfHOtgsY8JwVlCNq7muej4GgCTGTRyiW9K6" }. This is very clearly not the default password provided in /config/settings.development.json. Storing passwords as plain text is very much a bad idea; instead, we apply a hash function to the password and store that hashed value. When someone attempts to log in as the user, we then use the same hash function. If the hashed value of the input matches the value stored in the database, then we are reasonably certain that the password is correct3; otherwise we know we can reject the login.

The Meteor > MiniMongo tab shows all of the collections in the database that are published on the current page; what stops the users collection from displaying passwords?

Per the documentation for meteor/accounts-base, “by default, the current user’s username, emails and profile are published to the client”; our users have no profile field and we add in roles, but the password field is not included in the list of published fields and therefore will not appear in the developer tools.

What is bcrypt?

bcrypt allows us to hash passwords.

Is it possible to get rid of the bcrypt warning message in the Meteor console?

Yes, but it is probably not worth the time. As noted on the course website, the performance issues with bcrypt will only occur on logins and those are relatively uncommon. One might even argue that slower logins are a security feature as it forces an attacker to wait longer between attempts to break in, and after a certain point said attacker may well decide that your site is not a time-efficient target.

What is the purpose of having sample data in /config/settings.development.json?

We use the seed data in /config/settings.development.json to populate the database the first time that we start the application. This gives us enough data to test the application: the seed data for meteor-application-template-react allows us to immediately log in and interact with the website without having to touch the MongoDB console.

Can you define multiple schemas for the same collection?

Yes; see the attachSchema documentation. meteor-application-template-react provides an alternate approach that does not necessarily attach schemas to collections: AddStuff defines a formSchema constant to use within the file while EditStuff uses the StuffSchema defined along with the Stuffs collection in /imports/api/stuff/Stuff.js. meteor-example-form-react creates a separate forms directory to store these schemas.

Can we expand the Meteor.users collection to contain more data?

Yes, but this is not recommended practice as the Meteor.users collection has a number of specialized behaviors that might interact negatively with your design goals. A more simple approach is to define a new collection called something like UserProfiles, and provide a field in that collection that stores the userID associated with that document.

How can we enforce password constraints (ex. a minimum length, must contain numbers, etc.)?

See the Simple Schema documentation; min is easy enough for the minimum length, though you may have to write a separate function to perform custom validation or use regular expressions.

How can we allow users to change their passwords?

See the documentation for Accounts.changePassword.

How are passwords case-sensitive while user names are not?

See the Meteor notes on case sensitivity. In other systems that do not provide helper methods to take care of this, you might convert the usernames or email addresses to lowercase before saving them or comparing them to values in the database.

What is that “verified” : false in the “emails” field? How do we change that value?

This indicates that the email address has not been verified yet: it may be a valid email address but we do not know that it actually exists and belongs to the user. Accounts.sendVerificationEmail allows us to start that verification process.

What is the { tracker: Tracker } in /app/imports/api/stuff/stuff.js used for?

Tracker listens for changes on your data sources; see the Simple Schema documentation for notes on how this is integrated with Simple Schema.

If we remove “defaultData” from /config/settings.development.json after running the application for the first time, will those values be removed from the database?

No, by that point the values from "defaultData" are already in the database and removing them from the seed data will have no impact on the database.

Is StuffAdmin another database that runs alongside Stuff?

No, both Stuff and StuffAdmin are publications: they contain data from the database but are not databases themselves.

What does withTracker do in some of the pages (ex. /app/imports/ui/pages/EditStuff.jsx)?

The withTracker function provides access to the necessary publications from the database through setting up subscriptions; see more details in the official documentation.

Does Meteor + MongoDB allow users to create immutable data?

It is possible in MongoDB to define collection-level access control that prevents users from modifying the contents of the database. This effectively results in immutable data.

However, since the MongoDB admin defines the access control, the data is still not completely immutable: admin users can still modify it. This was pretty much a fundamental fact of life for databases—that admins can alter data—until the invention of the blockchain. Indeed, one way to look at the motivation for the development of blockchain technology was to prevent database admins from being able to alter the contents of a database!

Can Meteor be used with databases other than MongoDB?

Yes, through GraphQL.

The template shows how to add, edit, and show documents in a collection; how do you delete a document?

Use Collection#remove.

Why do we need export statements for the components? Does import not load in everything from the file?

import is not analagous to the #include in C and C++: it does not insert the entire imported file. Instead, you must export whatever you want to import in a different file. This may seem cumbersome at first, but this system allows for more flexibility and efficiency since you only import what you actually need. For example, you only import the Semantic UI React components that you actually use in the file, not the entire semantic-ui-react library.

Why do some import statements have curly braces, and other import statements do not?

See the next question.

Why do we use export in some files and export default in others?

Use export default when there is only a single entity in a file that must be made visible to other files. When there are multiple entities in a file that must be made visible to other files, then use export.

The choice of export vs. export default impacts on the syntax of the import statement. Take a look at the following code:

import { Stuffs } from '/imports/api/stuff/stuff';
import StuffItem from '/imports/ui/components/StuffItem';

In general, you use curly braces in your import statement when the associated file exported multiple entities. You don’t use curly braces when the associated file exported a default entity. So, the stuff.js file exported multiple entities (one of which was named Stuffs) while the StuffItem.jsx file exported (by default) a single item.

Note that the name referenced when importing a default export is irrelevant. The export statement in /app/imports/ui/components/NavBar.jsx is:

export default withRouter(NavBarContainer);

However, the import statement in /app/imports/ui/layouts/App.jsx is:

import NavBar from '../components/NavBar';

Even though the value exported from NavBar.jsx is the return value from calling withRouter on NavBarContainer, we can refer to it as NavBar in App.jsx.

How does publish work? Does it just send data from the server to the client? When does this data transfer happen?

‘publish’ defines a set of data on the server. The subscriptions you create on the client side with Meteor.subscribe retrieve that data from the server to use in your components and pages. Unlike SQL views, MongoDB will automatically update these subscriptions if the original collection is modified.

Can we use object-oriented programming in Meteor?

You already are; everything in /app/imports/ui extends React.Component. You could thus make a component that extends React.Component and have other components that inherit from the first component.

How is a protected route different from a regular route?

Both ProtectedRoute and AdminProtectedRoute are defined in /app/imports/ui/layouts/App.jsx; ProtectedRoute is a Route with additional logic to determine whether the user is logged in (the const isLogged = Meteor.userId() !== null).

How is an exact path different from a regular path?

An exact path must be an exact match. The Landing page requires that we be at ”/”, not some other path such as “/signin” that merely contains a /.

The pages export withTracker; where is withTracker called?

withTracker is actually called in the export itself; note the presence of parentheses for the withTracker function.

Is it possible to conditionally render parts of pages depending on whether the user is an admin or not?

Yes; see /app/imports/ui/components/NavBar.jsx for an example.

Can users add their own fields to the table in /app/imports/ui/pages/ListStuff.jsx?

Yes. You would have to make changes to the user interface (i.e. the ui/ directory), the database (i.e. the api/ directory), and to the default initialization data (i.e. settings.development.json).

What happens if you remove the subscription from /app/imports/ui/pages/ListStuff.jsx?

Without the subscription to Stuff, the ListStuff page would not have access to the Stuffs to display. Try it and see what happens.

Are the Route, ProtectedRoute, and AdminProtectedRoute components built into Meteor?

No. Look through the rest of the file: Route is imported from react-router-dom and both ProtectedRoute and AdminProtectedRoute are defined in App.jsx.

How exactly does ProtectedRoute create a new route?

ProtectedRoute is a function that returns a Route. This Route has all of the properties that were passed to the ProtectedRoute.

What is the relationship between publications and subscriptions?

The publication on the server side specifies a subset of the data in the database; the subscription on the client side requests that this data be mirrored in the client-side MiniMongo database. By analogy, Dr. Johnson publishes a screencast and you subscribe to it (in the form of watching the video).

What would happen if you removed the return this.ready() from the publications?

The this.ready() call signals that the data transfer is complete. Without this, any subscriptions on the publications would continue to wait for data indefinitely.

Yes, though the question itself hints at why this is a bad idea: you would have to include the header and footer in each page in your application. Placing the header and footer in /layouts/App.jsx makes the header and footer appear on every page.

Is it possible to modify ProtectedRoute to only allow users with some combination of roles?

Yes, though you would have to && the clauses together yourself.

What is the :_id in the “/edit/:_id” route?

The :_id is replaced with the _id of the Stuff being edited.

How does the <Switch> statement work in /app/imports/ui/layouts/App.jsx?

Switch is very much like the switch statement that you are familiar with: it directs program flow based on a single value. This is a very specific switch that decides which page to render based on the path of the current page. If the path for a Route within the Switch is equal to the current path in the browser, then Meteor will render the component for that Route. The last Route in the Switch does not include a path, making it behave much as the default case would: if none of the above paths match, the NotFound component is rendered.

You will note the lack of any break statements for the Switch. break is necessary for general-purpose switch statements because they must support fall-through. In this case though, we know that there is a one-to-one relationship between paths and pages: each path corresponds to a single page and vice versa, so there is no need for fall-through here.

Can we make routes that are visible to regular users but not admins?

Yes, you would just have to write conditional logic to prevent admins from seeing those pages.

What does the render function do?

The render method of a React.Component returns the JSX code to display for that component.

How do you generate the URL of a Stuff?

The URLs are defined in /app/imports/ui/layouts/App.jsx; these paths can be whatever you want them to be. For example, if we wanted to create a page for the user to edit his or her account information, we cannot reuse the path "/edit/:_id" because that is already the path for the EditStuff page. However, we could instead create a new ProtectedRoute with a path "/user/edit/:_id".

Why do we split the components on a page across multiple files in Meteor when we did everything in a single file in React?

You used a single .js file for your React projects because those applications only had a single page (ex. the home page for Island Snow). From a pedagogical standpoint, this let you focus on learning about React instead of having to figure out how various files interact with one another. From a software engineering standpoint, a single web page does not provide much opportunity for code reuse outside of the CSS, so the benefits of splitting the code across multiple files are not as apparent.

At this point in your development, neither of those motives for using a single file still hold true. You are already familiar with React, at least enough to use the Semantic UI React documentation as a reference. You are now working on increasingly complex projects with multiple pages, all of which share the same header and footer along with some smaller components.

One might argue that it is still possible to have multiple components in the same file. However, it is much easier to import components when they are in their own files: if NavBar was in /app/imports/ui/pages/Landing.jsx you would have to somehow remember that every time you wanted to use or modify that NavBar. With NavBar defined within a file named NavBar.jsx, there should be no confusion as to where that component is located.

Why are ProtectedRoute and AdminProtectedRoute separate?

ProtectedRoute requires a user who is logged in whereas AdminProtectedRoute requires an admin user who is logged in.

Is ProtectedRoute similar to the protected header in C++?

Not really; they both restrict access in some way, but protected has to do with class inheritance whereas ProtectedRoute is defined in the template as a route requiring the user to be logged in.

If you have multiple subscriptions on a page, is it possible to wait for a set of those subscriptions to become ready before updating the page or will the page automatically update upon any change to any of the subscriptions?

Yes; see the Meteor documentation on subscription readiness.

Is this publication and subscription model similar to how Google, Amazon, Facebook, etc. retrieve and display data?

Meteor’s publish/subscribe technology is an implementation of the publish-subscribe design pattern which is in wide use across the industry. For example, any technology stack employing Redis for data caching or ZeroMQ for distributed messaging is using the publish-subscribe model. So, it’s extremely likely that Google, Amazon, Facebook and all the rest are using publish-subscribe at some point in their tech stack.

Facebook has open sourced one of its primary data retrieval technologies, which is called GraphQL (https://graphql.org/). As noted above, it is simple to use GraphQL in Meteor applications in conjunction with or to entirely replace publish-subscribe.

Forms

How does error checking work?

This course uses Uniforms in conjunction with Simple Schema to accomplish this; see the documentation for those tools for more details. Essentially, Uniforms uses the schema created with Simple Schema to generate and format the form displayed on the page.

Dr. Johnson mentions “spinners” in the screencast, but the actual component is Loader. Why the difference?

The Semantic UI developers did not want you to confuse the Loader component with Spinners.

These are not mutually exclusive options: you can provide the Reset Password link while still tracking the number of unsuccessful login attempts. You could add an integer field to the users collection to store the number of consecutive failed logins and update that in handleSubmit in the Signin page.

How can we validate that an email address is an actual email address?

To verify that the string is a valid email address, use SimpleSchema.RegEx.Email or SimpleSchema.RegEx.EmailWithTLD. Checking if the email address actually exists is more difficult and your teaching assistant does not have an answer to that beyond sending an email to that address.

Is it possible to sort the data displayed on the page?

Yes, and you have already done something like this.

Can we combine pages together? For example, could we merge the Add Stuff, Edit Stuff, and List Stuff pages to form one Stuff page where we can see the existing Stuffs as we add and modify items?

This is absolutely possible; you would just have to modify the relevant .jsx files. Whether you should do this is a philosophical question. On one hand, combining all of the possible actions on a collection into a single page reduces the amount of navigation necessary, and seeing what is already in the collection may be useful when adding new items (ex. ensuring that you are not creating a duplicate of something already in the database). On the other hand, doing this will put a lot of data on one page, resulting in a potentially confusing and cluttered user interface.

Is it possible to combine the two Meteor.publish calls in /app/imports/startup/server/stuff.js so the application only uses one subscription for Stuffs?

It is certainly possible to combine the conditional logic so the Stuff subscription returns all Stuffs for admins and only the items that the user owns for non-admins. The template application separates the publications because it displays the Stuffs differently on different pages: an admin may want to see all Stuffs or just the Stuffs that he or she is directly associated with.

How can we further customize the forms? Can we use CSS to add new styles to the form elements?

See the documentation and assigned reading for Uniforms; in particular, note that you are not restricted to only text fields and dropdowns. You may also use /app/client/style.css (or any other .css file that you import) to style the elements in the form.

Is it possible to validate the AutoForm without the fake username?

Try moving the const owner line from submit to render and setting the value of the HiddenField to { owner }.

/app/imports/ui/pages/AddStuff.jsx defines insertCallback and submit methods with parameters, but those parameters are not provided when the method is used. How does the method receive those parameters?

The methods are used as follows:

<AutoForm ref={(ref) => { this.formRef = ref; }} schema={StuffSchema} onSubmit={this.submit}>
Stuffs.insert({ name, quantity, condition, owner }, this.insertCallback);

In both cases, the method is not actually called at that point: this.submit is set as the handler for the onSubmit event and this.insertCallback is passed as an argument to Stuffs.insert. As you will recall from the functional programming module earlier in the semester, functions are data in JavaScript and so you can store them in variables, pass them as arguments to other functions, etc. The methods are actually called at some other time within the code for AutoForm and Collection#insert respectively.

Are there any restrictions on the components we can create?

You are restricted only by your imagination.

Where does the error in /app/imports/ui/pages/EditStuff.jsx come from?

The code referenced is:

(error) => (error ?
swal('Error', error.message, 'error') :
      swal('Success', 'Item updated successfully', 'success')));

This is an arrow function, so error is the parameter for the function defined here. The function is not being called, only defined. For a complete look at how this function is used:

/** On successful submit, insert the data. */
submit(data) {
const { name, quantity, condition, _id } = data;
Stuffs.update(_id, { $set: { name, quantity, condition } }, (error) => (error ?
  swal('Error', error.message, 'error') :
  swal('Success', 'Item updated successfully', 'success')));
}

So the arrow function (with error as its parameter) is passed as an argument to Stuffs.update.

Is it possible to filter the range of possible inputs based on a specific set of valid values?

If you want to restrict the range of inputs, it is best to design the form to only allow those specific inputs rather than waiting until the user submits the form to perform validation. If the input is a string, use a dropdown; if the input is a number, use a number field, etc.

How does the Uniforms package save the form data into the database?

The onSubmit attribute for the AutoForm component indicates the code to execute when the form is submitted. In both /app/imports/ui/pages/AddStuff.jsx and /app/imports/ui/pages/EditStuff.jsx, onSubmit is set to this.submit, referring to a submit method defined within the class. This submit function takes care of the database operations.

Can we perform more specific validations, ex. limiting the name to only alphanumeric characters?

Yes, though this would likely require you to use regular expressions (and not just the constants referenced in the Simple Schema documentation).

Does input prevent users from overflowing the input to gain admin access?

No, though the type of vulnerability you are referring to would be attacked through a different route.

The Add Stuff and Edit Stuff pages are essentially the same; why do we need two separate pages to do the same thing?

Although the pages look the same, they serve different roles. Add Stuff creates an entirely new Stuff whereas Edit Stuff modifies an existing Stuff. One uses insert while the other uses update. If you made a single page for both tasks, you would have to perform some conditional logic to set up the form for the correct operation and that would be more complex than just having two separate pages/

Separating the add and edit processes also matches the CRUD operations.

With that being written, it is perfectly valid to argue that while the pages may have different purposes the forms within those pages are nearly identical. It would then be reasonable to extract the form fields into a new component that you could then use in both AddStuff.jsx and EditStuff.jsx.

Can users specify the unit of measurement (ex. for the quantity in the sample application)?

You could do this with another field in the document and a corresponding input in the form.

What is the model={this.props.doc} attribute in the AutoForm in /app/imports/ui/pages/EditStuff.jsx?

The model contains the data to display in the form.

Why does meteor-example-form-react place schemas into a forms directory?

Both CreateStudent and EditStudent use the StudentFormSchema defined in StudentFormInfo.js. The forms directory therefore serves as a convenient location to store these schemas. Also note that CreateStudent and EditStudent modify multiple collections in their respective submit methods. The schemas attached to the collections defined in the /api directory are specific to those individual schemas, but CreateStudent and EditStudent need to modify both StudentData and EnrollmentData. StudentFormSchema therefore serves as a separate schema that includes all of the fields to pass to the AutoForm.

This differs from what you have seen in meteor-application-template-react where the forms modify only a single collection. EditStuff uses the StuffSchema defined for the Stuffs collection. AddStuff defines a new formSchema that omits the owner field that would have been required in StuffSchema.

Authorization, Authentication, and Roles

How does the application differentiate between regular and admin users?

One example of this is in /app/imports/ui/components/Navbar.jsx:

{Roles.userIsInRole(Meteor.userId(), 'admin') ? (
    <Menu.Item as={NavLink} activeClassName="active" exact to="/admin" key='admin'>Admin</Menu.Item>
) : ''}

This uses the ternary operator to display the Admin menu item if the user is an admin and '' otherwise. The condition here is Roles.userIsInRole(Meteor.userId(), 'admin'); Roles.userIsInRole takes the ID of the user to examine and the role to search for as its arguments. For more details, see the documentation for Roles.userIsInRole.

Why is there no explicit check for the user being a regular user?

In the template you are using, the roles property is set to ['admin'] if the user is an admin user; if that is not the case, the only other option is that the user is a standard user.

How do you add new admin users without using /config/settings.development.json?

You can add the “admin” role to an existing user through a MongoDB command, ex. db.users.update({username: "john@foo.com"}, { $set: { roles: ["admin"] }});.

However, note that this must be done on the server-side.

Are there any roles besides “user” and “admin” in the template?

The template only provides these two roles; these roles are ultimately just strings stored in an array field in the users collection though, so all you need to do in order to create new roles is decide on a name for the role and add conditional logic to perform certain actions for that role. For more information, see the documentation for meteor-roles.

Are there any limits on the number of regular or admin users?

After a while your machine would probably run out of memory, but other than that there are no limits on the number of documents in a collection.

How can a user modify a document that he or she did not create?

Creating data does not inherently protect it from modification by others; if you want to ensure that users can only modify their own data, you would have to add in the logic for that yourself. For example, you can publish to the client-side only documents owned by the logged-in user.

Are there ethical concerns about having an admin user who can see all of the data on the site?

Absolutely; we have an Ethics in Software Engineering module later in the semester and you might also consider ICS 390 for further discussion of ethical issues in Computer Science.

What prevents users from changing their own roles, ex. a regular user changing his or her role to be an admin?

Mostly the fact that not even admins can make new admins in the template application. If you add that functionality in, you can use AdminProtectedRoute from /app/imports/ui/layouts/App.jsx to prevent standard users from accessing pages that only admins should have access to.

Does Meteor support group roles for users?

Yes, though it is more accurate to write that meteor/alanning:roles provides this; documentation is available here.

What prevents users from accessing admin pages?

/app/imports/ui/layouts/App.jsx uses AdminProtectedRoute for the admin page. AdminProtectdRoute redirects the user to the signin page if the current user is not an admin (the isLogged && isAdmin). Consequently, the current user must be an admin to access the page even if the user has typed in the URL of the admin page manually.

If there are multiple admins, can each admin see the _Stuff_s associated with other admins?

Yes, the ListStuffAdmin page displays everything in the Stuffs collection.

Can we show an error message (perhaps using swal) when the user attempts to access an admin page instead of redirecting to the signin page?

Yes.

How are we able to use ProtectedRoute and AdminProtectedRoute in the same way as a React component when they do not extend React.Component?

Although neither ProtectedRoute or AdminProtectedRoute extend React.Component, they are functions that return a Route, which is a component we can use in the render method.

Are there roles that allow the user to view or modify the source code for the website?

No, not to my knowledge. The source code for the website should only be available on GitHub, so without access to the repository there should not be any means of viewing or modifying the source code.

Can users change the roles of other users?

Yes.

What happens when you forget your password?

The answer to this depends on how much the IT staff likes you.

Should a user be able to see that someone else has modified an item that he or she owns?

This would depend on the application.

Are there alternatives to meteor/accounts-base and meteor/alanning:roles? Why did we choose this combination of libraries? Are there benefits to using any alternatives that may exist?

There are almost always alternative libraries for anything you might use; meteor/accounts-base and meteor/alanning:roles are the libraries used in the offical Meteor documentation though.

How would we record IP addresses for logins?

See the answers to this Stack Overflow question.

How would we add more sophisticated login processes (ex. multi-factor authentication, CAPTCHA)?

One way to support multi-factor authentication is through CAS. For example, the RadGrad application uses CAS authentication, which can be multi-factor.

For reCAPTCHA, see the Meteor-reCAPTCHA project (with the caveat that I have not tested this code myself).

Errors

Warning: React.createElement: type is invalid – expected a string (for built-in components) or a class/function (for composite components) but got: object.

As the warning message indicates, one of your components is most likely missing an export keyword. The rest of the error message will suggest the component that you should start looking at. See the Named vs. Default Exports screencast for more details.

The meteor command is not found on the command line.

Ensure that the path to your .meteor directory is on the PATH.

The eslint command is not found on the command line.

See the Troubleshooting portion of the ESLint installation instructions.

Miscellaneous Questions

Is Meteor used for real-life applications4?

Meteor is one of the top 10 most used web application frameworks. Also see the Meteor showcase, though the most important example for you is clearly RadGrad.

What is a hook function?

See the answers to this Stack Overflow question; this should not be confused with hooking.

How can we easily know what Semantic UI tools are available to us?

See the Semantic UI React documentation.

There is no direct relationship between React and Meteor; Meteor supports React but is not inherently tied to React in order to work. Recall that one of the early steps in the Meteor React Tutorial (specifically https://www.meteor.com/tutorials/react/components) was to install React, so Meteor is not dependent on React. In turn, you used React before learning about Meteor, so React does not require Meteor either.

How difficult would it be to use another UI framework in Meteor?

Not difficult. Meteor is entirely decoupled from the UI framework.

Can Meteor be used for real-time apps involving large quantities of data (ex. multiplayer games)?

Yes, of course. Interestingly, real-time communication is one area in which Meteor excels. For example, it is almost trivial to create a real-time chat app in Meteor—for example, Make a live chat app in under 2 hours with Meteor. Meteor’s publish-subscribe technology makes it possible to create real-time apps with significantly less code and less opportunity for errors than traditional web application frameworks, which require HTML hacks such as AJAX to do real-time updates.

That said, as the amount of data to be manipulated grows, the developer must become increasingly thoughtful about how to manage it, and that is just as true for a Meteor-based app as it is for a non-Meteor-based app. Note that the publish-subscribe technology is not the only way to manage communication of data between client and server in Meteor. Another approach is Meteor Methods, which is the Meteor implementation of remote procedure calls.

What makes Meteor unique among all the web application frameworks out there?

It is the only one named Meteor.

More seriously, here are some interesting features of Meteor:

Archived Questions

These questions were from previous semesters and are no longer pertinent to current course material; however, the questions and answers are preserved here for posterity.

Why “Bert Alert”?

Ask the developer.

What options are available so that Bert alert does not block the navbar?

See the Bert documentation, especially the API & Defaults and Customization sections.

Unanswered Questions

This section contains questions I haven’t yet answered or am still working on.

Footnotes

0: Given the author, these answers are likely to make matters even more confusing. 1: Your teaching assistant remembers one instance where two projects both used PostgreSQL and the Users table in one project overwrote all the users for the other project. 2: The correct term for this is cracker, not hacker. 3: It is theoretically possible for two different passwords to have the same hash value; each character in this hashed value can be one of sixty-five characters and the bcrypt value is sixty characters long, so there are 5,953,898,114,759,757,583,498,133,232,325,552,989,993,673,976,517,266,254,986,001,716,363,076,818,883,115,493,008,517,660,200,595,855,712,890,625 possible hash values. As opposed to fake-life applications.