2020-11-19 17:11:23 +03:00
|
|
|
import HttpError from '@wasp/core/HttpError.js'
|
|
|
|
|
2020-11-24 22:39:36 +03:00
|
|
|
const userPublicSelection = {
|
|
|
|
id: true,
|
|
|
|
username: true,
|
|
|
|
email: true,
|
|
|
|
bio: true,
|
|
|
|
profilePictureUrl: true
|
|
|
|
}
|
|
|
|
|
2020-11-19 17:11:23 +03:00
|
|
|
export const getUser = async ({ username }, context) => {
|
|
|
|
// TODO: Do some error handling?
|
2020-11-27 00:48:35 +03:00
|
|
|
const user = await context.entities.User.findUnique({
|
2020-11-24 22:39:36 +03:00
|
|
|
where: { username },
|
|
|
|
// TODO: Tricky, if you forget this you could return unwanted fields
|
|
|
|
// like hashed password!
|
|
|
|
// It would be cool if we had some protection against making this mistake easily.
|
2020-11-27 18:10:02 +03:00
|
|
|
select: {
|
|
|
|
...userPublicSelection,
|
|
|
|
followedBy: { select: { id: true } }
|
|
|
|
}
|
2020-11-24 22:39:36 +03:00
|
|
|
})
|
2020-11-19 17:11:23 +03:00
|
|
|
if (!user) throw new HttpError(404, 'No user with username ' + username)
|
2020-11-27 18:10:02 +03:00
|
|
|
|
|
|
|
userSetFollowedFields(user, context.user)
|
|
|
|
|
2020-11-19 17:11:23 +03:00
|
|
|
return user
|
|
|
|
}
|
2020-11-20 20:22:49 +03:00
|
|
|
|
2020-11-27 18:10:02 +03:00
|
|
|
const userSetFollowedFields = (user, me) => {
|
|
|
|
user.following = me && user.followedBy.find(({ id }) => id === me.id)
|
|
|
|
user.followersCount = user.followedBy.length
|
|
|
|
delete user.followedBy
|
|
|
|
}
|
|
|
|
|
2020-11-27 00:48:35 +03:00
|
|
|
// TODO: I extracted this articleInclude and articleSetFavoritedFields to enable
|
|
|
|
// reusing of logic that shapes articles as they come out of the server,
|
|
|
|
// but I wonder if there is a more elegant way - here there are a lot of assumptions,
|
|
|
|
// and it is easy to not use where it should be used or use it in wrong setting.
|
|
|
|
|
|
|
|
const articleInclude = {
|
|
|
|
user: {
|
|
|
|
// TODO: Tricky, if you forget this you could return unwanted fields
|
|
|
|
// like hashed password!
|
|
|
|
// It would be cool if we had some protection against making this mistake easily.
|
|
|
|
select: userPublicSelection
|
|
|
|
},
|
2020-11-27 16:25:47 +03:00
|
|
|
tags: true,
|
2020-11-27 00:48:35 +03:00
|
|
|
favoritedBy: {
|
|
|
|
select: {
|
|
|
|
// TODO: Tricky, if I forgot this select here, sensitive data could leak out (hashed password).
|
|
|
|
username: true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const articleSetFavoritedFields = (article, user) => {
|
|
|
|
article.favorited = user && article.favoritedBy.find(f => f.username === user.username)
|
|
|
|
article.favoritesCount = article.favoritedBy.length
|
|
|
|
delete article.favoritedBy
|
|
|
|
}
|
|
|
|
|
|
|
|
const getArticles = async ({ where }, context) => {
|
2020-11-20 20:22:49 +03:00
|
|
|
// TODO: Do some error handling?
|
|
|
|
const articles = await context.entities.Article.findMany({
|
2020-11-27 00:48:35 +03:00
|
|
|
where,
|
|
|
|
include: articleInclude
|
2020-11-20 20:22:49 +03:00
|
|
|
})
|
2020-11-27 00:48:35 +03:00
|
|
|
|
|
|
|
for (const article of articles) {
|
|
|
|
articleSetFavoritedFields(article, context.user)
|
|
|
|
}
|
|
|
|
|
2020-11-20 20:22:49 +03:00
|
|
|
return articles
|
|
|
|
}
|
|
|
|
|
2020-11-27 00:48:35 +03:00
|
|
|
export const getArticlesByUser = async ({ username }, context) => {
|
|
|
|
return await getArticles({ where: { user: { username } } }, context)
|
|
|
|
}
|
|
|
|
|
|
|
|
export const getFavoritedArticles = async (args, context) => {
|
|
|
|
if (!context.user) { throw new HttpError(403) }
|
|
|
|
return await getArticles({
|
|
|
|
where: { favoritedBy: { some: { username: context.user.username } } },
|
|
|
|
}, context)
|
|
|
|
}
|
|
|
|
|
2020-11-27 20:49:54 +03:00
|
|
|
export const getFollowedArticles = async (_args, context) => {
|
|
|
|
if (!context.user) { throw new HttpError(403) }
|
|
|
|
|
|
|
|
const followedUsersIds = (await context.entities.User.findUnique({
|
|
|
|
where: { id: context.user.id },
|
|
|
|
include: { following: { select: { id: true } } }
|
|
|
|
})).following.map(({ id }) => id)
|
|
|
|
|
|
|
|
return await getArticles({ where: { user: { id: { in: followedUsersIds } } } }, context)
|
|
|
|
}
|
|
|
|
|
|
|
|
export const getAllArticles = async (_args, context) => {
|
|
|
|
return await getArticles({}, context)
|
|
|
|
}
|
|
|
|
|
2020-11-24 23:10:26 +03:00
|
|
|
export const getArticle = async ({ slug }, context) => {
|
2020-11-20 20:22:49 +03:00
|
|
|
// TODO: Do some error handling?
|
2020-11-27 00:48:35 +03:00
|
|
|
const article = await context.entities.Article.findUnique({
|
|
|
|
where: { slug },
|
|
|
|
include: articleInclude
|
|
|
|
})
|
|
|
|
articleSetFavoritedFields(article, context.user)
|
2020-11-20 20:22:49 +03:00
|
|
|
return article
|
|
|
|
}
|
2020-11-25 00:57:14 +03:00
|
|
|
|
|
|
|
export const getArticleComments = async ({ slug }, context) => {
|
|
|
|
// TODO: Do some error handling?
|
|
|
|
const comments = await context.entities.Comment.findMany({
|
|
|
|
where: { article: { slug } },
|
|
|
|
include: {
|
|
|
|
user: {
|
|
|
|
// TODO: Tricky, if you forget this you could return unwanted fields
|
|
|
|
// like hashed password!
|
|
|
|
// It would be cool if we had some protection against making this mistake easily.
|
|
|
|
select: userPublicSelection
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
return comments
|
|
|
|
}
|