Skip to content

Commit 8cf181f

Browse files
authored
Merge pull request #573 from codex-team/master
Update prod
2 parents 1930b27 + 17be2b0 commit 8cf181f

File tree

5 files changed

+97
-57
lines changed

5 files changed

+97
-57
lines changed

convertors/set-user-project-last-visit.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ async function run() {
3535
const userDocument = usersDocuments.find(u => u._id.toString() === userInProject.userId.toString());
3636
if (userDocument) {
3737
const projectId = collectionName.split(':')[1];
38-
await hawkDb.collection('users').updateOne({ _id: userDocument._id }, { $set: { projectsLastVisit: { [projectId]: userInProject.timestamp } } });
38+
await hawkDb.collection('users').updateOne({ _id: userDocument._id }, { $set: { [`projectsLastVisit.${projectId}`]: userInProject.timestamp } });
3939
usersUpdatedCount++;
4040
console.log(`Updated ${usersUpdatedCount}/${usersInProject.length} users in project ${collectionName}.`);
4141
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
require('dotenv').config();
2+
require('process');
3+
const { setup } = require('./setup');
4+
5+
/**
6+
* Method that runs convertor script
7+
*/
8+
async function run() {
9+
const { client, hawkDb } = await setup();
10+
11+
const collections = await hawkDb.listCollections({}, {
12+
authorizedCollections: true,
13+
nameOnly: true,
14+
}).toArray();
15+
16+
let usersMembershipCollectionsToCheck = collections.filter(col => /^membership:/.test(col.name)).map(col => col.name);
17+
18+
console.log(`Found ${usersMembershipCollectionsToCheck.length} users membership collections.`);
19+
20+
const usersDocuments = await hawkDb.collection('users').find({}).toArray();
21+
22+
let i = 1;
23+
24+
for (const collectionName of usersMembershipCollectionsToCheck) {
25+
console.log(`[${i}/${usersMembershipCollectionsToCheck.length}] Processing ${collectionName}`);
26+
27+
const userId = collectionName.split(':')[1];
28+
29+
const userDocument = usersDocuments.find(u => u._id.toString() === userId);
30+
31+
if (!userDocument) {
32+
i++;
33+
continue;
34+
}
35+
36+
const memberships = await hawkDb.collection(collectionName).find({}).toArray();
37+
38+
for (const membership of memberships) {
39+
const workspaceId = membership.workspaceId.toString();
40+
const isPending = membership.isPending || false;
41+
await hawkDb.collection('users').updateOne({ _id: userDocument._id }, { $set: { [`workspaces.${workspaceId}`]: { isPending } } });
42+
}
43+
44+
i++;
45+
}
46+
47+
await client.close();
48+
}
49+
50+
run().catch(err => {
51+
console.error('❌ Script failed:', err);
52+
process.exit(1);
53+
});

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "hawk.api",
3-
"version": "1.2.14",
3+
"version": "1.2.18",
44
"main": "index.ts",
55
"license": "BUSL-1.1",
66
"scripts": {

src/models/user.ts

Lines changed: 33 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -33,22 +33,9 @@ export interface TokensPair {
3333
/**
3434
* Membership collection DB implementation
3535
*/
36-
export interface MembershipDBScheme {
37-
/**
38-
* Document id
39-
*/
40-
_id: ObjectId;
41-
42-
/**
43-
* User's workspace id
44-
*/
45-
workspaceId: ObjectId;
46-
47-
/**
48-
* Shows if member is pending
49-
*/
36+
export type MembershipDBScheme = Record<string, {
5037
isPending?: boolean;
51-
}
38+
}>;
5239

5340
/**
5441
* This structure represents how user notifications are stored at the DB (in 'users' collection)
@@ -124,6 +111,11 @@ export default class UserModel extends AbstractModel<UserDBScheme> implements Us
124111
*/
125112
public githubId?: string;
126113

114+
/**
115+
* User's workspaces
116+
*/
117+
public workspaces!: MembershipDBScheme;
118+
127119
/**
128120
* User's original password (this field appears only after registration).
129121
* Using to send password to user after registration
@@ -155,11 +147,6 @@ export default class UserModel extends AbstractModel<UserDBScheme> implements Us
155147
*/
156148
protected collection: Collection<UserDBScheme>;
157149

158-
/**
159-
* Collection of user's workspaces
160-
*/
161-
private membershipCollection: Collection<MembershipDBScheme>;
162-
163150
/**
164151
* Model constructor
165152
* @param modelData - user data
@@ -174,7 +161,6 @@ export default class UserModel extends AbstractModel<UserDBScheme> implements Us
174161

175162
super(modelData);
176163

177-
this.membershipCollection = this.dbConnection.collection('membership:' + this._id);
178164
this.collection = this.dbConnection.collection<UserDBScheme>('users');
179165
}
180166

@@ -339,19 +325,13 @@ export default class UserModel extends AbstractModel<UserDBScheme> implements Us
339325
* @param workspaceId - user's id to add
340326
* @param isPending - if true, mark user's membership as pending
341327
*/
342-
public async addWorkspace(workspaceId: string, isPending = false): Promise<object> {
343-
const doc: OptionalId<MembershipDBScheme> = {
344-
workspaceId: new ObjectId(workspaceId),
345-
};
346-
347-
if (isPending) {
348-
doc.isPending = isPending;
349-
}
350-
351-
const documentId = (await this.membershipCollection.insertOne(doc)).insertedId;
328+
public async addWorkspace(workspaceId: string, isPending = false): Promise<{ workspaceId: string }> {
329+
await this.update(
330+
{ _id: new ObjectId(this._id) },
331+
{ [`workspaces.${workspaceId}`]: { isPending } }
332+
);
352333

353334
return {
354-
id: documentId,
355335
workspaceId,
356336
};
357337
}
@@ -361,9 +341,10 @@ export default class UserModel extends AbstractModel<UserDBScheme> implements Us
361341
* @param workspaceId - id of workspace to remove
362342
*/
363343
public async removeWorkspace(workspaceId: string): Promise<{ workspaceId: string }> {
364-
await this.membershipCollection.deleteOne({
365-
workspaceId: new ObjectId(workspaceId),
366-
});
344+
await this.collection.updateOne(
345+
{ _id: new ObjectId(this._id) },
346+
{ $unset: { [`workspaces.${workspaceId}`]: '' } }
347+
);
367348

368349
return {
369350
workspaceId,
@@ -375,11 +356,9 @@ export default class UserModel extends AbstractModel<UserDBScheme> implements Us
375356
* @param workspaceId - workspace id to confirm
376357
*/
377358
public async confirmMembership(workspaceId: string): Promise<void> {
378-
await this.membershipCollection.updateOne(
379-
{
380-
workspaceId: new ObjectId(workspaceId),
381-
},
382-
{ $unset: { isPending: '' } }
359+
await this.collection.updateOne(
360+
{ _id: new ObjectId(this._id) },
361+
{ $unset: { [`workspaces.${workspaceId}.isPending`]: '' } }
383362
);
384363
}
385364

@@ -389,23 +368,22 @@ export default class UserModel extends AbstractModel<UserDBScheme> implements Us
389368
* @param ids - workspaces id to filter them if there are workspaces that doesn't belong to the user
390369
*/
391370
public async getWorkspacesIds(ids: (string | ObjectId)[] = []): Promise<string[]> {
392-
const idsAsObjectId = ids.map(id => new ObjectId(id));
393-
const searchQuery = ids.length ? {
394-
workspaceId: {
395-
$in: idsAsObjectId,
396-
},
397-
isPending: {
398-
$ne: true,
399-
},
400-
} : {
401-
isPending: {
402-
$ne: true,
403-
},
404-
};
371+
const res = [];
405372

406-
const membershipDocuments = await this.membershipCollection.find(searchQuery).toArray();
373+
if (ids.length === 0) {
374+
return Object.keys(this.workspaces);
375+
}
376+
377+
for (const id of ids) {
378+
const workspaceId = id.toString();
379+
const workspace = this.workspaces[workspaceId];
380+
381+
if (workspace && workspace.isPending !== true) {
382+
res.push(workspaceId);
383+
}
384+
}
407385

408-
return membershipDocuments.map(doc => doc.workspaceId.toString());
386+
return res;
409387
}
410388

411389
/**

src/resolvers/project.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const REPETITIONS_GROUP_HASH_INDEX_NAME = 'groupHash_hashed';
1414
const REPETITIONS_USER_ID_INDEX_NAME = 'userId';
1515
const EVENTS_TIMESTAMP_INDEX_NAME = 'timestamp';
1616
const GROUPING_TIMESTAMP_INDEX_NAME = 'groupingTimestamp';
17+
const GROUPING_TIMESTAMP_AND_LAST_REPETITION_TIME_AND_ID_INDEX_NAME = 'groupingTimestampAndLastRepetitionTimeAndId';
1718
const GROUPING_TIMESTAMP_AND_GROUP_HASH_INDEX_NAME = 'groupingTimestampAndGroupHash';
1819
const MAX_SEARCH_QUERY_LENGTH = 50;
1920

@@ -117,6 +118,14 @@ module.exports = {
117118
name: GROUPING_TIMESTAMP_AND_GROUP_HASH_INDEX_NAME,
118119
});
119120

121+
await projectDailyEventsCollection.createIndex({
122+
groupingTimestamp: -1,
123+
lastRepetitionTime: -1,
124+
_id: -1,
125+
}, {
126+
name: GROUPING_TIMESTAMP_AND_LAST_REPETITION_TIME_AND_ID_INDEX_NAME,
127+
});
128+
120129
await projectEventsCollection.createIndex({
121130
groupHash: 1,
122131
},

0 commit comments

Comments
 (0)