-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement community board [1/7] #81
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,229 @@ | ||
import Filter from 'bad-words'; | ||
import { ObjectId } from 'mongodb'; | ||
import Fuse from 'fuse.js'; | ||
import { Flyer, FlyerModel } from '../entities/Flyer'; | ||
import { | ||
DEFAULT_LIMIT, | ||
MAX_NUM_DAYS_OF_TRENDING_ARTICLES, | ||
FILTERED_WORDS, | ||
DEFAULT_OFFSET, | ||
} from '../common/constants'; | ||
import { OrganizationModel } from '../entities/Organization'; | ||
|
||
const { IS_FILTER_ACTIVE } = process.env; | ||
|
||
function isFlyerFiltered(flyer: Flyer) { | ||
if (IS_FILTER_ACTIVE === 'true') { | ||
if (flyer.isFiltered) { | ||
// If the body has been checked already in microservice | ||
return true; | ||
} | ||
const filter = new Filter({ list: FILTERED_WORDS }); | ||
return filter.isProfane(flyer.title); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i agree with @katesliang 's comments from ur last PR
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanks shungo There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah i think the microservice for articles only checks the body, so i was planning on doing the same thing for flyers, but i realized that flyers actually don't have a body (it's just an image) so I'll get rid of this part There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nice |
||
} | ||
return false; | ||
} | ||
|
||
const getFlyerByID = async (id: string): Promise<Flyer> => { | ||
return FlyerModel.findById(new ObjectId(id)).then((flyer) => { | ||
if (!isFlyerFiltered(flyer)) { | ||
return flyer; | ||
} | ||
return null; | ||
}); | ||
}; | ||
|
||
const getFlyersByIDs = async (ids: string[]): Promise<Flyer[]> => { | ||
return Promise.all(ids.map((id) => FlyerModel.findById(new ObjectId(id)))).then((flyers) => { | ||
// Filter out all null values that were returned by ObjectIds not associated | ||
// with Flyers in database | ||
return flyers.filter((flyer) => flyer !== null && !isFlyerFiltered(flyer)); | ||
}); | ||
}; | ||
|
||
const getAllFlyers = async (offset = DEFAULT_OFFSET, limit = DEFAULT_LIMIT): Promise<Flyer[]> => { | ||
return FlyerModel.find({}) | ||
.sort({ date: 'desc' }) | ||
.skip(offset) | ||
.limit(limit) | ||
.then((flyers) => { | ||
return flyers.filter((flyer) => !isFlyerFiltered(flyer)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why do you check if it's not null here but in the above and below functions? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i think getAllFlyers shouldn't return extra nulls because it's using find({}) and getFlyerByID is only looking for one article so it'll only return null if there aren't any flyers to be found |
||
}); | ||
}; | ||
|
||
const getFlyersByOrganizationSlug = async ( | ||
slug: string, | ||
limit: number = DEFAULT_LIMIT, | ||
offset: number = DEFAULT_OFFSET, | ||
): Promise<Flyer[]> => { | ||
return FlyerModel.find({ 'organization.slug': slug }) | ||
.sort({ date: 'desc' }) | ||
.skip(offset) | ||
.limit(limit) | ||
.then((flyers) => { | ||
return flyers.filter((flyer) => flyer !== null && !isFlyerFiltered(flyer)); | ||
}); | ||
}; | ||
|
||
const getFlyersByOrganizationSlugs = async ( | ||
slugs: string[], | ||
limit: number = DEFAULT_LIMIT, | ||
offset: number = DEFAULT_OFFSET, | ||
): Promise<Flyer[]> => { | ||
const uniqueSlugs = [...new Set(slugs)]; | ||
return FlyerModel.find({ 'organization.slug': { $in: uniqueSlugs } }) | ||
.sort({ date: 'desc' }) | ||
.skip(offset) | ||
.limit(limit) | ||
.then((flyers) => { | ||
return flyers.filter((flyer) => flyer !== null && !isFlyerFiltered(flyer)); | ||
}); | ||
}; | ||
|
||
const getFlyersByOrganizationID = async ( | ||
organizationID: string, | ||
limit: number = DEFAULT_LIMIT, | ||
offset: number = DEFAULT_OFFSET, | ||
): Promise<Flyer[]> => { | ||
const organization = await (await OrganizationModel.findById(organizationID)).execPopulate(); | ||
return FlyerModel.find({ 'organization.slug': organization.slug }) | ||
.sort({ date: 'desc' }) | ||
.skip(offset) | ||
.limit(limit) | ||
.then((flyers) => { | ||
return flyers.filter((flyer) => !isFlyerFiltered(flyer)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same comment as above There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you're right i'll check for null in getFlyersByOrganizationID |
||
}); | ||
}; | ||
|
||
const getFlyersByOrganizationIDs = async ( | ||
organizationIDs: string[], | ||
limit: number = DEFAULT_LIMIT, | ||
offset: number = DEFAULT_OFFSET, | ||
): Promise<Flyer[]> => { | ||
const uniqueOrgIDs = [...new Set(organizationIDs)].map((id) => new ObjectId(id)); | ||
console.log(uniqueOrgIDs); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. delete? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. true |
||
const orgSlugs = await OrganizationModel.find({ _id: { $in: uniqueOrgIDs } }).select('slug'); | ||
return getFlyersByOrganizationSlugs( | ||
orgSlugs.map((org) => org.slug), | ||
limit, | ||
offset, | ||
); | ||
}; | ||
|
||
const getFlyersAfterDate = async (since: string, limit = DEFAULT_LIMIT): Promise<Flyer[]> => { | ||
return ( | ||
FlyerModel.find({ | ||
// Get all Flyers after or on the desired date | ||
date: { $gte: new Date(new Date(since).setHours(0, 0, 0)) }, | ||
}) | ||
// Sort dates in order of most recent to least | ||
.sort({ date: 'desc' }) | ||
.limit(limit) | ||
.then((flyers) => { | ||
return flyers.filter((flyer) => !isFlyerFiltered(flyer)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. truee |
||
}) | ||
); | ||
}; | ||
|
||
/** | ||
* Performs fuzzy search on all Flyers to find Flyers with title/publisher matching the query. | ||
* @param query the term to search for | ||
* @param limit the number of results to return | ||
* @returns at most limit Flyers with titles or publishers matching the query | ||
*/ | ||
const searchFlyers = async (query: string, limit = DEFAULT_LIMIT) => { | ||
const allFlyers = await FlyerModel.find({}); | ||
const searcher = new Fuse(allFlyers, { | ||
keys: ['title', 'organization.name'], | ||
}); | ||
|
||
return searcher | ||
.search(query) | ||
.map((searchRes) => searchRes.item) | ||
.slice(0, limit); | ||
}; | ||
|
||
/** | ||
* Computes and returns the trending Flyers in the database. | ||
* | ||
* @function | ||
* @param {number} limit - number of Flyers to retrieve. | ||
*/ | ||
const getTrendingFlyers = async (limit = DEFAULT_LIMIT): Promise<Flyer[]> => { | ||
const flyers = await FlyerModel.find({ isTrending: true }).exec(); | ||
return flyers.filter((flyer) => !isFlyerFiltered(flyer)).slice(0, limit); | ||
}; | ||
|
||
/** | ||
* Refreshes trending Flyers. | ||
*/ | ||
const refreshTrendingFlyers = async (): Promise<Flyer[]> => { | ||
// Set previous trending Flyers to not trending | ||
const oldTrendingFlyers = await FlyerModel.find({ isTrending: true }).exec(); | ||
oldTrendingFlyers.forEach(async (a) => { | ||
const flyer = await FlyerModel.findById(new ObjectId(a._id)); // eslint-disable-line | ||
flyer.isTrending = false; | ||
await flyer.save(); | ||
}); | ||
|
||
// Get new trending Flyers | ||
const flyers = await FlyerModel.aggregate() | ||
// Get a sample of random Flyers | ||
.sample(100) | ||
// Get Flyers after 30 days ago | ||
.match({ | ||
date: { | ||
$gte: new Date( | ||
new Date().setDate(new Date().getDate() - MAX_NUM_DAYS_OF_TRENDING_ARTICLES), | ||
), | ||
}, | ||
Comment on lines
+168
to
+175
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. and this
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. rn we're just randomly sampling because we don't have any flyers T_T but I can fix it later after we get the app launched There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. okie you should leave a comment or create an issue or smth to document it somewhere There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's create an issue! @isaachan100 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. prod |
||
}); | ||
|
||
flyers.forEach(async (a) => { | ||
const flyer = await FlyerModel.findById(new ObjectId(a._id)); // eslint-disable-line | ||
flyer.isTrending = true; | ||
await flyer.save(); | ||
}); | ||
|
||
return flyers; | ||
}; | ||
|
||
/** | ||
* Increments number of shoutouts on an Flyer and publication by one. | ||
* @function | ||
* @param {string} id - string representing the unique Object Id of an Flyer. | ||
*/ | ||
const incrementShoutouts = async (id: string): Promise<Flyer> => { | ||
const flyer = await FlyerModel.findById(new ObjectId(id)); | ||
if (flyer) { | ||
flyer.shoutouts += 1; | ||
return flyer.save(); | ||
} | ||
return flyer; | ||
}; | ||
|
||
/** | ||
* Checks if an Flyer's title contains profanity. | ||
* @function | ||
* @param {string} title - Flyer title. | ||
*/ | ||
const checkProfanity = async (title: string): Promise<boolean> => { | ||
const filter = new Filter(); | ||
return filter.isProfane(title); | ||
}; | ||
|
||
export default { | ||
checkProfanity, | ||
getAllFlyers, | ||
getFlyerByID, | ||
getFlyersAfterDate, | ||
getFlyersByIDs, | ||
getFlyersByOrganizationID, | ||
getFlyersByOrganizationIDs, | ||
getFlyersByOrganizationSlug, | ||
getFlyersByOrganizationSlugs, | ||
searchFlyers, | ||
getTrendingFlyers, | ||
incrementShoutouts, | ||
refreshTrendingFlyers, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. alphabetize There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. appdev teaching me the alphabet im so thankful |
||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
alphabetize!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
trueee
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prod