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

Commit dbb05da

Browse files
authored
Merge pull request #3739 from withspectrum/alpha
Prod cut
2 parents 2e06c27 + e3374b9 commit dbb05da

File tree

48 files changed

+878
-544
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+878
-544
lines changed

.circleci/config.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,11 @@ jobs:
130130
name: Deploy and alias API
131131
command: |
132132
cd build-api
133-
npx now-cd --alias "alpha=api.alpha.spectrum.chat" --team spaceprogram
133+
npx now-cd --alias "alpha=api.alpha.spectrum.chat" --team space-program
134134
cd ..
135135
- run:
136136
name: Deploy and alias Hyperion
137-
command: npx now-cd --alias "alpha=hyperion.alpha.spectrum.chat" --team spaceprogram
137+
command: npx now-cd --alias "alpha=hyperion.alpha.spectrum.chat" --team space-program
138138

139139
# Run eslint, flow etc.
140140
test_static_js:

api/loaders/community.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
getCommunitiesBySlug,
55
getCommunitiesMemberCounts,
66
getCommunitiesChannelCounts,
7+
getCommunitiesOnlineMemberCounts,
78
} from '../models/community';
89
import { getCommunitiesSettings } from '../models/communitySettings';
910
import { getCommunitiesRecurringPayments } from '../models/recurringPayment';
@@ -33,6 +34,11 @@ export const __createCommunityChannelCountLoader = createLoader(
3334
'group'
3435
);
3536

37+
export const __createCommunityOnlineMemberCountLoader = createLoader(
38+
communityIds => getCommunitiesOnlineMemberCounts(communityIds),
39+
'group'
40+
);
41+
3642
export const __createCommunitySettingsLoader = createLoader(
3743
communityIds => getCommunitiesSettings(communityIds),
3844
key => key.communityId

api/loaders/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
__createCommunityMemberCountLoader,
3030
__createCommunityChannelCountLoader,
3131
__createCommunitySettingsLoader,
32+
__createCommunityOnlineMemberCountLoader,
3233
} from './community';
3334
import {
3435
__createDirectMessageThreadLoader,
@@ -71,6 +72,7 @@ const createLoaders = (options?: DataLoaderOptions) => ({
7172
stripeCustomers: __createStripeCustomersLoader(options),
7273
communityChannelCount: __createCommunityChannelCountLoader(options),
7374
communityMemberCount: __createCommunityMemberCountLoader(options),
75+
communityOnlineMemberCount: __createCommunityOnlineMemberCountLoader(options),
7476
communitySettings: __createCommunitySettingsLoader(options),
7577
directMessageThread: __createDirectMessageThreadLoader(options),
7678
directMessageParticipants: __createDirectMessageParticipantsLoader(options),

api/models/community.js

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ export const getVisibleCommunitiesByUser = async (evaluatingUserId: string, curr
118118
const overlappingMemberships = intersection(evaluatingUserCommunityIds, currentUserCommunityIds)
119119
const allVisibleCommunityIds = [...publicCommunityIds, ...overlappingMemberships]
120120
const distinctCommunityIds = allVisibleCommunityIds.filter((x, i, a) => a.indexOf(x) === i)
121-
121+
122122
return await db
123123
.table('communities')
124124
.getAll(...distinctCommunityIds)
@@ -165,6 +165,38 @@ export const getCommunitiesMemberCounts = (communityIds: Array<string>) => {
165165
.run();
166166
};
167167

168+
export const getCommunitiesOnlineMemberCounts = (
169+
communityIds: Array<string>
170+
) => {
171+
return db
172+
.table('usersCommunities')
173+
.getAll(...communityIds, {
174+
index: 'communityId',
175+
})
176+
.filter({ isBlocked: false, isMember: true })
177+
.pluck(['communityId', 'userId'])
178+
.eqJoin('userId', db.table('users'))
179+
.pluck('left', { right: ['lastSeen', 'isOnline'] })
180+
.zip()
181+
.filter(rec =>
182+
rec('isOnline')
183+
.eq(true)
184+
.or(
185+
rec('lastSeen')
186+
.toEpochTime()
187+
.ge(
188+
db
189+
.now()
190+
.toEpochTime()
191+
.sub(86400)
192+
)
193+
)
194+
)
195+
.group('communityId')
196+
.count()
197+
.run();
198+
};
199+
168200
// prettier-ignore
169201
export const getCommunityMetaData = (communityId: string): Promise<Array<number>> => {
170202
const getChannelCount = db

api/models/reputationEvents.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export const getTopMembersInCommunity = (communityId: string): Promise<Array<str
1313
.group('userId')
1414
.run()
1515
.then(results => {
16-
if (!results) return null;
16+
if (!results) return [];
1717
const sorted = results
1818
.map(c => ({
1919
userId: c.group,

api/models/user.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -480,11 +480,7 @@ const setUserOnline = (id: string, isOnline: boolean): DBUser => {
480480
let data = {};
481481

482482
data.isOnline = isOnline;
483-
484-
// If a user is going offline, store their lastSeen
485-
if (isOnline === false) {
486-
data.lastSeen = new Date();
487-
}
483+
data.lastSeen = new Date();
488484
return db
489485
.table('users')
490486
.get(id)

api/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
"hoist-non-react-statics": "^2.5.5",
5656
"host-validation": "^1.1.0",
5757
"hpp": "^0.2.2",
58-
"imgix-core-js": "^1.0.6",
58+
"imgix-core-js": "^1.2.0",
5959
"immutability-helper": "^2.7.1",
6060
"isomorphic-fetch": "^2.2.1",
6161
"iterall": "^1.2.2",
@@ -108,7 +108,7 @@
108108
"redux-thunk": "^2.3.0",
109109
"rethinkdb-changefeed-reconnect": "^0.3.2",
110110
"rethinkdb-inspector": "^0.3.3",
111-
"rethinkdb-migrate": "^1.3.0",
111+
"rethinkdb-migrate": "^1.4.0",
112112
"rethinkdbdash": "^2.3.29",
113113
"sanitize-filename": "^1.6.1",
114114
"serialize-javascript": "^1.5.0",

api/queries/community/conversationGrowth.js

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import type { DBCommunity } from 'shared/types';
33
import type { GraphQLContext } from '../../';
44
import UserError from '../../utils/UserError';
5+
import { canAdministerCommunity } from '../../utils/permissions';
56
const {
67
getThreadCount,
78
getCommunityGrowth,
@@ -18,36 +19,28 @@ export default async (
1819
return new UserError('You must be signed in to continue.');
1920
}
2021

21-
const { isOwner } = await loaders.userPermissionsInCommunity.load([
22-
currentUser.id,
23-
id,
24-
]);
25-
26-
if (!isOwner) {
22+
if (!await canAdministerCommunity(currentUser.id, id, loaders)) {
2723
return new UserError(
28-
'You must be the owner of this community to view analytics.'
24+
'You must be a team member to view community analytics.'
2925
);
3026
}
3127

28+
const [
29+
count,
30+
weeklyGrowth,
31+
monthlyGrowth,
32+
quarterlyGrowth,
33+
] = await Promise.all([
34+
getThreadCount(id),
35+
getCommunityGrowth('threads', 'weekly', 'createdAt', id),
36+
getCommunityGrowth('threads', 'monthly', 'createdAt', id),
37+
getCommunityGrowth('threads', 'quarterly', 'createdAt', id),
38+
]);
39+
3240
return {
33-
count: await getThreadCount(id),
34-
weeklyGrowth: await getCommunityGrowth(
35-
'threads',
36-
'weekly',
37-
'createdAt',
38-
id
39-
),
40-
monthlyGrowth: await getCommunityGrowth(
41-
'threads',
42-
'monthly',
43-
'createdAt',
44-
id
45-
),
46-
quarterlyGrowth: await getCommunityGrowth(
47-
'threads',
48-
'quarterly',
49-
'createdAt',
50-
id
51-
),
41+
count,
42+
weeklyGrowth,
43+
monthlyGrowth,
44+
quarterlyGrowth,
5245
};
5346
};

api/queries/community/metaData.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,22 @@ export default async (root: DBCommunity, _: any, ctx: GraphQLContext) => {
77
const { user, loaders } = ctx;
88
const { id } = root;
99

10-
if (!await canViewCommunity(user, id, loaders)) {
10+
if (!(await canViewCommunity(user, id, loaders))) {
1111
return {
1212
channels: 0,
1313
members: 0,
1414
};
1515
}
1616

17-
const [channelCount, memberCount] = await Promise.all([
17+
const [channelCount, memberCount, onlineMemberCount] = await Promise.all([
1818
loaders.communityChannelCount.load(id),
1919
loaders.communityMemberCount.load(id),
20+
loaders.communityOnlineMemberCount.load(id),
2021
]);
2122

2223
return {
2324
channels: channelCount ? channelCount.reduction : 0,
2425
members: memberCount ? memberCount.reduction : 0,
26+
onlineMembers: onlineMemberCount ? onlineMemberCount.reduction : 0,
2527
};
2628
};

api/queries/community/topAndNewThreads.js

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,47 +2,60 @@
22
import type { DBCommunity } from 'shared/types';
33
import type { GraphQLContext } from '../../';
44
import UserError from '../../utils/UserError';
5+
import { canAdministerCommunity } from '../../utils/permissions';
56
import { getMessageCount } from '../../models/message';
67
import {
78
getThreads,
89
getThreadsByCommunityInTimeframe,
910
} from '../../models/thread';
1011

11-
export default ({ id }: DBCommunity, __: any, { user }: GraphQLContext) => {
12+
export default async (
13+
{ id }: DBCommunity,
14+
__: any,
15+
{ user, loaders }: GraphQLContext
16+
) => {
1217
const currentUser = user;
1318

1419
if (!currentUser) {
1520
return new UserError('You must be signed in to continue.');
1621
}
1722

18-
return getThreadsByCommunityInTimeframe(id, 'weekly').then(async threads => {
19-
if (!threads) return { topThreads: [], newThreads: [] };
20-
21-
const messageCountPromises = threads.map(async ({ id }) => ({
22-
id,
23-
messageCount: await getMessageCount(id),
24-
}));
25-
26-
// promise all the active threads and message counts
27-
const threadsWithMessageCounts = await Promise.all(messageCountPromises);
28-
29-
const topThreads = threadsWithMessageCounts
30-
.filter(t => t.messageCount > 0)
31-
.sort((a, b) => {
32-
const bc = parseInt(b.messageCount, 10);
33-
const ac = parseInt(a.messageCount, 10);
34-
return bc <= ac ? -1 : 1;
35-
})
36-
.slice(0, 10)
37-
.map(t => t.id);
38-
39-
const newThreads = threadsWithMessageCounts
40-
.filter(t => t.messageCount === 0)
41-
.map(t => t.id);
42-
43-
return {
44-
topThreads: await getThreads([...topThreads]),
45-
newThreads: await getThreads([...newThreads]),
46-
};
47-
});
23+
if (!await canAdministerCommunity(currentUser.id, id, loaders)) {
24+
return new UserError(
25+
'You must be a team member to view community analytics.'
26+
);
27+
}
28+
29+
const threads = await getThreadsByCommunityInTimeframe(id, 'weekly');
30+
31+
if (!threads || threads.length === 0)
32+
return { topThreads: [], newThreads: [] };
33+
34+
const threadsWithMessageCounts = await Promise.all(
35+
threads.map(({ id }) =>
36+
getMessageCount(id).then(messageCount => ({
37+
id,
38+
messageCount,
39+
}))
40+
)
41+
);
42+
43+
const topThreads = threadsWithMessageCounts
44+
.filter(t => t.messageCount > 0)
45+
.sort((a, b) => {
46+
const bc = parseInt(b.messageCount, 10);
47+
const ac = parseInt(a.messageCount, 10);
48+
return bc <= ac ? -1 : 1;
49+
})
50+
.slice(0, 10)
51+
.map(t => t.id);
52+
53+
const newThreads = threadsWithMessageCounts
54+
.filter(t => t.messageCount === 0)
55+
.map(t => t.id);
56+
57+
return {
58+
topThreads: await getThreads([...topThreads]),
59+
newThreads: await getThreads([...newThreads]),
60+
};
4861
};

0 commit comments

Comments
 (0)