Skip to content

Commit

Permalink
Merge branch 'master' into gregWIP
Browse files Browse the repository at this point in the history
  • Loading branch information
smattingly authored Feb 21, 2019
2 parents 305438a + 1a54c75 commit 4f4f97b
Show file tree
Hide file tree
Showing 72 changed files with 8,048 additions and 2,696 deletions.
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"FallSport": true,
"SpringSport": true,
"Major": true,
"Student": true
"Student": true,
"Staff": true
// …and any others (e.g. `"Organization": true`)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
},
Expand Down
3 changes: 3 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# All pull reviews to master must be reveiwed by project manager
* @tydingsl
* @Evsus
61 changes: 61 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,64 @@ lib-cov
*.out
*.pid

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Typescript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

# next.js build output
.next
15 changes: 15 additions & 0 deletions .htmlhintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"tagname-lowercase": true,
"attr-lowercase": true,
"attr-value-double-quotes": true,
"tag-pair": true,
"id-unique": true,
"src-not-empty": true,
"attr-no-duplication": true,
"title-require": true,
"alt-require": true,
"csslint": {
"display-property-grouping": true,
"known-properties": true
}
}
15 changes: 15 additions & 0 deletions .nycrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"check-coverage": true,
"skip-full": true,
"lines": 95,
"statements": 95,
"functions": 95,
"branches": 95,
"exclude": [
"test/**/*.js",
"api/controllers/RestController.js"
],
"reporter": [
"lcov"
]
}
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
language: node_js
node_js: "11"
64 changes: 38 additions & 26 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ If the student is using an "unregistered" browser, or the "force update" flag is

Otherwise, if the student is checked out (i.e., they have no open Visit record), they will be taken to the check in (Visit create) form. The form requires them to describe the purpose of their Visit to the NLC. When the form is submitted, a Visit record is created, storing the student's identity, purpose of their visit, the date/time of form submission, and the location (see "Register this browser", below). This is an "open" Visit record; the student is now checked in. The application will display a success message and a "sign out" link. Because the application is used in "kiosk mode" on shared PCs, the student will automatically be logged out after a short delay. The application will display the sign in page.

Otherwise, the student is checked in (i.e., the have an open Visit record). They will be taken to the check out (Visit update form). The form always displays the student's check in date/time and purpose of their visit. It requires them to indicate if that purpose was achieved (Yes, No, or Not sure), if they used a tutor (Yes, No), and if they did, for which courses were they tutored (text area). There is a text area for optional Comments. As a special case, if the date of the student's check in is *not* the current system date, the form asks them to estimate the duration of their visit, in quarter-hour increments, up to a maximum of 8 hours. In the normal case, the student is checking out the same day that they checked in, and the date/time of their check out is automatically captured at form submission. The Visit record is updated with the information from the form, plus a flag that indicates if the duration was estimated or not. The Visit record is now "closed"; the student is checked out. The application will display a success message and a "sign out" link. Because the application is used in "kiosk mode" on shared PCs, the student will automatically be logged out after a short delay. The application will display the sign in page.
Otherwise, the student is checked in (i.e., they have an open Visit record). They will be taken to the check out (Visit update) form. The form always displays the student's check in date/time and purpose of their visit. It requires them to indicate if that purpose was achieved (Yes, No, or Not sure), if they used a tutor (Yes, No), and if they did, for which courses were they tutored (text area). There is a text area for optional Comments. As a special case, if the date of the student's check in is *not* the current system date, the form asks them to estimate the duration of their visit, in quarter-hour increments, up to a maximum of 8 hours. In the normal case, the student is checking out the same day that they checked in, and the date/time of their check out is automatically captured at form submission. (The timestamps automatically placed on Sails models will serve as the check in and (actual, not estimated) check out times.) The Visit record is updated with the information from the form, the duration of the Visit, plus a flag that indicates if the duration was estimated or not. The Visit record is now "closed"; the student is checked out. The application will display a success message and a "sign out" link. Because the application is used in "kiosk mode" on shared PCs, the student will automatically be logged out after a short delay. The application will display the sign in page.

### Voluntary student profile updates

Expand Down Expand Up @@ -160,9 +160,20 @@ Use `Ctrl-C` to terminate the application.

## Running tests

There are three `package.json` scripts for checking code quality in the application.
There are four `package.json` scripts for checking code quality in the application.

- `npm run lint` will check the JavaScript code against the rules defined in `.eslintrc`, and fix some problems that it identifies.
- `npm run htmlhint` will check the HTML content according to the rules defined in `.htmlhintrc`.
- `npm run mocha` will run all automated test cases.
- `npm run coverage` will check how much of the code is tested by the mocha process, enforcing a threshold of 95% or higher.

All four of these scripts are run, in the order listed, when the command `npm test` is issued. Notice that this is a standard script, so the word `run` is not needed.

It is important to run `npm test` and verify successful results before issuing a pull request.

When pull requests to master are created, the Travis CI (continuous integration) service will automatically create a virtual machine in the cloud, clone the application's git repository, run the `npm install` script, and run the `npm test` script.

The pull request will be marked with the CI results, indicating that all status checks passed, or that some failed.

## Components of the application

Expand All @@ -182,6 +193,8 @@ The following minor models exist only as "reference lists." Data for these model
- FallSport: the set of Fall sports that can appear on a student profile
- SpringSport: the set of Spring sports that can appear on a student profile

Each major model should define a `createDevelopmentData` function that creates sample data for the model and possibly for associated minor models. The function should be called from `config/bootstrap.js` in order to populate the database at runtime. See the `Student` model for an example.

### Views

Views present information to the user. For data entry/editing, this means an HTML form; for read-only displays it means some other HTML page.
Expand All @@ -192,8 +205,6 @@ Accordingly, the `student` and `staff` folders (will) have only an `editForm.htm

The Visit component must support creating new records (known as a "check in") and editing existing records (known as a "check out"). So, the `visit` folder will contain `createForm.html` and `editForm.html`, named in anticipation that the `RestController` can be used.

:construction: (Note: more needs to be said (and figured out) about views like what displays after a successful add, edit etc. There will also be a "display list" type view of Visits (staff access only), but I need to build out the structure for that.)

### Controllers

A controller directs and coordinates the behavior of a model and a view. Based on an incoming request, a controller usually instructs a model to perform certain operations, and activates a view to respond to the user. The controller "knows how to talk to" the model and the views; the model and views never communicate directly. When the response to a request contains existing data, the controller requests the needed data from the model, and passes it to the view.
Expand All @@ -206,10 +217,10 @@ For simple [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete)
- `GET /:model/:id/edit`
- `POST /:model/:id`

:construction: More RESTful URLs will be added to the controller.

The `RestController` can communicate with any model driven by the Sails ORM, using the [model API](https://sailsjs.com/documentation/reference/waterline-orm/models#?builtin-model-methods) and the application's helpers (see next section). The `RestController` expects to find a `views/pages` subfolder that is named for the model, containing `createForm.html` and/or `editForm.html` files (depending on which operations are supported.)

Note: in development mode, Sails automatically provides handling of some request using [Blueprints](https://sailsjs.com/documentation/concepts/blueprints). This is a helpful set of features for developers. But be aware that Blueprints are disabled when an application goes into production mode.

### Helpers

The application's helpers are documented [here](https://dewv.github.io/nlcAttendance).
Expand All @@ -221,7 +232,7 @@ The application's helpers are documented [here](https://dewv.github.io/nlcAttend
* Use the present tense ("Add feature" not "Added feature")
* Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
* Limit the first line to 72 characters or less
* Reference issues and pull requests liberally after the first line
* Reference issues and pull requests liberally after the first line. It is generally our practice that code-related Issues are never manually closed; they should close automatically when code is merged to the master branch from commit and/or pull request messages that refer to the Issue.

### JavaScript style checking

Expand All @@ -231,7 +242,7 @@ There are several ways that this tool is activated.

1. It is the tool that produces the icons and associated messages that appear in the "gutter" of the source code editor, next to the line numbers.
2. The terminal command `npm run lint` executes a script in `package.json` that runs the tool and reports any findings. This script runs the tool with its `--fix` flag, which will automatically fix some code issues. Be aware that this can cause otherwise unexpected changes when you run `git status`.
3. The terminal command `npm test` executes a script in `package.json` that first runs the lint script just discussed, and then runs the mocha test script discussed elsewhere.
3. The terminal command `npm test` executes a script in `package.json` that runs the lint script just discussed, along with other code quality scripts discussed elsewhere.

As discussed above, c9 has a problematic expectation for the location of the `.eslintrc` config file; we work around this with a symlink.

Expand All @@ -253,33 +264,34 @@ The bash command `mv` moves a file, which amounts to a rename when the same fold
### mocha style guide

- Include thoughtfully-worded, well-structured mocha tests in the `test` folder.
- Treat `describe` as a noun or situation.
- Treat `it` as a statement about state or how an operation changes state.
- Files that contain test code should be named to match the files that contain the code that they test. (Extensions may differ; all test code will be in `.js` files, but both `.js` and `.html` files will be tested.)
- Use`describe` to identify the component under test.
- Use one or more nested `context` blocks to categorize tests.
- Use`it` to describe expected behavior, usually beginning with the word "should"

#### Example

File `test/views/student/editForm.js` includes the following code to test the behavior of `views/pages/student/editForm.html`. (Note that the `pages` folder was dropped from the `test` file tree because we did not expect to test other `view` folder contents; however, this could change.)

```javascript
TBD
describe("Student views", ...
context("The edit form", ...
it("should include a text input to edit the last name", ...
it("should include select options to edit the fall sport", ...
```
### Documentation Styleguide
### Documentation style guide
* jsdoc, but how?
* Use [Markdown](https://daringfireball.net/projects/markdown).
* Reference methods and classes in markdown with the custom `{}` notation:
* Reference classes with `{ClassName}`
* Reference instance methods with `{ClassName::methodName}`
* Reference class methods with `{ClassName.methodName}`
We use [jsdoc](https://usejsdoc.org/) to generate [our API documentation](https://dewv.github.io/nlcAttendance).
#### Example
This includes documentation for the Request, Response, Record, Model, and Controller concepts from Express/Sails.
```javascript
/**
*/
```
Each model file should document:
1. the model itself, as a module implementing the [Model](https://dewv.github.io/nlcAttendance/docs/Model.html) interface, and
2. a related record type, which implements the [Record](https://dewv.github.io/nlcAttendance/docs/Record.html) interface.
## Additional Notes
Each controller file should document the controller as a module implementing the [Controller](https://dewv.github.io/nlcAttendance/docs/Controller.html) interface.
### Issue and Pull Request Labels
Although Sails helpers are defined in module format, the framework essentially turns them into globally available functions. Accordingly, each helper file documents its helper from the caller's perspective, as if it were a global function.
:construction:
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Attendance Tracking

For the Naylor Learning Center

[![Build Status](https://travis-ci.org/dewv/nlcAttendance.svg?branch=master)](https://travis-ci.org/dewv/nlcAttendance)
23 changes: 16 additions & 7 deletions api/controllers/RestController.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* @module RestController
*
* @description A generic controller for routing standard REST requests to the proper model's view.
* Routes standard REST requests to the proper model's view.
* @implements Controller
* @module
*/
module.exports = {
/**
Expand All @@ -13,7 +13,7 @@ module.exports = {
*/
createFormRequested: async function(request, response) {
let model = sails.models[request.params.model];
let domains = await sails.helpers.getAssociationDomains(model);
let domains = await sails.helpers.getDomains(model);
let ejsData = {
formData: await sails.helpers.getDefaults(model),
action: "/" + request.params.model
Expand All @@ -22,7 +22,7 @@ module.exports = {
for (let domain in domains) {
ejsData[domain] = await sails.helpers.generateHtmlSelect(domain, domains[domain]);
}

console.log(JSON.stringify(ejsData));
return sails.helpers.responseViewSafely(response, `pages/${request.params.model}/createForm`, ejsData);
},

Expand Down Expand Up @@ -50,14 +50,23 @@ module.exports = {
let model = sails.models[request.params.model];
let recordToUpdate = await sails.helpers.populateOne(model, request.params.id);
if (!recordToUpdate) return response.notFound();
let domains = await sails.helpers.getAssociationDomains(model);
let domains = await sails.helpers.getDomains(model);
let ejsData = {
formData: recordToUpdate,
action: `/${request.params.model}/${request.params.id}`
};

for (let domain in domains) {
ejsData[domain] = await sails.helpers.generateHtmlSelect(domain, domains[domain], recordToUpdate[domain] === null ? undefined : recordToUpdate[domain].name);
let selected = undefined;
if (recordToUpdate[domain]) {
if (recordToUpdate[domain].name) {
selected = recordToUpdate[domain].name;
}
else {
selected = recordToUpdate[domain];
}
}
ejsData[domain] = await sails.helpers.generateHtmlSelect(domain, domains[domain], selected);
}

return await sails.helpers.responseViewSafely(response, `pages/${request.params.model}/editForm`, ejsData);
Expand Down
35 changes: 35 additions & 0 deletions api/docs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Document symbols for jsdoc

/**
* Represents a set of structured data, called records.
* @interface Model
* @see {@link https://sailsjs.com/documentation/concepts/models-and-orm/models|Sails Concepts}
* @see {@link https://sailsjs.com/documentation/reference/waterline-orm/models|Sails Reference}
*/

/**
* A uniquely identifiable object that corresponds 1-to-1 with a physical database entry.
* @interface Record
* @see {@link https://sailsjs.com/documentation/concepts/models-and-orm/records|Sails Concepts}
* @see {@link https://sailsjs.com/documentation/reference/waterline-orm/records|Sails Reference}
*/

/**
* A dictionary of request-handling actions.
* @interface Controller
* @see {@link https://sailsjs.com/documentation/concepts/actions-and-controllers#?controllers|Sails Concepts}
*/

/**
* Represents the HTTP request, with properties for the query string, parameters, body, HTTP headers, and so on.
* @external Request
* @see {@link https://sailsjs.com/documentation/reference/request-req|Sails Reference}
* @see {@link http://expressjs.com/en/4x/api.html#req|Express API Reference}
*/

/**
* Represents the HTTP response that an Express app sends when it gets an HTTP request.
* @external Response
* @see {@link https://sailsjs.com/documentation/reference/response-res|Sails Reference}
* @see {@link http://expressjs.com/en/4x/api.html#res|Express API Reference}
*/
8 changes: 4 additions & 4 deletions api/helpers/encode-associations.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
* @name sails.helpers.encodeAssociations
* @description Replaces user-entered association domain values with their corresponding ID/key.
* @function
* @argument {Object} model - A Sails model defining the associations, if any.
* @argument {Object} record - A data record that may contain association domain values that need encoding.
* @return {Object} The record argument, modified so that any association domain values are replace with their ID/key.
* @argument {Model} model - A Sails model defining the associations, if any.
* @argument {Record} record - A data record that may contain association domain values that need encoding.
* @return {Record} The record argument, modified so that any association domain values are replace with their ID/key.
* @async
*/
module.exports = {
Expand Down Expand Up @@ -36,7 +36,7 @@ module.exports = {
for (let property in inputs.model.attributes) {
if (sails.helpers.isAssociation(inputs.model, property)) {
let lookup = await sails.models[inputs.model.attributes[property].model].findOne({ name: inputs.record[property] });
inputs.record[property] = lookup ? lookup.id : null;
inputs.record[property] = lookup ? lookup.id : /* istanbul ignore next */ null;
}
}

Expand Down
Loading

0 comments on commit 4f4f97b

Please sign in to comment.