Skip to content
This repository has been archived by the owner on Oct 11, 2022. It is now read-only.

Commit

Permalink
Merge pull request #4703 from withspectrum/2.7.3
Browse files Browse the repository at this point in the history
2.7.3
  • Loading branch information
brianlovin authored Feb 20, 2019
2 parents df7281f + c8233dc commit 59902e2
Show file tree
Hide file tree
Showing 16 changed files with 80 additions and 35 deletions.
1 change: 1 addition & 0 deletions api/routes/api/email.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ emailRouter.get('/unsubscribe', (req, res) => {
case 'newThreadCreated':
case 'newMessageInThreads':
case 'newDirectMessage':
case 'newMention':
return unsubscribeUserFromEmailNotification(userId, type).then(() =>
res
.status(200)
Expand Down
7 changes: 5 additions & 2 deletions athena/queues/mention-notification.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ export default async ({ data }: Job<MentionNotificationJobData>) => {
// in a private channel where the user is not a member. Users can still be
// mentioned in public channels where they are not a member
const thread = await getThreadById(threadId);

// if for some reason no thread was found, or the thread was deleted
// dont send any notification about the mention
if (!thread || thread.deletedAt) return;
debug('got thread');

const { isPrivate: channelIsPrivate } = await getChannelById(
thread.channelId
Expand All @@ -74,6 +74,7 @@ export default async ({ data }: Job<MentionNotificationJobData>) => {
) {
return;
}
debug('user is member in community');

// see if a usersThreads record exists. If it does, and notifications are muted, we
// should not send an email. If the record doesn't exist, it means the person being
Expand Down Expand Up @@ -120,8 +121,10 @@ export default async ({ data }: Job<MentionNotificationJobData>) => {
]);

// if the user shouldn't get an email, just add an in-app notif
if (!shouldEmail)
if (!shouldEmail) {
debug('recipient doesnt have an email');
return storeUsersNotifications(storedNotification.id, recipient.id);
}

// if the mention was in a message, get the data about the message
const messagePromise = messageId ? await getMessageById(messageId) : null;
Expand Down
25 changes: 13 additions & 12 deletions athena/queues/private-community-request-approved.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Raven from 'shared/raven';
import { getCommunityById } from '../models/community';
import { storeNotification } from '../models/notification';
import { storeUsersNotifications } from 'shared/db/queries/usersNotifications';
import { getUsers } from 'shared/db/queries/user';
import { getUserById } from 'shared/db/queries/user';
import { fetchPayload } from '../utils/payloads';
import isEmail from 'validator/lib/isEmail';
import { sendPrivateCommunityRequestApprovedEmailQueue } from 'shared/bull/queues';
Expand Down Expand Up @@ -41,25 +41,26 @@ export default async (job: Job<PrivateCommunityRequestApprovedJobData>) => {
const updatedNotification = await storeNotification(nextNotificationRecord);

const community = await getCommunityById(communityId);
const recipients = await getUsers([userId]);
const filteredRecipients = recipients.filter(
user => user && isEmail(user.email)
);
const usersNotificationPromises = filteredRecipients.map(recipient =>
storeUsersNotifications(updatedNotification.id, recipient.id)
const recipient = await getUserById(userId);

const canSendEmail = recipient && recipient.email && isEmail(recipient.email);

const notificationPromise = storeUsersNotifications(
updatedNotification.id,
recipient.id
);

const usersEmailPromises = filteredRecipients.map(recipient =>
const emailPromise =
canSendEmail &&
sendPrivateCommunityRequestApprovedEmailQueue.add({
// $FlowIssue
recipient,
community,
})
);
});

return await Promise.all([
...usersEmailPromises, // handle emails separately
...usersNotificationPromises, // update or store usersNotifications in-app
emailPromise, // handle emails separately
notificationPromise, // update or store usersNotifications in-app
]).catch(err => {
console.error('❌ Error in job:\n');
console.error(err);
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": "Spectrum",
"version": "2.6.4",
"version": "2.7.3",
"license": "BSD-3-Clause",
"devDependencies": {
"@babel/preset-flow": "^7.0.0",
Expand Down
9 changes: 6 additions & 3 deletions scripts/deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,12 @@ if (servers.indexOf('hyperion') > -1) {
stdio: 'inherit',
});
console.log('Aliasing to hyperion.workers.spectrum.chat');
exec(now('alias hyperion.workers.spectrum.chat'), {
stdio: 'inherit',
});
exec(
now(`alias hyperion.${flags.prod ? 'workers' : 'alpha'}.spectrum.chat`),
{
stdio: 'inherit',
}
);
console.log('Clearing cache');
exec(
now(
Expand Down
6 changes: 3 additions & 3 deletions shared/db/db.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ poolMaster.on('queueing', size => {
statsd.gauge('db.query_queue.size', size);
});

poolMaster.on('size', size => {
statsd.gauge('db.connections.count', size);
});
setInterval(() => {
statsd.gauge('db.connections.count', poolMaster.getLength());
}, 5000);

// Exit the process on unhealthy db in test env
if (process.env.TEST_DB) {
Expand Down
16 changes: 14 additions & 2 deletions shared/imgix/signCommunity.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,19 @@ export const signCommunity = (community: DBCommunity, expires?: number): DBCommu

return {
...rest,
profilePhoto: signImageUrl(profilePhoto, { w: 256, h: 256, expires }),
coverPhoto: signImageUrl(coverPhoto, { w: 1280, h: 384, expires }),
profilePhoto: signImageUrl(profilePhoto, {
w: 256,
h: 256,
dpr: 2,
auto: 'compress',
expires
}),
coverPhoto: signImageUrl(coverPhoto, {
w: 1280,
h: 384,
dpr: 2,
q: 100,
expires
}),
};
};
15 changes: 14 additions & 1 deletion shared/imgix/signThread.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @flow
import type { DBThread } from 'shared/types';
import { signImageUrl } from 'shared/imgix';
const url = require('url');

const signBody = (body?: string, expires?: number): string => {
if (!body) {
Expand Down Expand Up @@ -32,7 +33,19 @@ const signBody = (body?: string, expires?: number): string => {
const { src } = returnBody.entityMap[key].data;

// transform the body inline with signed image urls
returnBody.entityMap[key].data.src = signImageUrl(src, { expires });
const imageUrlStoredAsSigned =
src.indexOf('https://spectrum.imgix.net') >= 0;
// if the image was stored in the db as a signed url (eg. after the plaintext update to the thread editor)
// we need to remove all query params from the src, then re-sign in order to avoid duplicate signatures
// or sending down a url with an expired signature
if (imageUrlStoredAsSigned) {
const pathname = url.parse(src).pathname;
// always attempt to use the parsed pathname, but fall back to the original src
const sanitized = decodeURIComponent(pathname || src);
returnBody.entityMap[key].data.src = signImageUrl(sanitized, { expires });
} else {
returnBody.entityMap[key].data.src = signImageUrl(src, { expires });
}
});

return JSON.stringify(returnBody);
Expand Down
4 changes: 4 additions & 0 deletions shared/imgix/signUser.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@ export const signUser = (user: DBUser, expires?: number): DBUser => {
profilePhoto: signImageUrl(profilePhoto, {
w: 256,
h: 256,
dpr: 2,
auto: 'compress',
expires,
}),
coverPhoto: signImageUrl(coverPhoto, {
w: 1280,
h: 384,
dpr: 2,
q: 100,
expires,
}),
};
Expand Down
3 changes: 1 addition & 2 deletions src/components/loading/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,7 @@ export const GridProfile = styled.div`
grid-template-areas: 'cover cover' 'meta content';
grid-column-gap: 32px;
width: 100%;
min-width: 100%;
max-width: 100%;
max-width: 1280px;
height: 100%;
min-height: 100vh;
background-color: ${theme.bg.default};
Expand Down
9 changes: 7 additions & 2 deletions src/components/outsideClickHandler/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,19 @@ type Props = {
class OutsideAlerter extends React.Component<Props> {
wrapperRef: React.Node;

// iOS bug, see: https://stackoverflow.com/questions/10165141/jquery-on-and-delegate-doesnt-work-on-ipad
componentDidMount() {
// $FlowFixMe
document.addEventListener('mousedown', this.handleClickOutside);
document
.getElementById('root')
.addEventListener('mousedown', this.handleClickOutside);
}

componentWillUnmount() {
// $FlowFixMe
document.removeEventListener('mousedown', this.handleClickOutside);
document
.getElementById('root')
.removeEventListener('mousedown', this.handleClickOutside);
}

setWrapperRef = (node: React.Node) => {
Expand Down
2 changes: 1 addition & 1 deletion src/components/upsell/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export const UpsellCreateCommunity = () => {
<Subtitle>{subtitle}</Subtitle>
<Actions>
<Link to="/new/community">
<Button onClick={close}>Get Started</Button>
<Button>Get Started</Button>
</Link>
</Actions>
</NullCard>
Expand Down
1 change: 1 addition & 0 deletions src/reset.css.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ injectGlobal`
padding: 0;
margin: 0;
-webkit-font-smoothing: antialiased;
-webkit-tap-highlight-color: rgba(0,0,0,0);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial,
sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
}
Expand Down
5 changes: 3 additions & 2 deletions src/views/channel/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ export const Grid = styled.main`
grid-template-areas: 'cover cover cover' 'meta content extras';
grid-column-gap: 32px;
width: 100%;
min-width: 100%;
max-width: 100%;
max-width: 1280px;
min-height: 100vh;
background-color: ${theme.bg.default};
box-shadow: inset 1px 0 0 ${theme.bg.border},
inset -1px 0 0 ${theme.bg.border};
@media (max-width: 1280px) {
grid-template-columns: 240px 1fr;
Expand Down
5 changes: 3 additions & 2 deletions src/views/community/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,11 @@ export const Grid = styled.main`
grid-template-areas: 'cover cover cover' 'meta content extras';
grid-column-gap: 32px;
width: 100%;
min-width: 100%;
max-width: 100%;
max-width: 1280px;
min-height: 100vh;
background-color: ${theme.bg.default};
box-shadow: inset 1px 0 0 ${theme.bg.border},
inset -1px 0 0 ${theme.bg.border};
@media (max-width: 1280px) {
grid-template-columns: 320px 1fr;
Expand Down
5 changes: 3 additions & 2 deletions src/views/user/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,11 @@ export const Grid = styled.main`
grid-template-areas: 'cover cover cover' 'meta content extras';
grid-column-gap: 32px;
width: 100%;
min-width: 100%;
max-width: 100%;
max-width: 1280px;
min-height: 100vh;
background-color: ${theme.bg.default};
box-shadow: inset 1px 0 0 ${theme.bg.border},
inset -1px 0 0 ${theme.bg.border};
@media (max-width: 1028px) {
grid-template-columns: 320px 1fr;
Expand Down

0 comments on commit 59902e2

Please sign in to comment.