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

Commit e5ca1d8

Browse files
authored
Merge pull request #3765 from withspectrum/2.4.25
2.4.25
2 parents 5fadf98 + 7a5ff25 commit e5ca1d8

File tree

8 files changed

+110
-20
lines changed

8 files changed

+110
-20
lines changed

api/routes/create-subscription-server.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,17 @@ const createSubscriptionsServer = (server: any, path: string) => {
2525
},
2626
onDisconnect: rawSocket => {
2727
return getUserIdFromReq(rawSocket.upgradeReq)
28-
.then(id => {
29-
return setUserOnline(id, false);
30-
})
28+
.then(id => id && setUserOnline(id, false))
3129
.catch(err => {
3230
console.error(err);
3331
});
3432
},
3533
onConnect: (connectionParams, rawSocket) =>
3634
getUserIdFromReq(rawSocket.upgradeReq)
37-
.then(id => setUserOnline(id, true))
35+
.then(id => (id ? setUserOnline(id, true) : null))
3836
.then(user => {
3937
return {
40-
user,
38+
user: user || null,
4139
loaders: createLoaders({ cache: false }),
4240
};
4341
})

api/utils/session-store.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@ const ONE_DAY = 86400000;
77
/**
88
* Get the sessions' users' ID of a req manually, needed for websocket authentication
99
*/
10-
export const getUserIdFromReq = (req: any): Promise<string> =>
10+
export const getUserIdFromReq = (req: any): Promise<?string> =>
1111
new Promise((res, rej) => {
1212
session(req, {}, err => {
13-
if (err) return rej(err);
14-
if (!req.session || !req.session.passport || !req.session.passport.user)
15-
return rej();
13+
if (err) {
14+
return rej(err);
15+
}
16+
if (!req.session || !req.session.passport || !req.session.passport.user) {
17+
return res(null);
18+
}
1619

1720
return res(req.session.passport.user);
1821
});

now.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
{
22
"scale": {
3-
"bru1": {
4-
"min": 0,
5-
"max": 0
6-
},
73
"sfo1": {
84
"min": 1,
95
"max": "auto"

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "Spectrum",
3-
"version": "2.4.24",
3+
"version": "2.4.25",
44
"license": "BSD-3-Clause",
55
"devDependencies": {
66
"babel-cli": "^6.24.1",

shared/middlewares/cors.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export default cors({
99
/\.spectrum\.chat$/,
1010
process.env.NOW_URL,
1111
'https://zeit.co',
12+
/(\.|https:\/\/)zeit\.sh$/,
1213
].filter(Boolean)
1314
: [/localhost/],
1415
credentials: true,
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// @flow
2+
// Generates a meta image which shows a title and a footer text on a nice Spectrum background.
3+
import theme from 'shared/theme';
4+
import { btoa } from 'abab';
5+
import { stringify } from 'query-string';
6+
7+
// NOTES(@mxstbr):
8+
// Imgix has a useful ~text endpoint that allows us to add text to any image, but unfortunately that endpoint only allows us to add one piece of text to an image—but we need two!
9+
// We work around this by generating two images that only contain the text of the title and the footer respectively, nothing else, and then using the blend option to blend the background image with the title image (which only has the title text) and used the mark option to add our footer text as a "watermark" to the footer.
10+
11+
const WIDTH = 1500;
12+
const IMGIX_TEXT_ENDPOINT = 'https://assets.imgix.net/~text';
13+
14+
const TITLE_PARAMS = {
15+
w: WIDTH * 0.8, // 10% padding on each side
16+
h: 270, // Magic number, clips text after three lines
17+
txtsize: 56,
18+
txtlead: 16,
19+
txtfont: 'Helvetica,Bold',
20+
txtalign: 'left,middle',
21+
txtcolor: 'ffffff',
22+
// NOTE(@mxstbr): txtclip (i.e. ellipsis on overflowing text) only works with single-line text, which titles aren't, so this doesn't do anything rn
23+
txtclip: 'end,ellipsis',
24+
};
25+
26+
const FOOTER_PARAMS = {
27+
h: 64,
28+
txtsize: 36,
29+
txtcolor: theme.brand.default.replace('#', ''),
30+
txtalign: 'right,middle',
31+
txtfont: 'Helvetica,Bold',
32+
};
33+
34+
const BACKGROUND_URL = `https://spectrum.imgix.net/default_images/twitter-share-card.png`;
35+
36+
type GetMetaImageInput = {
37+
title: string,
38+
footer: string,
39+
};
40+
41+
const generateImageFromText = ({ title, footer }: GetMetaImageInput) => {
42+
const base64title = btoa(title);
43+
const base64footer = btoa(footer);
44+
if (!base64title || !base64footer) return;
45+
46+
const titleUrl = `${IMGIX_TEXT_ENDPOINT}?${stringify(
47+
{ ...TITLE_PARAMS, txt64: base64title.replace('=', '') },
48+
{ encode: false }
49+
)}`;
50+
const footerUrl = `${IMGIX_TEXT_ENDPOINT}?${stringify(
51+
{ ...FOOTER_PARAMS, txt64: base64footer.replace(/=/g, '') },
52+
{ encode: false }
53+
)}`;
54+
55+
const base64titleurl = btoa(titleUrl);
56+
const base64footerurl = btoa(footerUrl);
57+
58+
if (!base64titleurl || !base64footerurl) return;
59+
60+
const BACKGROUND_PARAMS = {
61+
w: WIDTH,
62+
bm: 'normal', // Blend the title normally, don't change opacity or color or anything, just overlay it
63+
by: 170, // Magic numbers that get the position right
64+
bx: 180,
65+
markalign: 'left,bottom', // Show the footer on the left side
66+
markpad: 24, // We overwrite the X pos, so the padding only applies on the y-axis
67+
markx: 100,
68+
blend64: btoa(titleUrl).replace(/=/g, ''),
69+
mark64: btoa(footerUrl).replace(/=/g, ''),
70+
};
71+
72+
return `${BACKGROUND_URL}?${stringify(BACKGROUND_PARAMS, { encode: false })}`;
73+
};
74+
75+
export default generateImageFromText;

src/views/notifications/utils.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ const threadToString = (context, currentUser) => {
154154
<Link
155155
to={{
156156
pathname: window.location.pathname,
157-
search: `?thread=${context.payload.id}`,
157+
search: `?thread=${context.payload.threadId}`,
158158
}}
159159
>
160160
{context.payload.content.title}

src/views/thread/container.js

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import {
3939
} from './style';
4040
import WatercoolerActionBar from './components/watercoolerActionBar';
4141
import { ErrorBoundary } from 'src/components/error';
42+
import generateImageFromText from 'src/helpers/generate-image-from-text';
4243

4344
type Props = {
4445
data: {
@@ -226,7 +227,11 @@ class ThreadContainer extends React.Component<Props, State> {
226227
// we never autofocus on mobile
227228
if (window && window.innerWidth < 768) return;
228229

229-
const { currentUser, data: { thread }, threadSliderIsOpen } = this.props;
230+
const {
231+
currentUser,
232+
data: { thread },
233+
threadSliderIsOpen,
234+
} = this.props;
230235

231236
// if no thread has been returned yet from the query, we don't know whether or not to focus yet
232237
if (!thread) return;
@@ -270,7 +275,10 @@ class ThreadContainer extends React.Component<Props, State> {
270275

271276
renderChatInputOrUpsell = () => {
272277
const { isEditing } = this.state;
273-
const { data: { thread }, currentUser } = this.props;
278+
const {
279+
data: { thread },
280+
currentUser,
281+
} = this.props;
274282

275283
if (!thread) return null;
276284
if (thread.isLocked) return null;
@@ -319,7 +327,11 @@ class ThreadContainer extends React.Component<Props, State> {
319327
};
320328

321329
renderPost = () => {
322-
const { data: { thread }, slider, currentUser } = this.props;
330+
const {
331+
data: { thread },
332+
slider,
333+
currentUser,
334+
} = this.props;
323335
if (!thread || !thread.id) return null;
324336

325337
if (thread.watercooler) {
@@ -445,8 +457,13 @@ class ThreadContainer extends React.Component<Props, State> {
445457
<Head
446458
title={headTitle}
447459
description={headDescription}
448-
image={thread.community.profilePhoto}
449-
/>
460+
image={generateImageFromText({
461+
title: headTitle,
462+
footer: `spectrum.chat/${thread.community.slug}`,
463+
})}
464+
>
465+
<meta name="twitter:card" content="summary_large_image" />
466+
</Head>
450467
<Titlebar
451468
title={thread.content.title}
452469
subtitle={`${thread.community.name} / ${thread.channel.name}`}

0 commit comments

Comments
 (0)