forked from mui/material-ui
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[docs] Add page feedback (mui#22885)
- Loading branch information
Showing
16 changed files
with
937 additions
and
124 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
FEEDBACK_URL=https://hgvi836wi8.execute-api.us-east-1.amazonaws.com |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
# Rating | ||
|
||
This Lambda function stores and retrieves page feedback using DynamoDB. It is already deployed in the Material-UI AWS account. Request credentials if you need to update dev for testing, or to deploy a new prod version. | ||
|
||
If you wish to deploy your own instance for testing, follow the steps below. | ||
|
||
## Prerequisites | ||
|
||
Create an AWS profile in ~/.aws/credentials called "claudia" with credentials corresponding to an IAM user with AmazonAPIGatewayAdministrator, AWSLambdaFullAccess and IAMFullAccess policies. | ||
You can do that with `aws configure --profile claudia`. | ||
|
||
Create a table in DynamoDB, with a `string` partition key called `id`, and a sort key called `page`. You can do that from the DynamoDB web console, or using the AWS CLI command line. Here is an example command that will create the `feedback-dev` table with the minimal provisioned throughput: | ||
|
||
```bash | ||
aws dynamodb create-table --profile claudia --region us-east-1 \ | ||
--attribute-definitions AttributeName=id,AttributeType=S AttributeName=page,AttributeType=S \ | ||
--key-schema AttributeName=id,KeyType=HASH AttributeName=page,KeyType=RANGE \ | ||
--provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=1 \ | ||
--query TableDescription.TableArn --output text \ | ||
--table-name feedback-dev | ||
``` | ||
|
||
You will need to repeat this command to create a table for production, for example `feedback-prod`. | ||
|
||
For on-demand throughput, replace: | ||
|
||
``` | ||
--provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=1 \ | ||
``` | ||
|
||
with: | ||
|
||
``` | ||
--billing-mode PAY_PER_REQUEST \ | ||
``` | ||
|
||
The project includes an IAM access policy that will grant the lambda function access to the tables. You can edit the [policies/access-dynamodb.json](policies/access-dynamodb.json) file to change the access permissions. These are only applied on create (`yarn setup`). Alternatively, to avoid inadvetantly pushing changes, use the `--policies` flag with `yarn setup` to refer to a copy of this directory, and exclude it in your `~/.gitignore`. | ||
|
||
> ⚠️ You will need to update the "Resource" key in this file with the value returned after creating each table. | ||
## Get started | ||
|
||
> ⚠️ When setting up for the first time, you will need to delete the included `claudia.json` file that is specific to the MUI installation. Alternatively, if making changes to the function that you intend to submit back, then to avoid inadvetantly commiting changes to `claudia.json`, use `--config` with each command to create and use a local config file, and exclude this file in your `~/.gitignore`. | ||
To set this up, first [set up the credentials](https://claudiajs.com/tutorials/installing.html#configuring-access-credentials), then: | ||
|
||
1. run `yarn install` (from the root workspace) to install the dependencies | ||
1. Navigate into the directory of this README, e.g. `cd docs/packages/feedback` | ||
1. run `yarn setup` to create the lambda function on AWS under the default name. | ||
This will also ask you for table names for development and production. | ||
If you used the above AWS command, they will be `feedback-dev` and `feedback-dev` respectively. | ||
1. Test the API using the [example requests below](#testing) | ||
|
||
For subsequent updates, use the `npm run deploy` command. | ||
|
||
## Stage variables | ||
|
||
The table name, stored in the API Gateway stage variables, is passed to each request processor in the `request.env` key-value map. Check out [index.js](index.js) to see it in use. | ||
|
||
The value is set during the first deployment, using `--configure-table-dev` & `--configure-table-prod`. This works using a post-deploy step (check out the last line of [index.js](index.js) for the actual setup, and [Configuring stage variables using post-deployment steps](https://github.com/claudiajs/claudia-api-builder/blob/master/docs/api.md#configuring-stage-variables-using-post-deployment-steps) for more information about the API). | ||
|
||
## The API | ||
|
||
- `POST` to `/feedback` - stores a new rating data object | ||
- `GET` from `/feedback/{id}` - returns all ratings with id `{id}` | ||
- `GET` from `/rating/average` - returns average ratings for all pages | ||
|
||
## Testing | ||
|
||
Claudia will print the API URL after it is created (typically something in the format `https://[API ID].execute-api.[REGION].amazonaws.com/<version>`). Replace `<API-URL>` with that value in the examples below: | ||
|
||
You can test the API by using `curl` (or using a fancier client like [Postman](https://www.getpostman.com/)). Below are some examples with `curl`. | ||
|
||
### Create new feedback | ||
|
||
This will create a feedback entry from the data stored in [example.json](example.json). Change the data in the file to create ratings: | ||
|
||
```bash | ||
curl -H "Content-Type: application/json" -X POST --data @example.json <API-URL>/feedback | ||
``` | ||
|
||
Add the UUID returned to `example.json` with key `id` to store more feedback under the same id. | ||
|
||
### Retrieve feedback | ||
|
||
This will get the feedback stored for ID d6890562-3606-4c14-a765-da81919057d1 | ||
|
||
```bash | ||
curl <API-URL>/feedback/d6890562-3606-4c14-a765-da81919057d1 | ||
``` | ||
|
||
### Retrieve average ratings | ||
|
||
This will get the average feedback stored for all pages | ||
|
||
```bash | ||
curl <API-URL>/feedback/average | ||
``` | ||
|
||
### Testing with the documentation | ||
|
||
Create the file `docs/.env.local` containing an environment variable `FEEDBACK_URL` with your API URL without the version. For example: | ||
|
||
```sh | ||
FEEDBACK_URL=https://abcd123ef4.execute-api.us-east-1.amazonaws.com | ||
``` | ||
|
||
If already running, restart the local docs site. Feedback should now be posted to your deployment. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"lambda": { | ||
"role": "feedback-executor", | ||
"name": "feedback", | ||
"region": "us-east-1" | ||
}, | ||
"api": { | ||
"id": "hgvi836wi8", | ||
"module": "index" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"page": "/components/cards", | ||
"version": "5.0.0", | ||
"rating": 5, | ||
"comment": "Yay!", | ||
"language": "en" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
/* eslint-disable no-console */ | ||
const ApiBuilder = require('claudia-api-builder'); | ||
const AWS = require('aws-sdk'); | ||
const uuid = require('uuid/v4'); | ||
|
||
const api = new ApiBuilder(); | ||
const dynamoDb = new AWS.DynamoDB.DocumentClient(); | ||
|
||
async function dbGet(request, id, page) { | ||
const stage = request.context.stage; | ||
const params = { | ||
TableName: request.env[`${stage}TableName`], | ||
Key: { | ||
id, | ||
page, | ||
}, | ||
ConsistentRead: true, | ||
}; | ||
|
||
try { | ||
console.log('dbGet()', params); | ||
const response = await dynamoDb.get(params).promise(); | ||
console.log({ response }); | ||
return response.Item; | ||
} catch (error) { | ||
console.error(error); | ||
throw error; | ||
} | ||
} | ||
|
||
async function dbPut(request, id, item = {}) { | ||
const stage = request.context.stage; | ||
const { page, rating, comment, version, language } = request.body; | ||
|
||
const params = { | ||
TableName: request.env[`${stage}TableName`], | ||
Item: { | ||
id, | ||
page, | ||
rating, | ||
comment, | ||
version, | ||
language, | ||
dateTime: new Date().toString(), | ||
}, | ||
}; | ||
|
||
await Object.assign(params.Item, item); | ||
|
||
try { | ||
console.log('dbPut()', params); | ||
const response = await dynamoDb.put(params).promise(); | ||
console.log({ response }); | ||
return params.Item; | ||
} catch (error) { | ||
console.error(error); | ||
throw error; | ||
} | ||
} | ||
|
||
async function dbQuery(request, id) { | ||
const stage = request.context.stage; | ||
const params = { | ||
TableName: request.env[`${stage}TableName`], | ||
KeyConditionExpression: 'id = :id', | ||
ExpressionAttributeValues: { | ||
':id': id, | ||
}, | ||
ConsistentRead: true, | ||
}; | ||
|
||
try { | ||
console.log('dbQuery()', params); | ||
const response = await dynamoDb.query(params).promise(); | ||
console.log({ response }); | ||
return response.Items; | ||
} catch (error) { | ||
console.error(error); | ||
throw error; | ||
} | ||
} | ||
|
||
async function updateAverageRating(request, currentUserRating) { | ||
console.log('updateAverageRating()'); | ||
|
||
const id = 'average'; | ||
const pageAverage = await dbGet(request, id, request.body.page); | ||
const average = (pageAverage && pageAverage.rating) || 0; | ||
let count = (pageAverage && pageAverage.count) || 0; | ||
|
||
let rating; | ||
if (currentUserRating !== null) { | ||
rating = (average * count - currentUserRating + request.body.rating) / count; | ||
} else { | ||
rating = (average * count + request.body.rating) / (count + 1); | ||
count += 1; | ||
} | ||
|
||
const newAverageRating = { | ||
rating, | ||
count, | ||
comment: undefined, | ||
language: undefined, | ||
}; | ||
|
||
return dbPut(request, id, newAverageRating); | ||
} | ||
|
||
api.post( | ||
'/feedback', | ||
async (request) => { | ||
console.log('POST /feedback', request.body); | ||
const id = request.body.id || uuid(); | ||
|
||
let currentRating = null; | ||
if (request.body.id) { | ||
const userPage = await dbGet(request, id, request.body.page); | ||
console.log({ userPage }); | ||
currentRating = userPage && userPage.rating; | ||
} | ||
|
||
try { | ||
const result = await dbPut(request, id); | ||
await updateAverageRating(request, currentRating); | ||
return result; | ||
} catch (error) { | ||
console.log(error); | ||
throw error; | ||
} | ||
}, | ||
{ success: 201 }, | ||
); | ||
|
||
api.get('/feedback/{id}', (request) => { | ||
console.log(`GET /feedback/${request.pathParams.id}`); | ||
return (async () => { | ||
const result = await dbQuery(request, request.pathParams.id); | ||
return result.reduce((acc, curr) => { | ||
const { rating, comment, count } = curr; | ||
acc[curr.page] = { rating, comment, count }; | ||
return acc; | ||
}, {}); | ||
})(); | ||
}); | ||
|
||
api.addPostDeployConfig('devTableName', 'DynamoDB Development Table Name:', 'configure-table-dev'); | ||
api.addPostDeployConfig('prodTableName', 'DynamoDB Production Table Name:', 'configure-table-prod'); | ||
|
||
module.exports = api; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{ | ||
"name": "feedback", | ||
"version": "1.0.0", | ||
"description": "Store and retrieve page ratings and comments", | ||
"main": "./index.js", | ||
"license": "MIT", | ||
"author": "Material-UI Team", | ||
"private": true, | ||
"files": [ | ||
"*.js" | ||
], | ||
"scripts": { | ||
"claudia": "claudia --profile claudia", | ||
"curl": "curl -H \"Content-Type: application/json\" -X POST --data @example.json https://hgvi836wi8.execute-api.us-east-1.amazonaws.com/dev/rating", | ||
"setup": "claudia create --profile claudia --version dev --region us-east-1 --api-module index --policies policies --configure-table-dev --configure-table-prod --no-optional-dependencies", | ||
"update": "claudia update --profile claudia --version dev --no-optional-dependencies", | ||
"deploy": "claudia update --profile claudia --version dev --no-optional-dependencies && claudia --profile claudia set-version --version prod", | ||
"reconfigure": "claudia update --profile claudia --configure-db" | ||
}, | ||
"dependencies": { | ||
"claudia-api-builder": "^4.1.2", | ||
"uuid": "^3.3.2" | ||
}, | ||
"devDependencies": { | ||
"claudia": "^5.12.0" | ||
}, | ||
"optionalDependencies": { | ||
"aws-sdk": "^2.766.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"Version": "2012-10-17", | ||
"Statement": [ | ||
{ | ||
"Action": ["dynamodb:DeleteItem", "dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:Query"], | ||
"Effect": "Allow", | ||
"Resource": "arn:aws:dynamodb:us-east-1:446171413463:table/feedback-dev" | ||
}, | ||
{ | ||
"Action": ["dynamodb:DeleteItem", "dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:Query"], | ||
"Effect": "Allow", | ||
"Resource": "arn:aws:dynamodb:us-east-1:446171413463:table/feedback-dev" | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.