module "iam_roles" {
source = "[email protected]:mygainwell/pfe-iac-modules.git//terraform/modules/aws/iam-role/? ref=v1.4.8"
for_each = var.common.provision_globals && var.iam_roles != null ? { for item in var.iam_roles : item.name => item } : {}
common = var.common
iam_role = merge(
each.value,
{
assume_role_policy = !each.value.assume_role_policy_from_file && each.value.assume_role_policy_ec2_key ? jsonencode(
merge(flatten([for policy in [
for key, item in module.ec2_instances :
jsondecode(replace(replace(replace(replace(replace(replace(file(each.value.assume_role_policy), " [[account_number]]", data.aws_caller_identity.current.account_id), "[[account_name_abr]]", var.common.account_name_abr), "[[product_name]]", var.common.product_name), "[[tenant_abr]]", var.common.tenant_abr), "/\[\[${key}\]\].*/", "${item.id}""), "/".*\]\].*/", ""))
if strcontains(file(each.value.assume_role_policy), "[[${key}]]")
] : [{
Version = policy.Version
Statement = length(policy.Statement) > 0 ? [{
Sid = length(policy.Statement) > 0 ? policy.Statement[0].Sid : null
Effect = length(policy.Statement) > 0 ? policy.Statement[0].Effect : null
Action = length(policy.Statement) > 0 ? policy.Statement[0].Action : null
Condition = length(policy.Statement) > 0 ? policy.Statement[0].Condition : null
Principal = {
AWS = length(policy.Statement) > 0 ? [
for role in [
for key, item in module.ec2_instances :
jsondecode(replace(replace(replace(replace(replace(replace(file(each.value.assume_role_policy), " [[account_number]]", data.aws_caller_identity.current.account_id), "[[account_name_abr]]", var.common.account_name_abr), "[[product_name]]", var.common.product_name), "[[tenant_abr]]", var.common.tenant_abr), "/\[\[${key}\]\].*/", "${item.id}""), "/".*\]\].*/", ""))
if strcontains(file(each.value.assume_role_policy), "[[${key}]]")
] : role.Statement[0].Principal.AWS[0]
] : []
}
}] : []
}
])
) : each.value.assume_role_policy
}
)
}
module "iam_groups" {
source = "[email protected]:mygainwell/pfe-iac-modules.git//terraform/modules/aws/iam-user- group?ref=v1.4.8"
for_each = var.common.provision_globals && var.iam_groups != null ? { for item in var.iam_groups : item.index_key => item } : {}
common = var.common
iam_user_group = merge(
each.value,
{
policies = [
{
policy_arn = module.iam_roles[each.value.role_name].iam_policy_arn
}
]
}
)
}
I’m using the above code in my formating main.tf file. I have terragrunt.hcl file. Actually My requirement is need to create one s3 bucket with get put and delete permissions, IAM user can able to access the bucket . That Iam user need to be add one IAM group. And here we need to one to communicate with s3 bucket, so we need to create one IAM role. This is my overall requirement. But I coded these thing atlast my getting invalid index error. IS there anything need to change in main.tf file. or else anything need to add var.tf file. My repo structure is I maintained separate folder for policies, There we can take it. we need to give the path of policy.
Rajeswari Ravi is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
import React, { useEffect, useRef, useState } from "react";
import User from "../assets/Images/contact_form_img.png";
import { AiFillDislike, AiFillLike, AiOutlineDelete, AiOutlineDislike, AiOutlineLike } from "react-icons/ai";
import { MdOutlineFavorite, MdOutlineFavoriteBorder } from "react-icons/md";
import { IoMdTime } from "react-icons/io";
import { FaRegComment, FaRegEdit } from "react-icons/fa";
import { IoEyeOutline } from "react-icons/io5";
import { Editor } from "@tinymce/tinymce-react";
import { Link, useParams } from "react-router-dom";
import { apiInstance } from "../API/apiBaseURL";
import { toast } from "sonner";
import moment from "moment";
import DOMPurify from "dompurify";
import Prism from "prismjs";
import "prismjs/themes/prism-tomorrow.css";
import { useForm } from "react-hook-form";
import Pagination from "./Pagination/Pagination";
const QuestionView = () => {
const [like, setLike] = useState(0);
const [dislike, setDislike] = useState(0);
const [isLike, setIsLike] = useState(false);
const [isDislike, setIsDislike] = useState(false);
const [isFavorite, setIsFavorite] = useState(false);
const [question, setQuestion] = useState(null);
const [answers, setAnswers] = useState([]);
const { slug } = useParams();
const [currentPage, setCurrentPage] = useState(1);
const questionPerPage = 5;
const editorRef = useRef(null);
const { register, handleSubmit, reset } = useForm();
const onLikeButtonClick = () => {
if (isDislike) {
setDislike(dislike - 1);
setIsDislike(false);
}
setLike(like + (isLike ? -1 : 1));
setIsLike(!isLike);
};
const onDislikeButtonClick = () => {
if (isLike) {
setLike(like - 1);
setIsLike(false);
}
setDislike(dislike + (isDislike ? -1 : 1));
setIsDislike(!isDislike);
};
const onFavoriteButtonClick = () => {
setIsFavorite(!isFavorite);
};
useEffect(() => {
const fetchData = async () => {
try {
if (slug) {
const response = await apiInstance.get(`questions/show-single-question/${slug}`, {
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
}
});
setQuestion(response.data.data);
}
} catch (error) {
const errorMessage = error.response?.data?.message || error.message;
toast.error(errorMessage);
console.log(error, "error");
}
};
fetchData();
}, [slug]);
const questionId = question?._id;
useEffect(() => {
const fetchAnswers = async () => {
try {
if (questionId) {
const ansRes = await apiInstance.get(`answer/${questionId}?perPage=10&page=1`, {
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
}
});
setAnswers(ansRes.data.data);
}
} catch (error) {
const errorMessage = error.response?.data?.message || error.message;
toast.error(errorMessage);
console.log(error, "error");
}
};
fetchAnswers();
}, [questionId]);
useEffect(() => {
Prism.highlightAll();
}, [answers]);
const getTimeDifference = (createdAt) => {
const now = moment();
const duration = moment.duration(now.diff(moment(createdAt)));
const years = duration.years();
const months = duration.months();
const days = duration.days();
const hours = duration.hours();
const minutes = duration.minutes();
const seconds = duration.seconds();
if (years > 0) return `${years} year${years > 1 ? 's' : ''} ago`;
if (months > 0) return `${months} month${months > 1 ? 's' : ''} ago`;
if (days > 0) return `${days} day${days > 1 ? 's' : ''} ago`;
if (hours > 0) return `${hours} hour${hours > 1 ? 's' : ''} ago`;
if (minutes > 0) return `${minutes} minute${minutes > 1 ? 's' : ''} ago`;
return `${seconds} second${seconds > 1 ? 's' : ''} ago`;
};
const onSubmit = async (data) => {
try {
const editorContent = editorRef.current.getContent();
data.answer = editorContent;
data.questionId = question._id;
const response = await apiInstance.post('answer/write-answer', data, {
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
}
});
setAnswers([response.data.data, ...answers]);
toast.success("Answer submitted successfully");
reset();
} catch (error) {
const errorMessage = error.response?.data?.message || error.message;
toast.error(errorMessage);
console.log(error);
}
};
const indexOfLastQuestion = currentPage * questionPerPage;
const indexOfFirstQuestion = indexOfLastQuestion - questionPerPage;
const currentAnswer = answers.slice(indexOfFirstQuestion, indexOfLastQuestion);
const handlePageChange = (page) => {
setCurrentPage(page);
};
return (
<form onSubmit={handleSubmit(onSubmit)} className="content">
{question && (
<>
<div className="top-question-header d-flex justify-content-between align-items-center">
<div className="user-details-left d-flex align-items-center">
<div className="user-profile">
<img src={User} alt="User Profile" />
</div>
<div className="user-name ms-2">
<h6 className="m-0">{question?.user?.name}</h6>
</div>
</div>
<div className="d-flex align-items-center">
<div className="like d-flex align-items-center me-3">
<div onClick={onLikeButtonClick} style={{ cursor: "pointer" }}>
{isLike ? <AiFillLike style={{ color: "green" }} /> : <AiOutlineLike />}
</div>
<h6 className="m-0 fw-normal ps-1">{like}</h6>
</div>
<div className="like d-flex align-items-center me-3">
<div onClick={onDislikeButtonClick} style={{ cursor: "pointer" }}>
{isDislike ? <AiFillDislike style={{ color: "red" }} /> : <AiOutlineDislike />}
</div>
<h6 className="m-0 fw-normal ps-1">{dislike}</h6>
</div>
<div onClick={onFavoriteButtonClick} style={{ cursor: "pointer" }}>
{isFavorite ? <MdOutlineFavorite style={{ color: "red" }} /> : <MdOutlineFavoriteBorder />}
</div>
</div>
</div>
<div className="title-name my-4">
<h3>{question?.title}</h3>
</div>
<div className="aditional-detail d-flex">
<div className="time me-3">
<IoMdTime />
<span className="ps-1 fw-light">asked {getTimeDifference(question.createdAt)}</span>
</div>
<div className="comment me-3">
<FaRegComment />
<span className="ps-1 fw-light">{answers.length} Answers</span>
</div>
<div className="comment me-3">
<IoEyeOutline />
<span className="ps-1 fw-light">25 Views</span>
</div>
</div>
<div className="question-details my-4">
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(question?.question) }}></div>
<div className="d-flex justify-content-between align-items-center">
<div className="d-flex my-3">
{question?.tags?.map((tag, index) => (
<Link className="question-tag text-decoration-none text-uppercase me-2" key={index}>
{tag}
</Link>
))}
</div>
<div className="d-flex">
<FaRegEdit style={{ width: "20px", height: "20px", marginRight: "10px", color: "blue" }} />
<AiOutlineDelete style={{ width: "20px", height: "20px", color: "red" }} />
</div>
</div>
</div>
</>
)}
<div className="answer-title">
<h4>{answers.length} Answer{answers.length !== 1 && "s"}</h4>
</div>
{currentAnswer.map((answer, index) => (
<div className="answer pb-2 mb-5" key={index}>
<div className="d-flex justify-content-between align-items-center">
<div className="user-details-left d-flex align-items-center">
<div className="user-profile">
<img src={User} alt="User Profile" />
</div>
<div className="user-name ms-2 d-flex align-items-center">
<h6 className="m-0">{answer?.user?.name}</h6>
<span className="ms-2">answered {getTimeDifference(answer?.createdAt)}</span>
</div>
</div>
<div className="d-flex align-items-center">
<div className="like d-flex align-items-center me-3">
<div onClick={onLikeButtonClick} style={{ cursor: "pointer" }}>
{isLike ? <AiFillLike style={{ color: "green" }} /> : <AiOutlineLike />}
</div>
<h6 className="m-0 fw-normal ps-1">{like}</h6>
</div>
<div className="like d-flex align-items-center me-3">
<div onClick={onDislikeButtonClick} style={{ cursor: "pointer" }}>
{isDislike ? <AiFillDislike style={{ color: "red" }} /> : <AiOutlineDislike />}
</div>
<h6 className="m-0 fw-normal ps-1">{dislike}</h6>
</div>
</div>
</div>
<div className="answer-details my-4">
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(answer?.answer) }}></div>
</div>
</div>
))}
<Pagination
currentPage={currentPage}
totalItems={answers.length} // Use the total number of answers
itemsPerPage={questionPerPage}
onPageChange={handlePageChange}
/>
<div className="editor">
<h4 className="mb-4">Write your answer here</h4>
<Editor
apiKey={process.env.REACT_APP_PUBLIC_TINY_MCE_API_KEY}
onInit={(evt, editor) => editorRef.current = editor}
init={{
height: 350,
menubar: false,
plugins: [
"advlist",
"autolink",
"lists",
"link",
"image",
"charmap",
"preview",
"anchor",
"searchreplace",
"visualblocks",
"codesample",
"fullscreen",
"insertdatetime",
"media",
"table",
"wordcount",
],
toolbar:
"undo redo | " +
"codesample | bold italic forecolor | alignleft aligncenter |" +
"alignright alignjustify | bullist numlist outdent indent",
content_style: "body { font-family:Inter; font-size:16px }",
}}
/>
</div>
<p className="text-center mt-4">
Please <Link to={"/login"} className="text-decoration-none">sign in</Link> or <Link to={"/signup"} className="text-decoration-none">create an account</Link> to participate in this conversation.
</p>
<div className="submit-btn mt-4 text-end">
<button type="submit">Submit</button>
</div>
</form>
);
};
export default QuestionView;
enter code here
Jay Kachhadiya is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
2