Skip to content

Commit

Permalink
Merge branch 'main-stage-13.2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
crayolakat committed Jan 9, 2024
2 parents 39422f3 + c822e8d commit 49415b9
Show file tree
Hide file tree
Showing 12 changed files with 176 additions and 65 deletions.
8 changes: 7 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
{
"extends": ["airbnb", "prettier"],
"parser": "@babel/eslint-parser",
"env": { "jest": true, "node": true, "browser": true, "jasmine": true }
"env": { "jest": true, "node": true, "browser": true, "jasmine": true },
"rules": {
"no-console": [
"warn",
{ "allow": ["warn", "error", "info", "time", "timeEnd"] }
]
}
}
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ If applicable, add screenshots to help explain your problem.
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Desktop or Mobile?
- Version [e.g. 22]
- Spoke Version: [e.g. 13.0.0]

**Additional context**
Add any other context about the problem here.
2 changes: 1 addition & 1 deletion .github/workflows/cypress-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on: [push]
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 10
timeout-minutes: 15
strategy:
matrix:
node-version: [16.x]
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/jest-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 10
timeout-minutes: 15
strategy:
matrix:
node-version: [14.x, 15.x, 16.x]
Expand Down Expand Up @@ -41,7 +41,7 @@ jobs:
run: yarn test
test-rediscache-contactcache:
runs-on: ubuntu-latest
timeout-minutes: 10
timeout-minutes: 15
services:
redis:
image: redis
Expand Down Expand Up @@ -74,7 +74,7 @@ jobs:
run: yarn test-rediscache-contactcache
test-rediscache:
runs-on: ubuntu-latest
timeout-minutes: 10
timeout-minutes: 15
services:
redis:
image: redis
Expand Down Expand Up @@ -107,7 +107,7 @@ jobs:
run: yarn test-rediscache
test-sqlite:
runs-on: ubuntu-latest
timeout-minutes: 10
timeout-minutes: 15
services:
redis:
image: redis
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Want to know more?
### Quick Start with Heroku
This version of Spoke suitable for testing and, potentially, for small campaigns. This won't cost any money and will not support production(aka large-scale) usage. It's a great way to practice deploying Spoke or see it in action.

<a href="https://heroku.com/deploy?template=https://github.com/StateVoicesNational/Spoke/tree/13.1.0">
<a href="https://heroku.com/deploy?template=https://github.com/StateVoicesNational/Spoke/tree/13.2.0">

<img src="https://www.herokucdn.com/deploy/button.svg" alt="Deploy">
</a>
Expand Down
4 changes: 4 additions & 0 deletions dev-tools/create-test-database
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ docker-compose exec -T postgres psql -h localhost -p 5432 -U spoke spokedev <<EO
CREATE USER spoke_test WITH PASSWORD 'spoke_test';
GRANT ALL PRIVILEGES ON DATABASE spoke_test TO spoke_test;
EOF

docker-compose exec -T postgres psql -h localhost -p 5432 -U spoke spoke_test <<EOF
GRANT ALL ON SCHEMA public TO spoke_test;
EOF
25 changes: 18 additions & 7 deletions docs/HOWTO-configure-auth0.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,25 @@ variables.
+ **Allowed Logout URLs** - `https://yourspoke.example.com/logout-callback`
+ **Allowed Origins (CORS)** - `https://yourspoke.example.com`
5. In Advanced Settings, under the OAuth section, turn off 'OIDC Conformant'.
6. Add a [new empty rule](https://manage.auth0.com/#/rules/create) in Auth0:
6. Navigate to [Actions Library](https://manage.auth0.com/#/actions/library).
7. Click "Build Custom".
8. Enter the following fields:
* Name: `Spoke Action`
* Trigger: `Login / Post Login`
* Runtime: `<DEFAULT>`
9. Click "Create".
10. In the code block of the Actions Code Editor, update the `exports.onExecutePostLogin` code as follows:
```javascript
function (user, context, callback) {
context.idToken["https://spoke/user_metadata"] = user.user_metadata;
callback(null, user, context);
}
exports.onExecutePostLogin = async (event, api) => {
api.idToken.setCustomClaim("https://spoke/user_metadata", event.user.user_metadata);
};
```
7. Update the Auth0 [Universal Landing page](https://manage.auth0.com/#/login_page), click on the `Customize Login Page` toggle, and copy and paste following code in the drop down into the `Default Templates` space:
11. Click `Deploy`.
12. Navigate to [Actions Flows](https://manage.auth0.com/#/actions/flows).
13. Click "Login".
14. Add "Spoke Action" to the Login flow.
15. Click "Apply".
16. Update the Auth0 [Universal Landing page](https://manage.auth0.com/#/login_page), click on the `Customize Login Page` toggle, and copy and paste following code in the drop down into the `Default Templates` space:

<details>
<summary>Code to paste into Auth0</summary>
Expand Down Expand Up @@ -125,4 +136,4 @@ callback(null, user, context);
```

</details>
8. Replace `YOUR_TOS_LINK_HERE` with the link to your Terms of Service and replace `YOUR_PRIVACY_POLICY_LINK_HERE` with the link to your Privacy Policy
17. Replace `YOUR_TOS_LINK_HERE` with the link to your Terms of Service and replace `YOUR_PRIVACY_POLICY_LINK_HERE` with the link to your Privacy Policy
18 changes: 18 additions & 0 deletions docs/RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# Release Notes

## v13.2.0
_December 2023_ Version 13.2.0

13.2.0 is a minor release.

### Bug Fixes
* Set contactTimezones for campaign when Redis is disabled

### Improvements
* Additional error catching
* Update bug report template
* Indicate progress in UI for bulk send
* Support for PostgreSQL 15
* Update Auth0 instructions

### Appreciations
* [Arique Aguilar](https://github.com/Arique1104), [Cody Gordon](https://github.com/codygordon), [Kathy Nguyen](https://github.com/crayolakat), and Harold Travis for QA.

## v13.1.0
_October 2023_ Version 13.1.0

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "spoke",
"version": "13.1.0",
"version": "13.2.0",
"description": "Spoke",
"main": "src/server",
"engines": {
Expand Down
162 changes: 115 additions & 47 deletions src/components/AssignmentTexter/BulkSendButton.jsx
Original file line number Diff line number Diff line change
@@ -1,73 +1,141 @@
import PropTypes from "prop-types";
import React, { Component } from "react";
import React, { useState, useEffect } from "react";
import { StyleSheet, css } from "aphrodite";
import Button from "@material-ui/core/Button";

import LinearProgress from "@material-ui/core/LinearProgress";
import Typography from '@material-ui/core/Typography';
import Snackbar from '@material-ui/core/Snackbar';
import Alert from '@material-ui/lab/Alert';

// This is because the Toolbar from material-ui seems to only apply the correct margins if the
// immediate child is a Button or other type it recognizes. Can get rid of this if we remove material-ui
const styles = StyleSheet.create({
container: {
display: "block",
width: "25ex",
marginLeft: "auto",
marginRight: "auto"
display: "flex",
flexFlow: "column",
alignItems: "center",
width: "30%",
maxWidth: 300,
height: "100%",
marginTop: 10,
marginRight: "auto",
marginLeft: "auto"
},
progressContainer: {
width: "100%"
},
progressText: {
position: "relative",
textAlign: "center",
color: "white"
},
progressBarRoot: {
height: 10,
borderRadius: 5
}
});

export default class BulkSendButton extends Component {
state = {
isSending: false
};
function BulkSendButton({
assignment, setDisabled, bulkSendMessages, refreshData, onFinishContact
}) {
const totalChunkSize = window.BULK_SEND_CHUNK_SIZE;
const [isSending, setIsSending] = useState(false);
const [totalSentMessages, setTotalSentMessages] = useState(0);
const [progress, setProgress] = useState(0);
const [errorMessage, setErrorMessage] = useState('');

sendMessages = async () => {
let sentMessages = 0;
const sendMessages = async () => {
try {
const { data } = await bulkSendMessages(assignment.id);
const sentMessages = data.bulkSendMessages.length;
const updatedTotalSent = totalSentMessages + sentMessages;

this.setState({ isSending: true });
this.props.setDisabled(true);
if (!sentMessages) {
/* end sending if no messages were left to send */
setProgress(100);
} else {
setTotalSentMessages(updatedTotalSent);
setProgress((updatedTotalSent / totalChunkSize) * 100);
}
} catch (err) {
console.error(err);
setErrorMessage(err.message);
}
}

console.log(`Start bulk sending messages ${new Date()}`);
while (sentMessages < window.BULK_SEND_CHUNK_SIZE) {
const res = await this.props.bulkSendMessages(this.props.assignment.id);
const handleEndSend = () => {
refreshData();
setErrorMessage('');
setIsSending(false);
setProgress(0);
setTotalSentMessages(0);
setDisabled(false);
onFinishContact();
}

// Check if all messages have been sent
if (!res.data.bulkSendMessages.length) {
break;
useEffect(() => {
if (isSending) {
/* sendMessages will be called the first time when isSending is set to true
and only called again when the progress state is updated and not complete */
if (progress < 100) {
sendMessages();
} else {
/* display "sent all" message for half a sec */
setTimeout(handleEndSend, 500);
}

// Print progress to console
sentMessages += res.data.bulkSendMessages.length;
console.log(`Bulk sent ${sentMessages} messages ${new Date()}`);
}
this.props.refreshData();
console.log(`Finish bulk sending messages ${new Date()}`);

this.setState({ isSending: false });
this.props.setDisabled(false);
this.props.onFinishContact();
};
}, [isSending, progress]);

render() {
return (
<div className={css(styles.container)}>
return (
<div className={css(styles.container)}>
{isSending ? (
<div className={css(styles.progressContainer)}>
<div className={css(styles.progressText)}>
<Typography variant="subtitle1">
{progress === 100
? 'Sent all messages!'
: `Sent ${totalSentMessages} of ${totalChunkSize} messages...`}
</Typography>
</div>
<LinearProgress
variant="determinate"
value={progress}
classes={{ root: css(styles.progressBarRoot) }}
/>
</div>
) : (
<Button
onClick={this.sendMessages}
disabled={this.state.isSending}
onClick={() => setIsSending(true)}
disabled={isSending}
color="primary"
variant="contained"
>
{this.state.isSending
? "Sending..."
: `Send Bulk (${window.BULK_SEND_CHUNK_SIZE})`}
{`Send Bulk (${totalChunkSize})`}
</Button>
</div>
);
}
)}
<Snackbar
anchorOrigin={{ vertical: 'top', horizontal: 'center' }}
open={!!errorMessage}
autoHideDuration={6000}
onClose={handleEndSend}
>
<Alert
onClose={handleEndSend}
severity="error"
>
{errorMessage}
</Alert>
</Snackbar>
</div>
);
}

BulkSendButton.propTypes = {
assignment: PropTypes.object,
onFinishContact: PropTypes.func,
bulkSendMessages: PropTypes.func,
refreshData: PropTypes.func,
setDisabled: PropTypes.func
assignment: PropTypes.shape({ id: PropTypes.number }).isRequired,
onFinishContact: PropTypes.func.isRequired,
bulkSendMessages: PropTypes.func.isRequired,
refreshData: PropTypes.func.isRequired,
setDisabled: PropTypes.func.isRequired
};

export default BulkSendButton;
4 changes: 3 additions & 1 deletion src/extensions/contact-loaders/s3-pull/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,9 @@ export async function loadContactS3PullProcessFile(jobEvent, contextVars) {
return { alreadyComplete: 1 };
}

await r.knex.batchInsert("campaign_contact", insertRows);
await r.knex.batchInsert("campaign_contact", insertRows).catch(e => {
console.error("Error with S3 pull batch insertion for campaign", campaign_id, e);
});
}

if (fileIndex < manifestData.entries.length - 1) {
Expand Down
4 changes: 3 additions & 1 deletion src/server/models/cacheable_queries/campaign.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,9 @@ const load = async (id, opts) => {
}
}

return await Campaign.get(id);
const campaign = await Campaign.get(id)
campaign.contactTimezones = await dbContactTimezones(id);
return campaign;
};

const campaignCache = {
Expand Down

0 comments on commit 49415b9

Please sign in to comment.