Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions convertors/set-user-workspaces-membership.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
require('dotenv').config();
require('process');
const { setup } = require('./setup');

/**
* Method that runs convertor script
*/
async function run() {
const { client, hawkDb } = await setup();

const collections = await hawkDb.listCollections({}, {
authorizedCollections: true,
nameOnly: true,
}).toArray();

let usersMembershipCollectionsToCheck = collections.filter(col => /^membership:/.test(col.name)).map(col => col.name);

console.log(`Found ${usersMembershipCollectionsToCheck.length} users membership collections.`);

const usersDocuments = await hawkDb.collection('users').find({}).toArray();

let i = 1;

for (const collectionName of usersMembershipCollectionsToCheck) {
console.log(`[${i}/${usersMembershipCollectionsToCheck.length}] Processing ${collectionName}`);

const userId = collectionName.split(':')[1];

const userDocument = usersDocuments.find(u => u._id.toString() === userId);

if (!userDocument) {
i++;
continue;
}

const memberships = await hawkDb.collection(collectionName).find({}).toArray();

for (const membership of memberships) {
const workspaceId = membership.workspaceId.toString();
const isPending = membership.isPending || false;
await hawkDb.collection('users').updateOne({ _id: userDocument._id }, { $set: { [`workspaces.${workspaceId}`]: { isPending } } });
}

i++;
}

await client.close();
}

run().catch(err => {
console.error('❌ Script failed:', err);
process.exit(1);
});
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "hawk.api",
"version": "1.2.16",
"version": "1.2.17",
"main": "index.ts",
"license": "BUSL-1.1",
"scripts": {
Expand Down
84 changes: 29 additions & 55 deletions src/models/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,9 @@ export interface TokensPair {
/**
* Membership collection DB implementation
*/
export interface MembershipDBScheme {
/**
* Document id
*/
_id: ObjectId;

/**
* User's workspace id
*/
workspaceId: ObjectId;

/**
* Shows if member is pending
*/
export type MembershipDBScheme = Record<string, {
isPending?: boolean;
}
}>;

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

/**
* User's workspaces
*/
public workspaces!: MembershipDBScheme;

/**
* User's original password (this field appears only after registration).
* Using to send password to user after registration
Expand Down Expand Up @@ -155,11 +147,6 @@ export default class UserModel extends AbstractModel<UserDBScheme> implements Us
*/
protected collection: Collection<UserDBScheme>;

/**
* Collection of user's workspaces
*/
private membershipCollection: Collection<MembershipDBScheme>;

/**
* Model constructor
* @param modelData - user data
Expand All @@ -174,7 +161,6 @@ export default class UserModel extends AbstractModel<UserDBScheme> implements Us

super(modelData);

this.membershipCollection = this.dbConnection.collection('membership:' + this._id);
this.collection = this.dbConnection.collection<UserDBScheme>('users');
}

Expand Down Expand Up @@ -339,19 +325,13 @@ export default class UserModel extends AbstractModel<UserDBScheme> implements Us
* @param workspaceId - user's id to add
* @param isPending - if true, mark user's membership as pending
*/
public async addWorkspace(workspaceId: string, isPending = false): Promise<object> {
const doc: OptionalId<MembershipDBScheme> = {
workspaceId: new ObjectId(workspaceId),
};

if (isPending) {
doc.isPending = isPending;
}

const documentId = (await this.membershipCollection.insertOne(doc)).insertedId;
public async addWorkspace(workspaceId: string, isPending = false): Promise<{ workspaceId: string }> {
await this.update(
{ _id: new ObjectId(this._id) },
{ [`workspaces.${workspaceId}`]: { isPending } }
);

return {
id: documentId,
workspaceId,
};
}
Expand All @@ -361,9 +341,10 @@ export default class UserModel extends AbstractModel<UserDBScheme> implements Us
* @param workspaceId - id of workspace to remove
*/
public async removeWorkspace(workspaceId: string): Promise<{ workspaceId: string }> {
await this.membershipCollection.deleteOne({
workspaceId: new ObjectId(workspaceId),
});
await this.collection.updateOne(
{ _id: new ObjectId(this._id) },
{ $unset: { [`workspaces.${workspaceId}`]: '' } }
);

return {
workspaceId,
Expand All @@ -375,11 +356,9 @@ export default class UserModel extends AbstractModel<UserDBScheme> implements Us
* @param workspaceId - workspace id to confirm
*/
public async confirmMembership(workspaceId: string): Promise<void> {
await this.membershipCollection.updateOne(
{
workspaceId: new ObjectId(workspaceId),
},
{ $unset: { isPending: '' } }
await this.collection.updateOne(
{ _id: new ObjectId(this._id) },
{ $unset: { [`workspaces.${workspaceId}.isPending`]: '' } }
);
}

Expand All @@ -389,23 +368,18 @@ export default class UserModel extends AbstractModel<UserDBScheme> implements Us
* @param ids - workspaces id to filter them if there are workspaces that doesn't belong to the user
*/
public async getWorkspacesIds(ids: (string | ObjectId)[] = []): Promise<string[]> {
const idsAsObjectId = ids.map(id => new ObjectId(id));
const searchQuery = ids.length ? {
workspaceId: {
$in: idsAsObjectId,
},
isPending: {
$ne: true,
},
} : {
isPending: {
$ne: true,
},
};
const res = [];

const membershipDocuments = await this.membershipCollection.find(searchQuery).toArray();
for (const id of ids) {
const workspaceId = id.toString();
const workspace = this.workspaces[workspaceId];

if (workspace && workspace.isPending !== true) {
res.push(workspaceId);
}
}

return membershipDocuments.map(doc => doc.workspaceId.toString());
return res;
}

/**
Expand Down
Loading