Skip to content

Commit

Permalink
Adding routes and migration script for bookmarking (#126)
Browse files Browse the repository at this point in the history
* Adding routes and migration script for bookmarking

* Refactoring WeeklyDebrief

* Fixing unbookmarking functions

* Adding (un)bookmark articles tests

* More article bookmark tests

* Adding more tests for flyers and magazines
  • Loading branch information
Aayush-Agnihotri committed Nov 21, 2023
1 parent b70e2f1 commit 8acc8fa
Show file tree
Hide file tree
Showing 9 changed files with 281 additions and 33 deletions.
41 changes: 41 additions & 0 deletions migrations/update-users-model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
module.exports = {
async up(db) {
/**
* Adds the bookmarkedArticles, bookmarkedMagazines, and bookmarkedFlyers fields to all users.
* Removes the numBookmarkedArticles field from all users
*/
const users = await db.collection('users').find({}).toArray();
users.map(async (user) => {
await db
.collection('users')
.updateOne(
{ _id: user._id },
{ $set: { bookmarkedArticles: [], bookmarkedMagazines: [], bookmarkedFlyers: [] } },
);
await db
.collection('users')
.updateOne({ _id: user._id }, { $unset: { numBookmarkedArticles: '' } });
return user;
});
},

async down(db) {
/**
* Removes the bookmarkedArticles, bookmarkedMagazines, and bookmarkedFlyers fields from all users.
* Adds the numBookmarkedArticles field to all users
*/
const users = await db.collection('users').find({}).toArray();
users.map(async (user) => {
await db
.collection('users')
.updateOne(
{ _id: user._id },
{ $unset: { bookmarkedArticles: '', bookmarkedMagazines: '', bookmarkedFlyers: '' } },
);
await db
.collection('users')
.updateOne({ _id: user._id }, { $set: { numBookmarkedArticles: 0 } });
return user;
});
},
};
File renamed without changes.
16 changes: 12 additions & 4 deletions src/entities/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ export class User {
@Property({ default: 0 })
numShoutouts?: number;

@Field()
@Property({ default: 0 })
numBookmarkedArticles?: number;

@Field((type) => [Article])
@Property({ required: true, type: () => Article, default: [] })
readArticles: mongoose.Types.DocumentArray<DocumentType<Article>>;
Expand All @@ -59,6 +55,18 @@ export class User {
@Property({ required: true, type: () => Organization, default: [] })
followedOrganizations: mongoose.Types.DocumentArray<DocumentType<Organization>>;

@Field((type) => [Article])
@Property({ required: true, type: () => Article, default: [] })
bookmarkedArticles: mongoose.Types.DocumentArray<DocumentType<Article>>;

@Field((type) => [Magazine])
@Property({ required: true, type: () => Magazine, default: [] })
bookmarkedMagazines: mongoose.Types.DocumentArray<DocumentType<Magazine>>;

@Field((type) => [Flyer])
@Property({ required: true, type: () => Flyer, default: [] })
bookmarkedFlyers: mongoose.Types.DocumentArray<DocumentType<Flyer>>;

@Field({ nullable: true })
@Property()
weeklyDebrief?: WeeklyDebrief;
Expand Down
4 changes: 0 additions & 4 deletions src/entities/WeeklyDebrief.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@ export default class WeeklyDebrief {
@Property({ default: 0 })
numShoutouts?: number;

@Field()
@Property({ default: 0 })
numBookmarkedArticles?: number;

@Field()
@Property({ default: 0 })
numReadArticles?: number;
Expand Down
6 changes: 3 additions & 3 deletions src/repos/MagazineRepo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,14 @@ const getMagazinesByPublicationSlugs = async (
});
};

function getMagazineByID(id: string) {
return MagazineModel.findById(id).then((magazine) => {
const getMagazineByID = async (id: string): Promise<Magazine> => {
return MagazineModel.findById(new ObjectId(id)).then((magazine) => {
if (!isMagazineFiltered(magazine)) {
return magazine;
}
return null;
});
}
};

function getMagazinesByIDs(ids: string[]) {
return Promise.all(ids.map((id) => MagazineModel.findById(new ObjectId(id)))).then(
Expand Down
110 changes: 106 additions & 4 deletions src/repos/UserRepo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,19 +193,116 @@ const incrementShoutouts = async (uuid: string): Promise<User> => {
};

/**
* Increment number of bookmarks in user's numBookmarkedArticles
* Add article to a user's bookmarkedArticles
*/
const incrementBookmarks = async (uuid: string): Promise<User> => {
const bookmarkArticle = async (uuid: string, articleID: string): Promise<User> => {
const user = await UserModel.findOne({ uuid });

if (user) {
user.numBookmarkedArticles++;
const article = await ArticleRepo.getArticleByID(articleID);
const checkDuplicates = (prev: boolean, cur: Article) => prev || cur.id === articleID;

if (article && !user.bookmarkedArticles.reduce(checkDuplicates, false)) {
user.bookmarkedArticles.push(article);
}

user.save();
}

return user;
};

/**
* Add magazine to a user's bookmarkedMagazines
*/
const bookmarkMagazine = async (uuid: string, magazineID: string): Promise<User> => {
const user = await UserModel.findOne({ uuid });

if (user) {
const magazine = await MagazineRepo.getMagazineByID(magazineID);
const checkDuplicates = (prev: boolean, cur: Magazine) => prev || cur.id === magazineID;

if (magazine && !user.bookmarkedMagazines.reduce(checkDuplicates, false)) {
user.bookmarkedMagazines.push(magazine);
}

user.save();
}

return user;
};

/**
* Add flyer to a user's bookmarkedFlyers
*/
const bookmarkFlyer = async (uuid: string, flyerID: string): Promise<User> => {
const user = await UserModel.findOne({ uuid });

if (user) {
const flyer = await FlyerRepo.getFlyerByID(flyerID);
const checkDuplicates = (prev: boolean, cur: Flyer) => prev || cur.id === flyerID;

if (flyer && !user.bookmarkedFlyers.reduce(checkDuplicates, false)) {
user.bookmarkedFlyers.push(flyer);
}

user.save();
}

return user;
};

/**
* Remove article from a user's bookmarkedArticles
*/
const unbookmarkArticle = async (uuid: string, articleID: string): Promise<User> => {
const user = await UserModel.findOne({ uuid });
if (user) {
const articleSlugs = user.bookmarkedArticles.map((article) => article.id);
const articleIndex = articleSlugs.indexOf(articleID);

if (articleIndex === -1) return user;

user.bookmarkedArticles.splice(articleIndex, 1);
return user.save();
}
return user;
};

/**
* Remove magazine from a user's bookmarkedMagazines
*/
const unbookmarkMagazine = async (uuid: string, magazineID: string): Promise<User> => {
const user = await UserModel.findOne({ uuid });
if (user) {
const magazineSlugs = user.bookmarkedMagazines.map((magazine) => magazine.id);
const magazineIndex = magazineSlugs.indexOf(magazineID);

if (magazineIndex === -1) return user;

user.bookmarkedMagazines.splice(magazineIndex, 1);
return user.save();
}
return user;
};

/**
* Remove flyer from a user's bookmarkedFlyers
*/
const unbookmarkFlyer = async (uuid: string, flyerID: string): Promise<User> => {
const user = await UserModel.findOne({ uuid });
if (user) {
const flyerSlugs = user.bookmarkedFlyers.map((flyer) => flyer.id);
const flyerIndex = flyerSlugs.indexOf(flyerID);

if (flyerIndex === -1) return user;

user.bookmarkedFlyers.splice(flyerIndex, 1);
return user.save();
}
return user;
};

export default {
appendReadArticle,
appendReadMagazine,
Expand All @@ -217,7 +314,12 @@ export default {
getUserByUUID,
getUsersFollowingPublication,
getUsersFollowingOrganization,
incrementBookmarks,
bookmarkArticle,
bookmarkMagazine,
bookmarkFlyer,
unbookmarkArticle,
unbookmarkMagazine,
unbookmarkFlyer,
incrementShoutouts,
unfollowPublication,
};
2 changes: 0 additions & 2 deletions src/repos/WeeklyDebriefRepo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ const createWeeklyDebrief = async (
creationDate,
expirationDate,
numShoutouts: user.numShoutouts,
numBookmarkedArticles: user.numBookmarkedArticles,
readArticles: user.readArticles.slice(0, 2),
readMagazines: user.readMagazines.slice(0, 2),
numReadArticles: user.readArticles.length,
Expand All @@ -36,7 +35,6 @@ const createWeeklyDebrief = async (
readArticles: [],
readMagazines: [],
numShoutouts: 0,
numBookmarkedArticles: 0,
weeklyDebrief,
},
},
Expand Down
48 changes: 45 additions & 3 deletions src/resolvers/UserResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,52 @@ class UserResolver {

@Mutation((_returns) => User, {
nullable: true,
description: 'Increments the number of bookmarks for the <User> given by <uuid>',
description: 'Adds the <Article> given by <articleID> to the <User> <bookmarkedArticles> field',
})
async bookmarkArticle(@Arg('uuid') uuid: string) {
return await UserRepo.incrementBookmarks(uuid);
async bookmarkArticle(@Arg('uuid') uuid: string, @Arg('articleID') articleID: string) {
return await UserRepo.bookmarkArticle(uuid, articleID);
}

@Mutation((_returns) => User, {
nullable: true,
description:
'Adds the <Magazine> given by <magazineID> to the <User> <bookmarkedMagazines> field',
})
async bookmarkMagazine(@Arg('uuid') uuid: string, @Arg('magazineID') magazineID: string) {
return await UserRepo.bookmarkMagazine(uuid, magazineID);
}

@Mutation((_returns) => User, {
nullable: true,
description: 'Adds the <Flyer> given by <flyerID> to the <User> <bookmarkedFlyers> field',
})
async bookmarkFlyer(@Arg('uuid') uuid: string, @Arg('flyerID') flyerID: string) {
return await UserRepo.bookmarkFlyer(uuid, flyerID);
}

@Mutation((_returns) => User, {
nullable: true,
description: 'Removes the <Article> given by <articleID> from the <User> <bookmarkedArticles>',
})
async unbookmarkArticle(@Arg('uuid') uuid: string, @Arg('articleID') articleID: string) {
return await UserRepo.unbookmarkArticle(uuid, articleID);
}

@Mutation((_returns) => User, {
nullable: true,
description:
'Removes the <Magazine> given by <magazineID> from the <User> <bookmarkedMagazines>',
})
async unbookmarkMagazine(@Arg('uuid') uuid: string, @Arg('magazineID') magazineID: string) {
return await UserRepo.unbookmarkMagazine(uuid, magazineID);
}

@Mutation((_returns) => User, {
nullable: true,
description: 'Removes the <Flyer> given by <flyerID> from the <User> <bookmarkedFlyers>',
})
async unbookmarkFlyer(@Arg('uuid') uuid: string, @Arg('flyerID') flyerID: string) {
return await UserRepo.unbookmarkFlyer(uuid, flyerID);
}

@Mutation((_returns) => [User], {
Expand Down
Loading

0 comments on commit 8acc8fa

Please sign in to comment.