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

Commit 3673cd1

Browse files
authored
Merge pull request #3819 from withspectrum/2.4.28
2.4.28
2 parents 772760a + 6592594 commit 3673cd1

File tree

37 files changed

+705
-501
lines changed

37 files changed

+705
-501
lines changed

api/models/thread.js

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,27 @@ export const getThreadsByChannel = (channelId: string, options: PaginationOption
7171
};
7272

7373
// prettier-ignore
74-
export const getThreadsByChannels = (channelIds: Array<string>, options: PaginationOptions): Promise<Array<DBThread>> => {
75-
const { first, after } = options
76-
74+
type GetThreadsByChannelPaginationOptions = {
75+
first: number,
76+
after: number,
77+
sort: 'latest' | 'trending'
78+
};
79+
80+
export const getThreadsByChannels = (
81+
channelIds: Array<string>,
82+
options: GetThreadsByChannelPaginationOptions
83+
): Promise<Array<DBThread>> => {
84+
const { first, after, sort = 'latest' } = options;
85+
86+
let order = [db.desc('lastActive'), db.desc('createdAt')];
87+
// If we want the top threads, first sort by the score and then lastActive
88+
if (sort === 'trending') order.unshift(db.desc('score'));
89+
7790
return db
7891
.table('threads')
7992
.getAll(...channelIds, { index: 'channelId' })
8093
.filter(thread => db.not(thread.hasFields('deletedAt')))
81-
.orderBy(db.desc('lastActive'), db.desc('createdAt'))
94+
.orderBy(...order)
8295
.skip(after || 0)
8396
.limit(first || 999999)
8497
.run();
@@ -447,10 +460,10 @@ export const setThreadLock = (threadId: string, value: boolean, userId: string,
447460
.run()
448461
.then(async () => {
449462
const thread = await getThreadById(threadId)
450-
451-
const event = value
452-
? byModerator
453-
? events.THREAD_LOCKED_BY_MODERATOR
463+
464+
const event = value
465+
? byModerator
466+
? events.THREAD_LOCKED_BY_MODERATOR
454467
: events.THREAD_LOCKED
455468
: byModerator
456469
? events.THREAD_UNLOCKED_BY_MODERATOR

api/models/usersChannels.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ const createMemberInDefaultChannels = (communityId: string, userId: string): Pro
465465
};
466466

467467
// prettier-ignore
468-
const toggleUserChannelNotifications = (userId: string, channelId: string, value: boolean): Promise<DBChannel> => {
468+
const toggleUserChannelNotifications = async (userId: string, channelId: string, value: boolean): Promise<DBChannel> => {
469469
const event = value ? events.CHANNEL_NOTIFICATIONS_ENABLED : events.CHANNEL_NOTIFICATIONS_DISABLED
470470

471471
trackQueue.add({
@@ -474,12 +474,25 @@ const toggleUserChannelNotifications = (userId: string, channelId: string, value
474474
context: { channelId }
475475
})
476476

477-
return db
477+
const permissions = await db
478478
.table('usersChannels')
479479
.getAll(channelId, { index: 'channelId' })
480480
.filter({ userId })
481-
.update({ receiveNotifications: value })
482481
.run();
482+
483+
// permissions exist, this user is trying to toggle notifications for a channel where they
484+
// are already a member
485+
if (permissions && permissions.length > 0) {
486+
return db
487+
.table('usersChannels')
488+
.getAll(channelId, { index: 'channelId' })
489+
.filter({ userId })
490+
.update({ receiveNotifications: value })
491+
.run();
492+
}
493+
494+
// if permissions don't exist, create a usersChannel relationship with notifications on
495+
return createMemberInChannel(channelId, userId, false)
483496
};
484497

485498
const removeUsersChannelMemberships = async (userId: string) => {

api/mutations/channel/toggleChannelNotifications.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ export default requireAuth(async (_: any, args: Input, ctx: GraphQLContext) => {
1919
loaders.userPermissionsInChannel.load([user.id, channelId]),
2020
]);
2121

22-
if (!permissions || permissions.isBlocked || !permissions.isMember) {
22+
// only reject if the user is blocked in the channel
23+
if (permissions && permissions.isBlocked) {
2324
let event = !permissions
2425
? events.CHANNEL_NOTIFICATIONS_ENABLED_FAILED
2526
: permissions.receiveNotifications
@@ -37,7 +38,8 @@ export default requireAuth(async (_: any, args: Input, ctx: GraphQLContext) => {
3738
return new UserError("You don't have permission to do that.");
3839
}
3940

40-
const value = !permissions.receiveNotifications;
41+
// if the user hasn't joined the channel, they are trying to join it now
42+
const value = permissions ? !permissions.receiveNotifications : true;
4143

4244
return toggleUserChannelNotifications(user.id, channelId, value).then(
4345
() => channel

api/mutations/message/addMessage.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { trackUserThreadLastSeenQueue } from 'shared/bull/queues';
1313
import type { FileUpload } from 'shared/types';
1414
import { events } from 'shared/analytics';
1515
import { isAuthedResolver as requireAuth } from '../../utils/permissions';
16-
import { trackQueue } from 'shared/bull/queues';
16+
import { trackQueue, calculateThreadScoreQueue } from 'shared/bull/queues';
1717

1818
type Input = {
1919
message: {
@@ -344,6 +344,14 @@ export default requireAuth(async (_: any, args: Input, ctx: GraphQLContext) => {
344344
timestamp: Date.now(),
345345
});
346346

347+
calculateThreadScoreQueue.add(
348+
{
349+
threadId: message.threadId,
350+
},
351+
{
352+
jobId: message.threadId,
353+
}
354+
);
347355
return {
348356
...dbMessage,
349357
contextPermissions,

api/mutations/message/deleteMessage.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { getUserPermissionsInChannel } from '../../models/usersChannels';
1313
import { getUserPermissionsInCommunity } from '../../models/usersCommunities';
1414
import { events } from 'shared/analytics';
1515
import { isAuthedResolver as requireAuth } from '../../utils/permissions';
16-
import { trackQueue } from 'shared/bull/queues';
16+
import { trackQueue, calculateThreadScoreQueue } from 'shared/bull/queues';
1717

1818
type Input = {
1919
id: string,
@@ -116,5 +116,15 @@ export default requireAuth(async (_: any, args: Input, ctx: GraphQLContext) => {
116116
message.senderId
117117
);
118118
})
119+
.then(() => {
120+
return calculateThreadScoreQueue.add(
121+
{
122+
threadId: message.threadId,
123+
},
124+
{
125+
jobId: message.threadId,
126+
}
127+
);
128+
})
119129
.then(() => true);
120130
});

api/mutations/thread/addThreadReaction.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { GraphQLContext } from '../../';
33
import { addThreadReaction } from '../../models/threadReaction';
44
import { getThreadById } from '../../models/thread';
55
import { isAuthedResolver as requireAuth } from '../../utils/permissions';
6+
import { calculateThreadScoreQueue } from 'shared/bull/queues';
67

78
type Input = {
89
input: {
@@ -13,8 +14,16 @@ type Input = {
1314

1415
export default requireAuth(
1516
async (_: any, args: Input, { user, loaders }: GraphQLContext) => {
16-
return await addThreadReaction(args.input, user.id).then(
17-
async () => await getThreadById(args.input.threadId)
18-
);
17+
return await addThreadReaction(args.input, user.id).then(() => {
18+
calculateThreadScoreQueue.add(
19+
{
20+
threadId: args.input.threadId,
21+
},
22+
{
23+
jobId: args.input.threadId,
24+
}
25+
);
26+
return getThreadById(args.input.threadId);
27+
});
1928
}
2029
);

api/mutations/thread/removeThreadReaction.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { GraphQLContext } from '../../';
33
import { removeThreadReaction } from '../../models/threadReaction';
44
import { getThreadById } from '../../models/thread';
55
import { isAuthedResolver as requireAuth } from '../../utils/permissions';
6+
import { calculateThreadScoreQueue } from 'shared/bull/queues';
67

78
type Input = {
89
input: {
@@ -12,8 +13,16 @@ type Input = {
1213

1314
export default requireAuth(
1415
async (_: any, args: Input, { user, loaders }: GraphQLContext) => {
15-
return await removeThreadReaction(args.input.threadId, user.id).then(
16-
async () => await getThreadById(args.input.threadId)
17-
);
16+
return await removeThreadReaction(args.input.threadId, user.id).then(() => {
17+
calculateThreadScoreQueue.add(
18+
{
19+
threadId: args.input.threadId,
20+
},
21+
{
22+
jobId: args.input.threadId,
23+
}
24+
);
25+
return getThreadById(args.input.threadId);
26+
});
1827
}
1928
);

api/queries/community/threadConnection.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,15 @@ import {
1010
import { getThreadsByChannels } from '../../models/thread';
1111
import { canViewCommunity } from '../../utils/permissions';
1212

13+
export type CommunityThreadConnectionPaginationOptions = {
14+
after: string,
15+
first: number,
16+
sort: 'latest' | 'trending',
17+
};
18+
1319
// prettier-ignore
14-
export default async (root: DBCommunity, args: PaginationOptions, ctx: GraphQLContext) => {
15-
const { first = 10, after } = args
20+
export default async (root: DBCommunity, args: CommunityThreadConnectionPaginationOptions, ctx: GraphQLContext) => {
21+
const { first = 10, after, sort = 'latest' } = args
1622
const { user, loaders } = ctx
1723
const { id } = root
1824

@@ -29,7 +35,7 @@ export default async (root: DBCommunity, args: PaginationOptions, ctx: GraphQLCo
2935
// Get the index from the encoded cursor, asdf234gsdf-2 => ["-2", "2"]
3036
const lastDigits = cursor.match(/-(\d+)$/);
3137
const lastThreadIndex =
32-
lastDigits && lastDigits.length > 0 && parseInt(lastDigits[1], 10);
38+
lastDigits && lastDigits.length > 0 && parseInt(lastDigits[1], 10) || 0;
3339
const currentUser = user;
3440

3541
// if the user is signed in, only return stories for the channels
@@ -44,10 +50,10 @@ export default async (root: DBCommunity, args: PaginationOptions, ctx: GraphQLCo
4450
channels = await getPublicChannelsByCommunity(id);
4551
}
4652

47-
// $FlowFixMe
4853
const threads = await getThreadsByChannels(channels, {
4954
first,
5055
after: lastThreadIndex,
56+
sort,
5157
});
5258

5359
return {

api/queries/thread/rootThread.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// @flow
2+
import { calculateThreadScoreQueue } from 'shared/bull/queues';
23
import type { GraphQLContext } from '../../';
34

45
export default async (
@@ -50,6 +51,23 @@ export default async (
5051
(!communityPermissions || !communityPermissions.isMember)
5152
)
5253
return null;
54+
55+
// If the threads score hasn't been updated in the past
56+
// 24 hours add a new job to the queue to update it
57+
if (
58+
(!thread.score && !thread.scoreUpdatedAt) ||
59+
(thread.scoreUpdatedAt &&
60+
Date.now() > new Date(thread.scoreUpdatedAt).getTime() + 86400000)
61+
) {
62+
calculateThreadScoreQueue.add(
63+
{
64+
threadId: thread.id,
65+
},
66+
{
67+
jobId: thread.id,
68+
}
69+
);
70+
}
5371
return thread;
5472
}
5573
};

api/routes/auth/create-signin-routes.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ export const createSigninRoutes = (
8080
// to the old URL the next time around
8181
// $FlowIssue
8282
req.session.redirectUrl = undefined;
83+
res.cookie('_now_no_cache', '1', {
84+
maxAge: 315569260000, // 10 years
85+
sameSite: 'lax',
86+
secure: false,
87+
});
8388
return res.redirect(redirectUrl.href);
8489
},
8590
],

0 commit comments

Comments
 (0)