Skip to content

Commit

Permalink
fix: blog lesson 7 solution (#204)
Browse files Browse the repository at this point in the history
* fix: blog lesson 7 solution

* chore: add solution to boilerplates

* add hints suggested in #187

* chore: remove unused impport

* Improve instructions and error messages

* override error when value accessed prematurely

* improve exercise instructions for blog #7

* chore: reword the instructions

* update wording of override instructions

* chore: add syntax errors
  • Loading branch information
fsdiogo authored and terichadbourne committed May 7, 2019
1 parent 26b293e commit 2f640bf
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 22 deletions.
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,9 @@ const validate = async (result, ipfs) => {
if (!result) {
return { fail: 'You forgot to return a result :)' }
} else if (result) {
return { success: 'Happy Message!'}
return { success: 'Happy Message!' }
} else {
return { fail: 'Sad but useful message :('}
return { fail: 'Sad but useful message :(' }
}
}
```
Expand All @@ -212,7 +212,7 @@ If this is the last lesson in your tutorial, the user will see a "More Tutorials

As you test your code, you may notice that you see error messages appear that are different from the ones you provided in your `validate` function. These might include syntax errors noted by our embedded code editor or errors returned by the IPFS API, both of which appear by default. Syntax errors can be very helpful for your user, and other errors might help you identify common errors you hadn't thought of.

If you'd like to replace a specific error message returned automatically with a moire user-friendly message created by you, add the attribute
If you'd like to replace a specific error message returned automatically with a more user-friendly message created by you, add the attribute
`:overrideErrors="true"` to the Lesson (or FileLesson) component at the start of your Vue file like so:

```js
Expand All @@ -226,11 +226,12 @@ Within the `validate` function, add cases for the specific error messages
you need to override, as in this example:

```js
} else if (result && result.error.message === 'No child name passed to addLink') {
} else if (result.error && result.error.message === 'No child name passed to addLink') {
// Forgot the file name and just used a directory as the path
return { fail: 'Uh oh. It looks like you created a folder instead of a file. Did you forget to include a filename in your path?' }
}
```
Be sure to adapt your test case so that it works within the context of your other conditionals to meet your validation needs. What is required is that you return an object with the `fail` key and a string as its value; that string is what will be shown to the user.

You'll also need to add the following lines below your custom validation so that
external error messages you haven't specifically overridden will continue to be shown to the user to aid in troubleshooting:
Expand Down
6 changes: 5 additions & 1 deletion src/tutorials/Blog/07-exercise.md
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
Fill in the body of the `traversePosts()` function. It takes the CID object of the most recent blog post as input. Use that to get the object from IPFS and follow the `prev` links. The return value of the function should be an array with the CID objects of all nodes (including the input CID).
Fill in the body of the `traversePosts()` function. It takes the CID object of the most recent blog post as input. Use that to get the object from IPFS and follow the `prev` links. The return value of the function should be an array with the CID objects of all nodes (including the input CID), starting with the most recent post and ending with the oldest post.

**Hint**: How do you know when you're out of links? Try using a [`while` loop](https://www.digitalocean.com/community/tutorials/using-while-and-do-while-loops-in-javascript) and checking for the presence of a `prev` field in the current object. If it exists, you're not done yet, and you'll need to reset a variable and run the loop again. You'll need to use the [array `push` method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) to add the relevant CIDs to your array as you go. As noted above, be careful to minimize the number of async calls that could create lag time, and remember that `value` doesn't exist until after your `ipfs.dag.get()` function has returned a result. (See the last example above.)

Please __do not__ edit the `run` function, only the `traversePosts` function.
46 changes: 33 additions & 13 deletions src/tutorials/Blog/07.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
:modules="modules"
:exercise="exercise"
:solution="solution"
:overrideErrors="true"
lessonTitle="Traverse through all posts, starting with the most recent" />
</template>

<script>
import Lesson from '../../components/Lesson'
import text from './07.md'
import exercise from './07-exercise.md'
import utils from './utils.js'
import shallowEqualArrays from 'shallow-equal/arrays'
import CID from 'cids'
Expand All @@ -26,6 +26,7 @@ const traversePosts = async (cid) => {
const run = async () => {
const natCid = await ipfs.dag.put({ author: "Nat" })
const samCid = await ipfs.dag.put({ author: "Sam" })
const treePostCid = await ipfs.dag.put({
content: "trees",
author: samCid,
Expand Down Expand Up @@ -57,36 +58,54 @@ const run = async () => {
posts: [dogPostCid]
})
return traversePosts
return traversePosts(dogPostCid)
}
return run`
const validate = async (result, ipfs) => {
if (!result) {
return { fail: 'You forgot to return a result :)' }
return { fail: 'No result was returned. Did you forget to return a result from your traversePosts function? Or perhaps you accidentally edited the run function?' }
}
if (typeof result !== 'function') {
return { fail: 'Return value needs to be a function.' }
if (result.error && result.error.message === `Cannot read property 'prev' of undefined`) {
return { fail: `Cannot read property 'prev' of undefined. Did you try to access the value of ipfs.dag.get() before the function completed?` }
}
if (result.error && result.error.message === `Cannot read property 'value' of undefined`) {
return { fail: `Cannot read property 'value' of undefined. Did you try to access the value of ipfs.dag.get() before the function completed?` }
}
if (result.error) {
return { error: result.error }
}
if (!Array.isArray(result)) {
return { fail: 'The return value of your traversePosts function needs to be an array.' }
}
const dogPostCid = 'zdpuAxe3g8XBLrqbp3NrjaiBLTrXjJ3SJymePGutsRRMrhAKS'
const computerPostCid = 'zdpuAwwT4kGJxT7mgVZRgvmV3ke8qGNZGLuCgLhJsdBSQGM44'
const treePostCid = 'zdpuAri55PR9iW239ahcbnfkFU2TVyD5iLmqEFmwY634KZAJV'
try {
const returnValue = await result(new CID(dogPostCid))
if (returnValue.length !== 3 || returnValue === undefined) {
return { fail: 'Your function needs to return 3 CIDs.' }
if (result.length !== 3 || result === undefined) {
return { fail: 'Your traversePosts function needs to return 3 CIDs' }
}
const isCids = returnValue.every(CID.isCID)
const isCids = result.every(CID.isCID)
if (!isCids) {
return { fail: 'Your function needs to return CIDs.' }
return { fail: 'Your traversePosts function needs to return CIDs.' }
}
const expectedCids = [treePostCid, computerPostCid, dogPostCid]
const returnedCids = returnValue.map(item => item.toBaseEncodedString())
const returnedCids = result.map(item => item.toBaseEncodedString())
if (!shallowEqualArrays(returnedCids.sort(), expectedCids.sort())) {
return { fail: `The CIDs returned by the function ${utils.stringify(returnedCids)} did not match the the expected CIDs ${utils.stringify(expectedCids)}.` }
return {
fail: 'The CIDs returned by the traversePosts function did not match the expected CIDs.',
log: {
returnedCids: returnedCids,
expectedCids: expectedCids
}
}
}
} catch (err) {
return { fail: `Your function threw an error: ${err}.` }
Expand All @@ -113,6 +132,7 @@ const traversePosts = async (cid) => {
const run = async () => {
const natCid = await ipfs.dag.put({ author: "Nat" })
const samCid = await ipfs.dag.put({ author: "Sam" })
const treePostCid = await ipfs.dag.put({
content: "trees",
author: samCid,
Expand Down Expand Up @@ -144,7 +164,7 @@ const run = async () => {
posts: [dogPostCid]
})
return traversePosts
return traversePosts(dogPostCid)
}
return run
Expand Down
11 changes: 9 additions & 2 deletions src/tutorials/boilerplates/boilerplate-file-upload.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
:validate="validate"
:modules="modules"
:exercise="exercise"
:solution="solution"
lessonTitle="REPLACEME" />
</template>

Expand Down Expand Up @@ -32,7 +33,13 @@ const validate = async (result, ipfs) => {
}
const code = `const run = async (files) => {
/* your code here */
// Your code here
}
return run
`
const solution = `const run = async (files) => {
// Your solution here
}
return run
`
Expand All @@ -44,7 +51,7 @@ export default {
FileLesson
},
data: () => {
return { text, validate, code, modules, exercise }
return { text, validate, code, modules, exercise, solution }
}
}
</script>
11 changes: 9 additions & 2 deletions src/tutorials/boilerplates/boilerplate-standard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
:validate="validate"
:modules="modules"
:exercise="exercise"
:solution="solution"
lessonTitle="REPLACEME" />
</template>

Expand Down Expand Up @@ -32,7 +33,13 @@ const validate = async (result, ipfs) => {
}
const code = `const run = async () => {
/* your code here */
// Your code here
}
return run
`
const solution = `const run = async () => {
// Your solution here
}
return run
`
Expand All @@ -44,7 +51,7 @@ export default {
Lesson
},
data: () => {
return { text, validate, code, modules, exercise }
return { text, validate, code, modules, exercise, solution }
}
}
</script>

0 comments on commit 2f640bf

Please sign in to comment.