Add progress to class creation, fix interest emails
If there's 20 people interested in a course, class creation could take quite a while so show progress. Only send emails to active members. Change "Interest +" wording to "interested" in emails.
This commit is contained in:
parent
2d76aaf87d
commit
4f121d0541
|
@ -12,7 +12,7 @@
|
||||||
<div>You can find the class on its course page here:<br></div>
|
<div>You can find the class on its course page here:<br></div>
|
||||||
<div><a href="[link]">[link]</a><br></div>
|
<div><a href="[link]">[link]</a><br></div>
|
||||||
<div><br></div>
|
<div><br></div>
|
||||||
<div>Your "interest" in this course is now removed and you won't receive any more notifications about its classes until you press the "Interest +" button again.<br></div>
|
<div>Your "interest" in this course is now removed and you won't receive any more notifications about its classes until you press the "interested" button again.<br></div>
|
||||||
<div><br></div>
|
<div><br></div>
|
||||||
<div>Spaceport<br></div>
|
<div>Spaceport<br></div>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -6,6 +6,6 @@ You can find the class on its course page here:
|
||||||
[link]
|
[link]
|
||||||
|
|
||||||
Your "interest" in this course is now removed and you won't receive any more
|
Your "interest" in this course is now removed and you won't receive any more
|
||||||
notifications about its classes until you press the "Interest +" button again.
|
notifications about its classes until you press the "interested" button again.
|
||||||
|
|
||||||
Spaceport
|
Spaceport
|
||||||
|
|
|
@ -3,6 +3,7 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import smtplib
|
import smtplib
|
||||||
|
import time
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from django.core.mail import send_mail, EmailMultiAlternatives
|
from django.core.mail import send_mail, EmailMultiAlternatives
|
||||||
|
@ -92,4 +93,7 @@ def send_interest_email(interest):
|
||||||
html_message=email_html,
|
html_message=email_html,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if not settings.EMAIL_HOST:
|
||||||
|
time.sleep(0.5) # simulate slowly sending emails when logging to console
|
||||||
|
|
||||||
logger.info('Sent interest email:\n' + email_text)
|
logger.info('Sent interest email:\n' + email_text)
|
||||||
|
|
|
@ -195,8 +195,13 @@ def calc_card_scans():
|
||||||
def get_progress(request_id):
|
def get_progress(request_id):
|
||||||
return cache.get('request-progress-' + request_id, [])
|
return cache.get('request-progress-' + request_id, [])
|
||||||
|
|
||||||
def set_progress(request_id, data):
|
def set_progress(request_id, data, replace=False):
|
||||||
logger.info('Progress - ID: %s | Status: %s', request_id, data)
|
logger.info('Progress - ID: %s | Status: %s', request_id, data)
|
||||||
progress = get_progress(request_id)
|
progress = get_progress(request_id)
|
||||||
progress.append(data)
|
|
||||||
|
if replace and len(progress):
|
||||||
|
progress[-1] = data
|
||||||
|
else:
|
||||||
|
progress.append(data)
|
||||||
|
|
||||||
cache.set('request-progress-' + request_id, progress)
|
cache.set('request-progress-' + request_id, progress)
|
||||||
|
|
|
@ -279,6 +279,7 @@ class SessionViewSet(Base, List, Retrieve, Create, Update):
|
||||||
return serializers.SessionSerializer
|
return serializers.SessionSerializer
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
def perform_create(self, serializer):
|
||||||
|
data = self.request.data
|
||||||
session = serializer.save(instructor=self.request.user)
|
session = serializer.save(instructor=self.request.user)
|
||||||
|
|
||||||
# ensure session datetime is at least 1 day in the future
|
# ensure session datetime is at least 1 day in the future
|
||||||
|
@ -287,15 +288,22 @@ class SessionViewSet(Base, List, Retrieve, Create, Update):
|
||||||
logging.info('Session is in the past or too soon, not sending interest emails.')
|
logging.info('Session is in the past or too soon, not sending interest emails.')
|
||||||
return
|
return
|
||||||
|
|
||||||
interests = models.Interest.objects.filter(course=session.course, satisfied_by__isnull=True)
|
interests = models.Interest.objects.filter(
|
||||||
|
course=session.course,
|
||||||
|
satisfied_by__isnull=True,
|
||||||
|
user__member__paused_date__isnull=True
|
||||||
|
)
|
||||||
|
|
||||||
|
for num, interest in enumerate(interests):
|
||||||
|
msg = 'Sending email {} / {}...'.format(num+1, len(interests))
|
||||||
|
if data['request_id']: utils_stats.set_progress(data['request_id'], msg, replace=True)
|
||||||
|
|
||||||
for interest in interests:
|
|
||||||
try:
|
try:
|
||||||
utils_email.send_interest_email(interest)
|
utils_email.send_interest_email(interest)
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
msg = 'Problem sending interest email: ' + str(e)
|
msg = 'Problem sending interest email: ' + str(e)
|
||||||
logger.exception(msg)
|
logger.exception(msg)
|
||||||
alert_tanner(msg)
|
utils.alert_tanner(msg)
|
||||||
|
|
||||||
num_satisfied = interests.update(satisfied_by=session)
|
num_satisfied = interests.update(satisfied_by=session)
|
||||||
logging.info('Satisfied %s interests.', num_satisfied)
|
logging.info('Satisfied %s interests.', num_satisfied)
|
||||||
|
|
|
@ -6,7 +6,7 @@ import 'react-datetime/css/react-datetime.css';
|
||||||
import moment from 'moment-timezone';
|
import moment from 'moment-timezone';
|
||||||
import './light.css';
|
import './light.css';
|
||||||
import { Button, Checkbox, Form, Grid, Header, Icon, Label, Message, Table } from 'semantic-ui-react';
|
import { Button, Checkbox, Form, Grid, Header, Icon, Label, Message, Table } from 'semantic-ui-react';
|
||||||
import { requester } from './utils.js';
|
import { requester, randomString } from './utils.js';
|
||||||
import { MembersDropdown } from './Members.js';
|
import { MembersDropdown } from './Members.js';
|
||||||
|
|
||||||
class AttendanceSheet extends React.Component {
|
class AttendanceSheet extends React.Component {
|
||||||
|
@ -378,6 +378,7 @@ export function InstructorClassList(props) {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [input, setInput] = useState({ max_students: null });
|
const [input, setInput] = useState({ max_students: null });
|
||||||
const [error, setError] = useState(false);
|
const [error, setError] = useState(false);
|
||||||
|
const [progress, setProgress] = useState([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [success, setSuccess] = useState(false);
|
const [success, setSuccess] = useState(false);
|
||||||
const [classes, setClasses] = useState([]);
|
const [classes, setClasses] = useState([]);
|
||||||
|
@ -387,9 +388,23 @@ export function InstructorClassList(props) {
|
||||||
if (loading) return;
|
if (loading) return;
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setSuccess(false);
|
setSuccess(false);
|
||||||
const data = { ...input, course: course.id };
|
|
||||||
|
const request_id = randomString();
|
||||||
|
const getStatus = () => {
|
||||||
|
requester('/stats/progress/?request_id='+request_id, 'GET')
|
||||||
|
.then(res => {
|
||||||
|
setProgress(res);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const interval = setInterval(getStatus, 500);
|
||||||
|
|
||||||
|
const data = { ...input, course: course.id, request_id: request_id };
|
||||||
requester('/sessions/', 'POST', token, data)
|
requester('/sessions/', 'POST', token, data)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
|
clearInterval(interval);
|
||||||
setSuccess(res.id);
|
setSuccess(res.id);
|
||||||
setInput({ max_students: null });
|
setInput({ max_students: null });
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
@ -398,6 +413,7 @@ export function InstructorClassList(props) {
|
||||||
setCourse({ ...course, sessions: [ res, ...course.sessions ] });
|
setCourse({ ...course, sessions: [ res, ...course.sessions ] });
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
|
clearInterval(interval);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
console.log(err);
|
console.log(err);
|
||||||
setError(err.data);
|
setError(err.data);
|
||||||
|
@ -445,6 +461,10 @@ export function InstructorClassList(props) {
|
||||||
|
|
||||||
<InstructorClassEditor input={input} setInput={setInput} error={error} token={token} />
|
<InstructorClassEditor input={input} setInput={setInput} error={error} token={token} />
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{progress.map(x => <>{x}<br /></>)}
|
||||||
|
</p>
|
||||||
|
|
||||||
<Form.Button loading={loading} error={error.non_field_errors}>
|
<Form.Button loading={loading} error={error.non_field_errors}>
|
||||||
Submit
|
Submit
|
||||||
</Form.Button>
|
</Form.Button>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user