Permalink
Browse files

Add lab README, starting-code & solution-code

  • Loading branch information...
jim-clark
jim-clark committed Feb 9, 2019
0 parents commit cf5031d734bc8fc0372dc3e375c47c649c97babf
@@ -0,0 +1,55 @@
<img src="https://i.imgur.com/2mZHtjU.png">

# Challenge Lab

## Requirements

- Continue to build out this GitHub users app to add search functionality that finds GitHub usernames based upon a provided partial GitHub username's actual name.

- For the UI, display a search form to the left of the existing form.

- When the search form is submitted, display a new view that lists the matching usernames (the way we are listing repos would work well). Here's the result of searching for `Jim Clark`:

<img src="https://i.imgur.com/nIZSDb3.png">

- Clicking on a username in the resulting list would then perform the search and display the user info as the current version of the app does.

## Hints

- The _index.js_ routes file might look something like this when you're done:

```js
router.get('/', githubCtrl.userDetails);
router.post('/', githubCtrl.userDetails);
// new route for searching for a user
router.post('/search', githubCtrl.search);
```

Note that we are able to use the same `githubCtrl.userDetails` controller action in both of these cases:
- When a username is submitted as a `POST /` (implemented in the lesson)
- Or, as part of this exercise, when one of the usernames in the above screenshot is clicked to submit a `GET /` with the username sent within a query string. How to enable this flexibility of being able to extract a username from either a form's `POST` or as a query string in `userDetails` is shown below...

- Refactor by putting the code for the POST route in _routes/index.js_ into a separate controller module. Refactoring will allow us to reuse the code from another route. The `userDetails` action might start like this:

```js
function userDetails(req, res) {
// first get username in a POST scenario and then check
// in a GET scenario (req.query.username)
var username = req.body.username || req.query.username;
if (!username) return res.render('index', {userData: null});
```
Notice how this allows for reuse of the `userDetails` handler and the _index.ejs_ view - whether a username is submitted or not!
- Since the UI for displaying the results for the new name-based search functionality will be very similar to that of the GitHub username search, after you add the new name-based search form on the left-side of _index.ejs_, copy _index.ejs_ to another view named something like _search-results.ejs_.
- The new search will require using the GitHub API's **user\_search\_url** endpoint that accepts a `?q={query}` query string.
- Here are the search docs that explains how to search for users:<br>[https://developer.github.com/v3/search/#search-users](https://developer.github.com/v3/search/#search-users)
- Use the `in:fullname` qualifier so that you can enter part of a name and find matches.
#### Collaboration with your fellow students is suggested - and so is having fun!
@@ -0,0 +1,90 @@
#!/usr/bin/env node

/**
* Module dependencies.
*/

var app = require('../server');
var debug = require('debug')('github-users:server');
var http = require('http');

/**
* Get port from environment and store in Express.
*/

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

/**
* Create HTTP server.
*/

var server = http.createServer(app);

/**
* Listen on provided port, on all network interfaces.
*/

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

/**
* Normalize a port into a number, string, or false.
*/

function normalizePort(val) {
var port = parseInt(val, 10);

if (isNaN(port)) {
// named pipe
return val;
}

if (port >= 0) {
// port number
return port;
}

return false;
}

/**
* Event listener for HTTP server "error" event.
*/

function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}

var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;

// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}

/**
* Event listener for HTTP server "listening" event.
*/

function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
@@ -0,0 +1,43 @@
var request = require('request');
const rootURL = 'https://api.github.com/';

module.exports = {
userDetails,
search
};

function search(req, res) {
var options = {
url: rootURL + 'search/users?q=' + req.body.search + ' in:fullname',
headers: {
'User-Agent': 'jim-clark',
'Authorization': 'token ' + process.env.GITHUB_TOKEN
}
};
request(options, function(err, response, body) {
var usersData = JSON.parse(body);
res.render('search-results', {usersData});
});
}

function userDetails(req, res) {
var username = req.body.username || req.query.username;
if (!username) return res.render('index', {userData: null});
var options = {
url: rootURL + 'users/' + username,
headers: {
'User-Agent': 'jim-clark',
'Authorization': 'token ' + process.env.GITHUB_TOKEN
}
};
request(options, function(err, response, body) {
var userData = JSON.parse(body);
// update the options url to fetch the user's repos
options.url = userData.repos_url;
request(options, function(err, response, body) {
// add a repos property
userData.repos = JSON.parse(body);
res.render('index', {userData});
});
});
}
Oops, something went wrong.

0 comments on commit cf5031d

Please sign in to comment.