Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Email notifications for create,update,delete deployment #182

Merged
merged 16 commits into from
Sep 29, 2023
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions docs/docs/rad-lab-ui/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,20 @@ sidebar_position: 4
# Troubleshooting

Please feel free to reach out and to create a [GitHub issue](https://github.com/GoogleCloudPlatform/rad-lab/issues) in case of any issues or concerns.

## Email Notifications
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the best place for this section is under Global Admin Variables section compared to Troubleshooting section.

And also we should remove the mention of Preferred Google Cloud Region and Zone from Global Admin Variables.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved Email Notifications section to Global Admin Variables

You can optionally enable RAD Lab notification for deployment events. This includes deployment creations, updates, and deletions.

If enabled, the following users/groups (defined in the module's Terraform variables) will receive email notifications:
- The individual taking the action
- `trusted_users`
- `trusted_groups`
- `owner_users`
- `owner_groups`

Currently only sending via gmail is supported. It is recommended to [create a new gmail address](https://support.google.com/mail/answer/56256?hl=en) for this purpose only and generate a `App Password` to authenticate it by followig [Sign in with app passwords](https://support.google.com/mail/answer/185833?hl=en)

acolver marked this conversation as resolved.
Show resolved Hide resolved
You will then provide this email and its password to RAD Lab UI via the `Global Variables` setup.

The email address will be store in Firestore, and email password will be securely stored in Google's [Secret Manager](https://cloud.google.com/secret-manager)

1 change: 1 addition & 0 deletions docs/docs/rad-lab-ui/ui_installation/env-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Firebase environment variables can be found in project settings section of your
- `NEXT_PUBLIC_NOTIFICATION_TOPIC` - Topic created for notifications
- `NEXT_PUBLIC_NOTIFICATION_SUB` - Subscription created for notifications
- `NEXT_PUBLIC_GIT_API_URL` - Url of the public repo to pull the deployment modules
- `SECRET_MANAGER_LOCATION` - Google Cloud region of the Secret Manager instance
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 Questions:

  1. How are we setting this Environment variable ? Are we needing admins to manually update the .env file with the region before UI deployment or using the existing bash script which creates the .env file.

  2. What is the default value of this variable ? Is it the same as app_engine_location variable ?

SOLUTION: If its manually set and we want to automate it like other variables we can expose the above app_engine_location variable as a TF output and we can use the existing bash script to create the .env with the same.

Copy link
Contributor Author

@SachinSogoduRaju SachinSogoduRaju Sep 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

app_engine_location and Secret Manager Location are different things so created new env in outputs and updated in bash script file.


## Git Hub repo envs

Expand Down
1 change: 1 addition & 0 deletions radlab-ui/webapp/.env.development
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ NEXT_PUBLIC_RAD_LAB_DOCS_SITE=https://googlecloudplatform.github.io/rad-lab/
MODULE_DEPLOYMENT_BUCKET_NAME=

GIT_TOKEN_SECRET_KEY_NAME=rad-lab-git-access-token
SECRET_MANAGER_LOCATION=
1 change: 1 addition & 0 deletions radlab-ui/webapp/.env.production
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ NEXT_PUBLIC_RAD_LAB_DOCS_SITE=https://googlecloudplatform.github.io/rad-lab/
MODULE_DEPLOYMENT_BUCKET_NAME=

GIT_TOKEN_SECRET_KEY_NAME=rad-lab-git-access-token
SECRET_MANAGER_LOCATION=

60 changes: 59 additions & 1 deletion radlab-ui/webapp/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion radlab-ui/webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"dependencies": {
"@google-cloud/iam-credentials": "^2.0.0",
"@google-cloud/pubsub": "^3.0.1",
"@google-cloud/secret-manager": "^4.1.3",
"@google-cloud/secret-manager": "^4.2.2",
"@google-cloud/storage": "^6.2.3",
"@headlessui/react": "^1.4.3",
"@heroicons/react": "^1.0.5",
Expand All @@ -28,13 +28,15 @@
"firebase": "^9.6.5",
"firebase-admin": "^11.0.1",
"formik": "^2.2.9",
"handlebars": "^4.7.8",
"hcl2-parser": "^1.0.3",
"lodash": "^4.17.21",
"lodash.debounce": "^4.0.8",
"next": "^12.0.8",
"next-i18next": "^10.2.0",
"next-seo": "^4.29.0",
"next-swagger-doc": "^0.3.4",
"nodemailer": "^6.9.5",
"nookies": "^2.5.2",
"ramda": "^0.28.0",
"react": "^17.0.2",
Expand All @@ -57,6 +59,7 @@
"@types/lodash.debounce": "^4.0.6",
"@types/lunr": "^2.3.4",
"@types/node": "^17.0.45",
"@types/nodemailer": "^6.4.10",
"@types/ramda": "^0.28.11",
"@types/react": "^17.0.38",
"@types/uuid": "^8.3.4",
Expand Down
23 changes: 23 additions & 0 deletions radlab-ui/webapp/public/assets/htmlTemplates/deleteEmail.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<html>
<head>
<style></style>
</head>
<body>
<h3>Hello!</h3>
<p>
RAD Lab Module with deployment ID -
<a href="{{{deployment_link}}}" style="border: 0" target="_blank">
{{deploymentId}}</a
>
has been successfully deleted!
</p>

<br />
<p>Thank you<br /></p>
<img
style="width: 8rem; height: 2rem"
src="https://github.com/GPS-Demos/rad-lab/blob/main/radlab-ui/webapp/public/assets/images/logo.png?raw=true"
/>
<p>P.S:- This is an auto generated email. Please do not reply!</p>
</body>
</html>
60 changes: 60 additions & 0 deletions radlab-ui/webapp/public/assets/htmlTemplates/email.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<html>
<head>
<style>
table {
font-family: arial, sans-serif;
border-collapse: collapse;
width: 40%;
}

td,
th {
border: 1px solid #dddddd;
text-align: left;
padding: 8px;
}
</style>
</head>
<body>
<h3>Hello!</h3>
<p>{{mailBodyTitle}}</p>
<p>Please use below details to access the same.</p>

<table id="myTable">
<tr>
<th>Name</th>
<th>value</th>
</tr>
<tr>
<td>Project Id</td>
<td>
<a href="{{{gcp_project_link}}}" style="border: 0" target="_blank"
>{{projectId}}</a
>
</td>
</tr>
<tr>
<td>Deployment Id</td>
<td>
<a href="{{{deployment_link}}}" style="border: 0" target="_blank"
>{{deploymentId}}</a
>
</td>
</tr>
{{#outputs}}
<tr>
<td>{{name}}</td>
<td>{{value}}</td>
</tr>
{{/outputs}}
</table>

<br />
<p>Thank you<br /></p>
<img
style="width: 8rem; height: 2rem"
src="https://github.com/GPS-Demos/rad-lab/blob/main/radlab-ui/webapp/public/assets/images/logo.png?raw=true"
/>
<p>P.S:- This is an auto generated email. Please do not reply!</p>
</body>
</html>
59 changes: 57 additions & 2 deletions radlab-ui/webapp/src/components/forms/DefaultCreateForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import {
ALERT_TYPE,
Dictionary,
IFormData,
ISecretManagerReq,
IUIVariable,
IVariables,
} from "@/utils/types"
import { mergeAllSafe } from "@/utils/variables"
import axios from "axios"
import { FormikValues } from "formik"
import { useTranslation } from "next-i18next"
import React, { useEffect, useState } from "react"
import { useNavigate } from "react-router-dom"
Expand All @@ -34,9 +36,20 @@ const DefaultCreateForm: React.FC<IDefaultCreateFormProps> = ({
const setAlert = alertStore((state) => state.setAlert)
const user = userStore((state) => state.user)
const navigate = useNavigate()
const [answerValueData, setAnswerValueData] = useState<FormikValues>({})

const handleSubmit = async (values: IFormData) => {
handleLoading(true)

if (values.email_notifications) {
const secretManagerPayload: ISecretManagerReq = {
key: "mailBoxCred",
value: values.mail_server_password,
}
await saveMailBoxCred(secretManagerPayload)
}

delete values.mail_server_password
const payload = Object.assign(values, {
email: user?.email,
})
Expand Down Expand Up @@ -75,14 +88,55 @@ const DefaultCreateForm: React.FC<IDefaultCreateFormProps> = ({
return mergeAllSafe([initialFormData, defaultSettingVariables])
}

const saveMailBoxCred = async (payload: ISecretManagerReq) => {
try {
await axios.post("/api/secret", payload)
} catch (error: any) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we put a proper type here? I believe it's some sort of AxiosErrorResponse

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

catch clause accept only any or unknown type hence used any here

setAlert({
message: error.message,
type: ALERT_TYPE.ERROR,
})
}
}

const handleChangeValues = (answerValues: FormikValues) => {
setAnswerValueData(answerValues)
}

const formatDependsVariables = (
formVariablesData: IUIVariable[],
currentAnswerValueData: FormikValues,
) => {
const allNonDependsVars = formVariablesData.filter(
(formVariableData) =>
formVariableData.name !== "mail_server_email" &&
formVariableData.name !== "mail_server_password",
)
const allDependsVars = formVariablesData.filter(
(formVariableData) =>
formVariableData.name === "mail_server_email" ||
formVariableData.name === "mail_server_password",
)

const notificationAnswer = currentAnswerValueData.email_notifications
const releventParse = allNonDependsVars.concat(
notificationAnswer ? allDependsVars : [],
)
return releventParse
}

useEffect(() => {
if (formVariables.length > 0) {
const initialFormVariable = setDefaultSettingVariables()
setInitialData(initialFormVariable)
const groupedVariableList = groupVariables(formVariables)
const releventParse = formatDependsVariables(
formVariables,
answerValueData,
)
const groupedVariableList = groupVariables(releventParse)
setFormData(groupedVariableList)
}
}, formVariables)
}, [formVariables, answerValueData])

return (
<div className="w-full">
Expand All @@ -98,6 +152,7 @@ const DefaultCreateForm: React.FC<IDefaultCreateFormProps> = ({
variableList={group}
idx={index}
key={grpId}
handleChangeValues={handleChangeValues}
/>
) : (
<></>
Expand Down
Loading