Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
187 changes: 139 additions & 48 deletions cloudformation/iam.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
AWSTemplateFormatVersion: "2010-09-09"
Description: Stack IAM Roles
Transform: AWS::Serverless-2016-10-31

Parameters:
RunEnvironment:
Type: String
Expand All @@ -14,8 +15,9 @@ Parameters:
Type: String
SqsQueueArn:
Type: String

Resources:
ApiLambdaIAMRole:
SqsLambdaIAMRole:
Type: AWS::IAM::Role
Properties:
ManagedPolicyArns:
Expand All @@ -30,7 +32,8 @@ Resources:
Service:
- lambda.amazonaws.com
Policies:
- PolicyDocument:
- PolicyName: ses-membership
PolicyDocument:
Version: "2012-10-17"
Statement:
- Action:
Expand All @@ -40,20 +43,85 @@ Resources:
Resource: "*"
Condition:
StringEquals:
ses:FromAddress: !Sub "membership@${SesEmailDomain}"
ses:FromAddress:
Fn::Sub: "membership@${SesEmailDomain}"
ForAllValues:StringLike:
ses:Recipients:
- "*@illinois.edu"
PolicyName: ses-membership
- PolicyDocument:

- PolicyName: lambda-logs
PolicyDocument:
Version: "2012-10-17"
Statement:
- Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Effect: Allow
Resource:
- Fn::Sub: arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${LambdaFunctionName}:*

- PolicyName: lambda-db-secrets
PolicyDocument:
Version: "2012-10-17"
Statement:
- Action:
- secretsmanager:GetSecretValue
Effect: Allow
Resource:
- Fn::Sub: arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:infra-core-api-config*

- PolicyName: lambda-dynamo
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: DynamoDBTableAccess
Effect: Allow
Action:
- dynamodb:BatchGetItem
- dynamodb:BatchWriteItem
- dynamodb:ConditionCheckItem
- dynamodb:PutItem
- dynamodb:DescribeTable
- dynamodb:DeleteItem
- dynamodb:GetItem
- dynamodb:Scan
- dynamodb:Query
- dynamodb:UpdateItem
Resource:
- Fn::Sub: arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-cache

- Sid: DynamoDBDescribeLimitsAccess
Effect: Allow
Action:
- dynamodb:DescribeLimits
Resource: "*"

ApiLambdaIAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Action:
- sts:AssumeRole
Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Policies:
- PolicyName: lambda-sqs
PolicyDocument:
Version: "2012-10-17"
Statement:
- Action:
- sqs:SendMessage
Effect: Allow
Resource: !Ref SqsQueueArn
PolicyName: lambda-sqs
- PolicyDocument:
Resource:
- Fn::Sub: "${SqsQueueArn}"

- PolicyName: lambda-logs
PolicyDocument:
Version: "2012-10-17"
Statement:
- Action:
Expand All @@ -63,59 +131,82 @@ Resources:
Effect: Allow
Resource:
- Fn::Sub: arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${LambdaFunctionName}:*
- Effect: Allow
Action:
- ec2:CreateNetworkInterface
- ec2:DescribeNetworkInterfaces
- ec2:DeleteNetworkInterface
- ec2:DescribeSubnets
- ec2:DeleteNetworkInterface
- ec2:AssignPrivateIpAddresses
- ec2:UnassignPrivateIpAddresses
Resource: "*"
PolicyName: lambda
- PolicyDocument:
Version: 2012-10-17

- PolicyName: lambda-db-secrets
PolicyDocument:
Version: "2012-10-17"
Statement:
- Action:
- secretsmanager:GetSecretValue
Effect: Allow
Resource:
- !Sub arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:infra-core-api-config*
PolicyName: lambda-db-secrets
- PolicyDocument:
Version: 2012-10-17
- Fn::Sub: arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:infra-core-api-config*

- PolicyName: lambda-dynamo
PolicyDocument:
Version: "2012-10-17"
Statement:
- Action:
- dynamodb:*
- Sid: DynamoDBIndexAccess
Effect: Allow
Action:
- dynamodb:Query
Resource:
- Fn::Sub: arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-stripe-links/index/*
- Fn::Sub: arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-events/index/*

- Sid: DynamoDBStreamAccess
Effect: Allow
Action:
- dynamodb:GetShardIterator
- dynamodb:DescribeStream
- dynamodb:GetRecords
- dynamodb:ListStreams
Resource:
- Fn::Sub: arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-stripe-links/stream/*
- Fn::Sub: arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-events/stream/*

- Sid: DynamoDBTableAccess
Effect: Allow
Action:
- dynamodb:BatchGetItem
- dynamodb:BatchWriteItem
- dynamodb:ConditionCheckItem
- dynamodb:PutItem
- dynamodb:DescribeTable
- dynamodb:DeleteItem
- dynamodb:GetItem
- dynamodb:Scan
- dynamodb:Query
- dynamodb:UpdateItem
Resource:
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-events/*
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-events
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-cache
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-cache/*
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-merchstore-purchase-history/*
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-merchstore-purchase-history
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-events-tickets
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-events-tickets/*
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-events-ticketing-metadata/*
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-events-ticketing-metadata
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-merchstore-metadata/*
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-merchstore-metadata
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-iam-userroles
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-iam-userroles/*
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-iam-grouproles
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-iam-grouproles/*
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-stripe-links
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-stripe-links/*
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-membership-provisioning
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-membership-provisioning/*
- Fn::Sub: arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-events
- Fn::Sub: arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-cache
- Fn::Sub: arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-merchstore-purchase-history
- Fn::Sub: arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-events-tickets
- Fn::Sub: arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-events-ticketing-metadata
- Fn::Sub: arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-merchstore-metadata
- Fn::Sub: arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-iam-userroles
- Fn::Sub: arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-iam-grouproles
- Fn::Sub: arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-stripe-links
- Fn::Sub: arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-membership-provisioning

- Sid: DynamoDBDescribeLimitsAccess
Effect: Allow
Action:
- dynamodb:DescribeLimits
Resource: "*"

PolicyName: lambda-dynamo
Outputs:
MainFunctionRoleArn:
Description: Main API IAM role ARN
Value:
Fn::GetAtt:
- ApiLambdaIAMRole
- Arn

SqsFunctionRoleArn:
Description: Sqs IAM role ARN
Value:
Fn::GetAtt:
- SqsLambdaIAMRole
- Arn
3 changes: 2 additions & 1 deletion cloudformation/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,8 @@ Resources:
FunctionName: !Sub ${ApplicationPrefix}-sqs-lambda
Handler: index.handler
MemorySize: 512
Role: !GetAtt AppSecurityRoles.Outputs.MainFunctionRoleArn
Role:
Fn::GetAtt: AppSecurityRoles.Outputs.SqsFunctionRoleArn
Timeout: !Ref SqsLambdaTimeout
LoggingConfig:
LogGroup: !Sub /aws/lambda/${ApplicationPrefix}-lambda
Expand Down
33 changes: 25 additions & 8 deletions src/ui/pages/events/ViewEvents.page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
import { Text, Button, Table, Modal, Group, Transition, ButtonGroup, Title } from '@mantine/core';
import {
Text,
Button,
Table,
Modal,
Group,
Transition,
ButtonGroup,
Title,
Badge,
Anchor,
} from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import { notifications } from '@mantine/notifications';
import { IconPlus, IconTrash } from '@tabler/icons-react';
Expand Down Expand Up @@ -65,13 +76,21 @@ export const ViewEventsPage: React.FC = () => {
style={{ ...styles, display: shouldShow ? 'table-row' : 'none' }}
key={`${event.id}-tr`}
>
<Table.Td>{event.title}</Table.Td>
<Table.Td>
{event.title} {event.featured ? <Badge color="green">Featured</Badge> : null}
</Table.Td>
<Table.Td>{dayjs(event.start).format('MMM D YYYY hh:mm')}</Table.Td>
<Table.Td>{event.end ? dayjs(event.end).format('MMM D YYYY hh:mm') : 'N/A'}</Table.Td>
<Table.Td>{event.location}</Table.Td>
<Table.Td>{event.description}</Table.Td>
<Table.Td>
{event.locationLink ? (
<Anchor target="_blank" size="sm" href={event.locationLink}>
{event.location}
</Anchor>
) : (
event.location
)}
</Table.Td>
<Table.Td>{event.host}</Table.Td>
<Table.Td>{event.featured ? 'Yes' : 'No'}</Table.Td>
<Table.Td>{capitalizeFirstLetter(event.repeats || 'Never')}</Table.Td>
<Table.Td>
<ButtonGroup>
Expand All @@ -98,7 +117,7 @@ export const ViewEventsPage: React.FC = () => {
useEffect(() => {
const getEvents = async () => {
const response = await api.get('/api/v1/events');
const upcomingEvents = await api.get('/api/v1/events?upcomingOnly=true');
const upcomingEvents = await api.get(`/api/v1/events?upcomingOnly=true&ts=${Date.now()}`);
const upcomingEventsSet = new Set(upcomingEvents.data.map((x: EventGetResponse) => x.id));
const events = response.data;
events.sort((a: EventGetResponse, b: EventGetResponse) => {
Expand Down Expand Up @@ -188,9 +207,7 @@ export const ViewEventsPage: React.FC = () => {
<Table.Th>Start</Table.Th>
<Table.Th>End</Table.Th>
<Table.Th>Location</Table.Th>
<Table.Th>Description</Table.Th>
<Table.Th>Host</Table.Th>
<Table.Th>Featured</Table.Th>
<Table.Th>Repeats</Table.Th>
<Table.Th>Actions</Table.Th>
</Table.Tr>
Expand Down
32 changes: 19 additions & 13 deletions tests/e2e/events.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,25 @@ describe("Events tests", () => {
for (let i = 0; i < rows.length; i++) {
const row = rows[i];
const expectedData = expectedTableData[i];
const title = await row.locator("td:nth-child(1)").innerText();
const location = await row.locator("td:nth-child(4)").innerText();
const description = await row.locator("td:nth-child(5)").innerText();
const host = await row.locator("td:nth-child(6)").innerText();
const featured = await row.locator("td:nth-child(7)").innerText();
const repeats = await row.locator("td:nth-child(8)").innerText();

expect(title).toEqual(expectedData.title);
expect(location).toEqual(expectedData.location);
expect(description).toEqual(expectedData.description);
expect(host).toEqual(expectedData.host);
expect(featured).toEqual(expectedData.featured ? "Yes" : "No");
expect(repeats).toEqual(capitalizeFirstLetter(expectedData.repeats));

const title = (await row.locator("td:nth-child(1)").innerText()).trim();
const location = (
await row.locator("td:nth-child(4)").innerText()
).trim();
const host = (await row.locator("td:nth-child(5)").innerText()).trim();
const repeats = (await row.locator("td:nth-child(6)").innerText()).trim();

let expectedTitle = expectedData.title;
if (expectedData.featured) {
expectedTitle = `${expectedData.title} \nFEATURED`;
}

expect(title.trim()).toEqual(expectedTitle.trim());
expect(location).toEqual(expectedData.location.trim());
expect(host).toEqual(expectedData.host.trim());
expect(repeats).toEqual(
capitalizeFirstLetter(expectedData.repeats).trim(),
);
}

expect(page.url()).toEqual("https://core.aws.qa.acmuiuc.org/events/manage");
Expand Down
Loading