Skip to content

Commit c2fa3a8

Browse files
authored
chore(i18n,learn): processed translations (#187)
1 parent 3d4329f commit c2fa3a8

File tree

15,010 files changed

+1995910
-100
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

15,010 files changed

+1995910
-100
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
---
2+
id: 5895f70bf9fc0f352b528e64
3+
title: Use a Template Engine's Powers
4+
challengeType: 2
5+
forumTopicId: 301567
6+
dashedName: use-a-template-engines-powers
7+
---
8+
9+
# --description--
10+
11+
One of the greatest features of using a template engine is being able to pass variables from the server to the template file before rendering it to HTML.
12+
13+
In your Pug file, you're able to use a variable by referencing the variable name as `#{variable_name}` inline with other text on an element or by using an equal sign on the element without a space such as `p=variable_name` which assigns the variable's value to the p element's text.
14+
15+
Pug is all about using whitespace and tabs to show nested elements and cutting down on the amount of code needed to make a beautiful site.
16+
17+
Take the following Pug code for example:
18+
19+
```pug
20+
head
21+
script(type='text/javascript').
22+
if (foo) bar(1 + 5);
23+
body
24+
if youAreUsingPug
25+
p You are amazing
26+
else
27+
p Get on it!
28+
```
29+
30+
The above yields the following HTML:
31+
32+
```html
33+
<head>
34+
<script type="text/javascript">
35+
if (foo) bar(1 + 5);
36+
</script>
37+
</head>
38+
<body>
39+
<p>You are amazing</p>
40+
</body>
41+
```
42+
43+
Your `index.pug` file included in your project, uses the variables `title` and `message`.
44+
45+
Pass those from your server to the Pug file by adding an object as a second argument to your `res.render` call with the variables and their values. Give the `title` a value of `Hello` and `message` a value of `Please log in`.
46+
47+
It should look like:
48+
49+
```javascript
50+
res.render('index', { title: 'Hello', message: 'Please log in' });
51+
```
52+
53+
Now refresh your page, and you should see those values rendered in your view in the correct spot as laid out in your `index.pug` file!
54+
55+
Submit your page when you think you've got it right. If you're running into errors, you can check out the <a href="https://forum.freecodecamp.org/t/advanced-node-and-express/567135#use-a-template-engines-power-2" target="_blank" rel="noopener noreferrer nofollow">project completed up to this point</a>.
56+
57+
# --hints--
58+
59+
Pug should correctly render variables.
60+
61+
```js
62+
async () => {
63+
const url = new URL("/", code);
64+
const res = await fetch(url);
65+
const data = await res.text();
66+
assert.match(
67+
data,
68+
/pug-variable("|')>Please log in/gi,
69+
'Your projects home page should now be rendered by pug with the projects .pug file unaltered'
70+
);
71+
}
72+
```
73+
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
---
2+
id: 5895f70ef9fc0f352b528e6b
3+
title: How to Put a Profile Together
4+
challengeType: 2
5+
forumTopicId: 301554
6+
dashedName: how-to-put-a-profile-together
7+
---
8+
9+
# --description--
10+
11+
Now that you can ensure the user accessing the `/profile` is authenticated, you can use the information contained in `req.user` on your page.
12+
13+
Pass an object containing the property `username` and value of `req.user.username` as the second argument for the `render` method of the profile view.
14+
15+
Then, go to your `profile.pug` view, and add the following line below the existing `h1` element, and at the same level of indentation:
16+
17+
```pug
18+
h2.center#welcome Welcome, #{username}!
19+
```
20+
21+
This creates an `h2` element with the class `center` and id `welcome` containing the text `Welcome,` followed by the username.
22+
23+
Also, in `profile.pug`, add a link referring to the `/logout` route, which will host the logic to unauthenticate a user:
24+
25+
```pug
26+
a(href='/logout') Logout
27+
```
28+
29+
Submit your page when you think you've got it right. If you're running into errors, you can <a href="https://forum.freecodecamp.org/t/advanced-node-and-express/567135#how-to-put-a-profile-together-9" target="_blank" rel="noopener noreferrer nofollow">check out the project completed up to this point</a>.
30+
31+
# --hints--
32+
33+
You should correctly add a Pug render variable to `/profile`.
34+
35+
```js
36+
async () => {
37+
const url = new URL("/_api/server.js", code);
38+
const res = await fetch(url);
39+
const data = await res.text();
40+
assert.match(
41+
data,
42+
/username:( |)req.user.username/,
43+
'You should be passing the variable username with req.user.username into the render function of the profile page'
44+
);
45+
}
46+
```
47+
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
---
2+
id: 589a69f5f9fc0f352b528e70
3+
title: Implementation of Social Authentication
4+
challengeType: 2
5+
forumTopicId: 301559
6+
dashedName: implementation-of-social-authentication
7+
---
8+
9+
# --description--
10+
11+
The basic path this kind of authentication will follow in your app is:
12+
13+
1. User clicks a button or link sending them to your route to authenticate using a specific strategy (e.g. GitHub).
14+
2. Your route calls `passport.authenticate('github')` which redirects them to GitHub.
15+
3. The page the user lands on, on GitHub, allows them to login if they aren't already. It then asks them to approve access to their profile from your app.
16+
4. The user is then returned to your app at a specific callback url with their profile if they are approved.
17+
5. They are now authenticated, and your app should check if it is a returning profile, or save it in your database if it is not.
18+
19+
Strategies with OAuth require you to have at least a *Client ID* and a *Client Secret* which is a way for the service to verify who the authentication request is coming from and if it is valid. These are obtained from the site you are trying to implement authentication with, such as GitHub, and are unique to your app--**THEY ARE NOT TO BE SHARED** and should never be uploaded to a public repository or written directly in your code. A common practice is to put them in your `.env` file and reference them like so: `process.env.GITHUB_CLIENT_ID`. For this challenge you are going to use the GitHub strategy.
20+
21+
Follow <a href="https://www.freecodecamp.org/news/how-to-set-up-a-github-oauth-application/" target="_blank" rel="noopener noreferrer nofollow">these instructions</a> to obtain your *Client ID and Secret* from GitHub. Set the homepage URL to your homepage (**not the project code's URL**), and set the callback URL to the same homepage URL with `/auth/github/callback` appended to the end. Save the client ID and your client secret in your project's `.env` file as `GITHUB_CLIENT_ID` and `GITHUB_CLIENT_SECRET`.
22+
23+
In your `routes.js` file, add `showSocialAuth: true` to the homepage route, after `showRegistration: true`. Now, create 2 routes accepting GET requests: `/auth/github` and `/auth/github/callback`. The first should only call passport to authenticate `'github'`. The second should call passport to authenticate `'github'` with a failure redirect to `/`, and then if that is successful redirect to `/profile` (similar to your last project).
24+
25+
An example of how `/auth/github/callback` should look is similar to how you handled a normal login:
26+
27+
```js
28+
app.route('/login')
29+
.post(passport.authenticate('local', { failureRedirect: '/' }), (req,res) => {
30+
res.redirect('/profile');
31+
});
32+
```
33+
34+
Submit your page when you think you've got it right. If you're running into errors, you can <a href="https://forum.freecodecamp.org/t/advanced-node-and-express/567135#implementation-of-social-authentication-3" target="_blank" rel="noopener noreferrer nofollow">check out the project up to this point</a>.
35+
36+
# --hints--
37+
38+
Route `/auth/github` should be correct.
39+
40+
```js
41+
async () => {
42+
try {
43+
const res = await fetch(code + '/_api/routes.js');
44+
if (res.ok) {
45+
const data = await res.text();
46+
assert.match(
47+
data.replace(/\s/g, ''),
48+
/passport.authenticate.*?github/g,
49+
'Route auth/github should only call passport.authenticate with github'
50+
);
51+
} else {
52+
throw new Error(res.statusText);
53+
}
54+
const res2 = await fetch(code + '/_api/app-stack');
55+
if (res2.ok) {
56+
const data2 = JSON.parse(await res2.json());
57+
const dataLayer = data2.find(layer => layer?.route?.path === '/auth/github');
58+
assert.deepInclude(dataLayer?.route, { methods: {get: true}, path: "/auth/github"});
59+
assert.deepInclude(dataLayer?.route?.stack?.[0], {method: "get", name: "authenticate"});
60+
} else {
61+
throw new Error(res2.statusText);
62+
}
63+
} catch (err) {
64+
throw new Error(err);
65+
}
66+
}
67+
```
68+
69+
Route `/auth/github/callback` should be correct.
70+
71+
```js
72+
async () => {
73+
try {
74+
const res = await fetch(code + '/_api/routes.js');
75+
if (res.ok) {
76+
const data = await res.text();
77+
assert.match(
78+
data.replace(/\s/g, ''),
79+
/failureRedirect:("|')\/\1/g,
80+
'Route auth/github/callback should accept a get request and call passport.authenticate for github with a failure redirect to home'
81+
);
82+
} else {
83+
throw new Error(res.statusText);
84+
}
85+
const res2 = await fetch(code + '/_api/app-stack');
86+
if (res2.ok) {
87+
const data2 = JSON.parse(await res2.json());
88+
const dataLayer = data2.find(layer => layer?.route?.path === '/auth/github/callback');
89+
assert.deepInclude(dataLayer?.route, { methods: {get: true}, path: "/auth/github/callback"});
90+
assert.deepInclude(dataLayer?.route?.stack?.[0], {method: "get", name: "authenticate"});
91+
} else {
92+
throw new Error(res2.statusText);
93+
}
94+
} catch (err) {
95+
throw new Error(err);
96+
}
97+
}
98+
```
99+
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
---
2+
id: 589a69f5f9fc0f352b528e71
3+
title: Implementation of Social Authentication II
4+
challengeType: 2
5+
forumTopicId: 301557
6+
dashedName: implementation-of-social-authentication-ii
7+
---
8+
9+
# --description--
10+
11+
The last part of setting up your GitHub authentication is to create the strategy itself. `passport-github@~1.1.0` has already been added as a dependency, so require it in your `auth.js` file as `GitHubStrategy` like this: `const GitHubStrategy = require('passport-github').Strategy;`. Do not forget to require and configure `dotenv` to use your environment variables.
12+
13+
To set up the GitHub strategy, you have to tell Passport to use an instantiated `GitHubStrategy`, which accepts 2 arguments: an object (containing `clientID`, `clientSecret`, and `callbackURL`) and a function to be called when a user is successfully authenticated, which will determine if the user is new and what fields to save initially in the user's database object. This is common across many strategies, but some may require more information as outlined in that specific strategy's GitHub README. For example, Google requires a *scope* as well which determines what kind of information your request is asking to be returned and asks the user to approve such access.
14+
15+
The current strategy you are implementing authenticates users using a GitHub account and OAuth 2.0 tokens. The client ID and secret obtained when creating an application are supplied as options when creating the strategy. The strategy also requires a `verify` callback, which receives the access token and optional refresh token, as well as `profile` which contains the authenticated user's GitHub profile. The `verify` callback must call `cb` providing a user to complete authentication.
16+
17+
Here's how your new strategy should look at this point:
18+
19+
```js
20+
passport.use(new GitHubStrategy({
21+
clientID: process.env.GITHUB_CLIENT_ID,
22+
clientSecret: process.env.GITHUB_CLIENT_SECRET,
23+
callbackURL: /*INSERT CALLBACK URL ENTERED INTO GITHUB HERE*/
24+
},
25+
function(accessToken, refreshToken, profile, cb) {
26+
console.log(profile);
27+
//Database logic here with callback containing your user object
28+
}
29+
));
30+
```
31+
32+
Your authentication won't be successful yet, and it will actually throw an error without the database logic and callback, but it should log your GitHub profile to your console if you try it!
33+
34+
Submit your page when you think you've got it right. If you're running into errors, you can <a href="https://forum.freecodecamp.org/t/advanced-node-and-express/567135#implementation-of-social-authentication-ii-4" target="_blank" rel="noopener noreferrer nofollow">check out the project completed up to this point</a>.
35+
36+
# --hints--
37+
38+
`passport-github` dependency should be added.
39+
40+
```js
41+
async () => {
42+
const url = new URL("/_api/package.json", code);
43+
const res = await fetch(url);
44+
const packJson = await res.json();
45+
assert.property(
46+
packJson.dependencies,
47+
'passport-github',
48+
'Your project should list "passport-github" as a dependency'
49+
);
50+
}
51+
```
52+
53+
`passport-github` should be required.
54+
55+
```js
56+
async () => {
57+
const url = new URL("/_api/auth.js", code);
58+
const res = await fetch(url);
59+
const data = await res.text();
60+
assert.match(
61+
data,
62+
/require.*("|')passport-github("|')/gi,
63+
'You should have required passport-github'
64+
);
65+
}
66+
```
67+
68+
GitHub strategy should be setup correctly thus far.
69+
70+
```js
71+
async () => {
72+
const url = new URL("/_api/auth.js", code);
73+
const res = await fetch(url);
74+
const data = await res.text();
75+
assert.match(
76+
data,
77+
/passport\.use.*new GitHubStrategy/gis,
78+
'Passport should use a new GitHubStrategy'
79+
);
80+
assert.match(
81+
data,
82+
/callbackURL:\s*("|').*("|')/gi,
83+
'You should have a callbackURL'
84+
);
85+
assert.match(
86+
data,
87+
/process\.env(\.GITHUB_CLIENT_SECRET|\[(?<q>"|')GITHUB_CLIENT_SECRET\k<q>\])/g,
88+
'You should use process.env.GITHUB_CLIENT_SECRET'
89+
);
90+
assert.match(
91+
data,
92+
/process\.env(\.GITHUB_CLIENT_ID|\[(?<q>"|')GITHUB_CLIENT_ID\k<q>\])/g,
93+
'You should use process.env.GITHUB_CLIENT_ID'
94+
);
95+
}
96+
```
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
---
2+
id: 589fc832f9fc0f352b528e78
3+
title: Announce New Users
4+
challengeType: 2
5+
forumTopicId: 301546
6+
dashedName: announce-new-users
7+
---
8+
9+
# --description--
10+
11+
Many chat rooms are able to announce when a user connects or disconnects and then display that to all of the connected users in the chat. Seeing as though you already are emitting an event on connect and disconnect, you will just have to modify this event to support such a feature. The most logical way of doing so is sending 3 pieces of data with the event: the username of the user who connected/disconnected, the current user count, and if that username connected or disconnected.
12+
13+
Change the event name to `'user'`, and pass an object along containing the fields `username`, `currentUsers`, and `connected` (to be `true` in case of connection, or `false` for disconnection of the user sent). Be sure to change both `'user count'` events and set the disconnect one to send `false` for the field `connected` instead of `true` like the event emitted on connect.
14+
15+
```js
16+
io.emit('user', {
17+
username: socket.request.user.username,
18+
currentUsers,
19+
connected: true
20+
});
21+
```
22+
23+
Now your client will have all the necessary information to correctly display the current user count and announce when a user connects or disconnects! To handle this event on the client side we should listen for `'user'`, then update the current user count by using jQuery to change the text of `#num-users` to `'{NUMBER} users online'`, as well as append a `<li>` to the unordered list with id `messages` with `'{NAME} has {joined/left} the chat.'`.
24+
25+
An implementation of this could look like the following:
26+
27+
```js
28+
socket.on('user', data => {
29+
$('#num-users').text(data.currentUsers + ' users online');
30+
let message =
31+
data.username +
32+
(data.connected ? ' has joined the chat.' : ' has left the chat.');
33+
$('#messages').append($('<li>').html('<b>' + message + '</b>'));
34+
});
35+
```
36+
37+
Submit your page when you think you've got it right. If you're running into errors, you can check out <a href="https://forum.freecodecamp.org/t/advanced-node-and-express/567135/3#announce-new-users-10" target="_blank" rel="noopener noreferrer nofollow">the project completed up to this point </a>.
38+
39+
# --hints--
40+
41+
Event `'user'` should be emitted with `username`, `currentUsers`, and `connected`.
42+
43+
```js
44+
async () => {
45+
const url = new URL("/_api/server.js", code);
46+
const res = await fetch(url);
47+
const data = await res.text();
48+
// Regex is lenient to match both `username` and `name` as the key on purpose.
49+
assert.match(
50+
data,
51+
/io.emit.*('|")user\1.*name.*currentUsers.*connected/s,
52+
'You should have an event emitted named user sending name, currentUsers, and connected'
53+
);
54+
}
55+
```
56+
57+
Client should properly handle and display the new data from event `'user'`.
58+
59+
```js
60+
async () => {
61+
const url = new URL("/public/client.js", code);
62+
const res = await fetch(url);
63+
const data = await res.text();
64+
assert.match(
65+
data,
66+
/socket.on.*('|")user\1[^]*num-users/s,
67+
'You should change the text of "#num-users" within on your client within the "user" event listener to show the current users connected'
68+
);
69+
assert.match(
70+
data,
71+
/socket.on.*('|")user\1[^]*messages.*li/s,
72+
'You should append a list item to "#messages" on your client within the "user" event listener to announce a user came or went'
73+
);
74+
}
75+
```
76+

0 commit comments

Comments
 (0)