2013-03-31 12:36:48 -06:00
|
|
|
package lila.forum
|
|
|
|
|
2013-05-24 10:27:42 -06:00
|
|
|
import actorApi._
|
2019-11-26 14:44:08 -07:00
|
|
|
import lila.common.Bus
|
2013-03-31 12:36:48 -06:00
|
|
|
import lila.common.paginator._
|
2020-04-03 07:49:08 -06:00
|
|
|
import lila.common.String.noShouting
|
2016-04-01 11:50:57 -06:00
|
|
|
import lila.db.dsl._
|
2013-05-24 10:27:42 -06:00
|
|
|
import lila.db.paginator._
|
2019-12-13 07:30:20 -07:00
|
|
|
import lila.hub.actorApi.timeline.{ ForumPost, Propagate }
|
2014-02-17 02:12:19 -07:00
|
|
|
import lila.security.{ Granter => MasterGranter }
|
2020-08-02 07:08:44 -06:00
|
|
|
import lila.user.User
|
2013-03-31 12:36:48 -06:00
|
|
|
|
2019-12-13 07:30:20 -07:00
|
|
|
final private[forum] class TopicApi(
|
2019-12-05 14:51:18 -07:00
|
|
|
env: Env,
|
2019-12-02 21:07:07 -07:00
|
|
|
indexer: lila.hub.actors.ForumSearch,
|
|
|
|
maxPerPage: lila.common.config.MaxPerPage,
|
2013-05-24 10:27:42 -06:00
|
|
|
modLog: lila.mod.ModlogApi,
|
2018-10-14 02:42:08 -06:00
|
|
|
spam: lila.security.Spam,
|
2020-08-02 06:59:14 -06:00
|
|
|
promotion: lila.security.PromotionApi,
|
2019-12-02 21:07:07 -07:00
|
|
|
timeline: lila.hub.actors.Timeline,
|
|
|
|
shutup: lila.hub.actors.Shutup,
|
2020-08-07 09:51:07 -06:00
|
|
|
detectLanguage: DetectLanguage
|
2019-12-13 18:17:43 -07:00
|
|
|
)(implicit ec: scala.concurrent.ExecutionContext) {
|
2013-03-31 12:36:48 -06:00
|
|
|
|
2016-04-01 11:50:57 -06:00
|
|
|
import BSONHandlers._
|
|
|
|
|
2019-12-13 07:30:20 -07:00
|
|
|
def show(
|
|
|
|
categSlug: String,
|
|
|
|
slug: String,
|
|
|
|
page: Int,
|
2020-01-29 17:57:34 -07:00
|
|
|
forUser: Option[User]
|
2019-12-13 07:30:20 -07:00
|
|
|
): Fu[Option[(Categ, Topic, Paginator[Post])]] =
|
2013-04-01 07:11:13 -06:00
|
|
|
for {
|
2019-12-13 18:17:43 -07:00
|
|
|
data <- env.categRepo bySlug categSlug flatMap {
|
|
|
|
_ ?? { categ =>
|
2020-01-29 17:57:34 -07:00
|
|
|
env.topicRepo.forUser(forUser).byTree(categSlug, slug) dmap {
|
2019-12-13 18:17:43 -07:00
|
|
|
_ map (categ -> _)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-11-28 11:20:59 -07:00
|
|
|
res <- data ?? {
|
2016-03-10 11:53:15 -07:00
|
|
|
case (categ, topic) =>
|
2019-12-10 14:01:18 -07:00
|
|
|
lila.mon.forum.topic.view.increment()
|
2019-12-05 14:51:18 -07:00
|
|
|
env.topicRepo incViews topic
|
2020-01-29 17:57:34 -07:00
|
|
|
env.postApi.paginator(topic, page, forUser) map { (categ, topic, _).some }
|
2013-04-01 07:11:13 -06:00
|
|
|
}
|
|
|
|
} yield res
|
2013-03-31 12:36:48 -06:00
|
|
|
|
2013-04-01 07:11:13 -06:00
|
|
|
def makeTopic(
|
2019-12-13 07:30:20 -07:00
|
|
|
categ: Categ,
|
2020-08-21 14:40:37 -06:00
|
|
|
data: ForumForm.TopicData,
|
2020-01-29 17:57:34 -07:00
|
|
|
me: User
|
2020-08-02 07:08:44 -06:00
|
|
|
): Fu[Topic] =
|
2019-12-05 14:51:18 -07:00
|
|
|
env.topicRepo.nextSlug(categ, data.name) zip detectLanguage(data.post.text) flatMap {
|
2014-02-26 15:05:15 -07:00
|
|
|
case (slug, lang) =>
|
|
|
|
val topic = Topic.make(
|
|
|
|
categId = categ.slug,
|
|
|
|
slug = slug,
|
2020-04-03 07:49:08 -06:00
|
|
|
name = noShouting(data.name),
|
2020-01-29 17:57:34 -07:00
|
|
|
userId = me.id,
|
|
|
|
troll = me.marks.troll,
|
2017-10-07 12:26:21 -06:00
|
|
|
hidden = categ.quiet || data.looksLikeVenting
|
2017-02-14 08:34:07 -07:00
|
|
|
)
|
2014-02-26 15:05:15 -07:00
|
|
|
val post = Post.make(
|
|
|
|
topicId = topic.id,
|
2017-08-21 14:39:01 -06:00
|
|
|
author = none,
|
2020-08-02 07:08:44 -06:00
|
|
|
userId = me.id,
|
|
|
|
troll = me.marks.troll,
|
2014-03-12 14:33:12 -06:00
|
|
|
hidden = topic.hidden,
|
2018-10-14 02:42:08 -06:00
|
|
|
text = spam.replace(data.post.text),
|
2014-02-26 15:05:15 -07:00
|
|
|
lang = lang map (_.language),
|
|
|
|
number = 1,
|
2017-07-09 02:35:32 -06:00
|
|
|
categId = categ.id,
|
2020-08-02 07:08:44 -06:00
|
|
|
modIcon = (~data.post.modIcon && MasterGranter(_.PublicMod)(me)).option(true)
|
2017-02-14 08:34:07 -07:00
|
|
|
)
|
2019-12-05 14:51:18 -07:00
|
|
|
env.postRepo.coll.insert.one(post) >>
|
|
|
|
env.topicRepo.coll.insert.one(topic withPost post) >>
|
2020-08-18 07:37:09 -06:00
|
|
|
env.categRepo.coll.update.one($id(categ.id), categ.withPost(topic, post)) >>- {
|
2020-08-16 07:06:40 -06:00
|
|
|
!categ.quiet ?? (indexer ! InsertPost(post))
|
|
|
|
!categ.quiet ?? env.recent.invalidate()
|
2020-08-02 07:08:44 -06:00
|
|
|
promotion.save(me, post.text)
|
|
|
|
shutup ! {
|
2018-07-20 03:41:46 -06:00
|
|
|
val text = s"${topic.name} ${post.text}"
|
2020-08-02 07:08:44 -06:00
|
|
|
if (post.isTeam) lila.hub.actorApi.shutup.RecordTeamForumMessage(me.id, text)
|
|
|
|
else lila.hub.actorApi.shutup.RecordPublicForumMessage(me.id, text)
|
2019-12-13 07:30:20 -07:00
|
|
|
}
|
2020-08-02 07:08:44 -06:00
|
|
|
if (!post.troll && !categ.quiet)
|
|
|
|
timeline ! Propagate(ForumPost(me.id, topic.id.some, topic.name, post.id)).toFollowersOf(me.id)
|
2019-12-13 07:30:20 -07:00
|
|
|
lila.mon.forum.post.create.increment()
|
|
|
|
env.mentionNotifier.notifyMentionedUsers(post, topic)
|
|
|
|
Bus.publish(actorApi.CreatePost(post), "forumPost")
|
|
|
|
} inject topic
|
2013-04-01 07:11:13 -06:00
|
|
|
}
|
2013-03-31 12:36:48 -06:00
|
|
|
|
2018-03-10 21:27:44 -07:00
|
|
|
def makeBlogDiscuss(categ: Categ, slug: String, name: String, url: String): Funit = {
|
|
|
|
val topic = Topic.make(
|
|
|
|
categId = categ.slug,
|
|
|
|
slug = slug,
|
|
|
|
name = name,
|
|
|
|
troll = false,
|
2020-01-29 17:57:34 -07:00
|
|
|
userId = User.lichessId,
|
2018-03-10 21:27:44 -07:00
|
|
|
hidden = false
|
|
|
|
)
|
|
|
|
val post = Post.make(
|
|
|
|
topicId = topic.id,
|
|
|
|
author = none,
|
2020-08-02 07:08:44 -06:00
|
|
|
userId = User.lichessId,
|
2018-03-10 21:27:44 -07:00
|
|
|
troll = false,
|
|
|
|
hidden = false,
|
|
|
|
text = s"Comments on $url",
|
|
|
|
lang = none,
|
|
|
|
number = 1,
|
|
|
|
categId = categ.id,
|
|
|
|
modIcon = true.some
|
|
|
|
)
|
2019-12-05 14:51:18 -07:00
|
|
|
env.postRepo.coll.insert.one(post) >>
|
|
|
|
env.topicRepo.coll.insert.one(topic withPost post) >>
|
2020-08-18 07:37:09 -06:00
|
|
|
env.categRepo.coll.update.one($id(categ.id), categ.withPost(topic, post)) >>-
|
2018-03-10 21:27:44 -07:00
|
|
|
(indexer ! InsertPost(post)) >>-
|
2020-07-07 02:34:48 -06:00
|
|
|
env.recent.invalidate() >>-
|
2019-12-08 10:35:26 -07:00
|
|
|
Bus.publish(actorApi.CreatePost(post), "forumPost") void
|
2018-03-10 21:27:44 -07:00
|
|
|
}
|
|
|
|
|
2020-01-29 17:57:34 -07:00
|
|
|
def paginator(categ: Categ, page: Int, forUser: Option[User]): Fu[Paginator[TopicView]] = {
|
2016-07-18 03:44:05 -06:00
|
|
|
val adapter = new Adapter[Topic](
|
2019-12-05 14:51:18 -07:00
|
|
|
collection = env.topicRepo.coll,
|
2020-01-29 17:57:34 -07:00
|
|
|
selector = env.topicRepo.forUser(forUser) byCategNotStickyQuery categ,
|
2019-12-02 21:07:07 -07:00
|
|
|
projection = none,
|
2016-04-01 22:01:52 -06:00
|
|
|
sort = $sort.updatedDesc
|
2017-07-08 02:44:43 -06:00
|
|
|
) mapFutureList { topics =>
|
2020-01-29 17:57:34 -07:00
|
|
|
env.postRepo.coll.optionsByOrderedIds[Post, String](topics.map(_ lastPostId forUser))(_.id) map {
|
|
|
|
posts =>
|
|
|
|
topics zip posts map {
|
|
|
|
case topic ~ post => TopicView(categ, topic, post, env.postApi lastPageOf topic, forUser)
|
|
|
|
}
|
2013-04-01 07:11:13 -06:00
|
|
|
}
|
2016-07-18 03:44:05 -06:00
|
|
|
}
|
|
|
|
val cachedAdapter =
|
|
|
|
if (categ.isTeam) adapter
|
|
|
|
else new CachedAdapter(adapter, nbResults = fuccess(1000))
|
|
|
|
Paginator(
|
|
|
|
adapter = cachedAdapter,
|
|
|
|
currentPage = page,
|
2017-02-14 08:34:07 -07:00
|
|
|
maxPerPage = maxPerPage
|
|
|
|
)
|
2016-07-18 03:44:05 -06:00
|
|
|
}
|
2013-03-31 12:36:48 -06:00
|
|
|
|
2020-01-29 17:57:34 -07:00
|
|
|
def getSticky(categ: Categ, forUser: Option[User]): Fu[List[TopicView]] =
|
2019-12-05 14:51:18 -07:00
|
|
|
env.topicRepo.stickyByCateg(categ) flatMap { topics =>
|
2019-11-30 19:29:40 -07:00
|
|
|
topics.map { topic =>
|
2020-01-29 17:57:34 -07:00
|
|
|
env.postRepo.coll.byId[Post](topic lastPostId forUser) map { post =>
|
|
|
|
TopicView(categ, topic, post, env.postApi lastPageOf topic, forUser)
|
2019-11-30 19:29:40 -07:00
|
|
|
}
|
|
|
|
}.sequenceFu
|
2017-07-07 08:27:13 -06:00
|
|
|
}
|
|
|
|
|
2013-03-31 12:36:48 -06:00
|
|
|
def delete(categ: Categ, topic: Topic): Funit =
|
2019-12-05 14:51:18 -07:00
|
|
|
env.postRepo.idsByTopicId(topic.id) flatMap { postIds =>
|
|
|
|
(env.postRepo removeByTopic topic.id zip env.topicRepo.coll.delete.one($id(topic.id))) >>
|
|
|
|
(env.categApi denormalize categ) >>-
|
2017-01-26 16:23:43 -07:00
|
|
|
(indexer ! RemovePosts(postIds)) >>-
|
2020-07-07 02:34:48 -06:00
|
|
|
env.recent.invalidate()
|
2016-01-06 21:21:50 -07:00
|
|
|
}
|
2013-03-31 12:36:48 -06:00
|
|
|
|
2013-05-16 20:04:26 -06:00
|
|
|
def toggleClose(categ: Categ, topic: Topic, mod: User): Funit =
|
2019-12-05 14:51:18 -07:00
|
|
|
env.topicRepo.close(topic.id, topic.open) >> {
|
2013-05-30 01:17:05 -06:00
|
|
|
MasterGranter(_.ModerateForum)(mod) ??
|
2016-04-01 22:01:52 -06:00
|
|
|
modLog.toggleCloseTopic(mod.id, categ.name, topic.name, topic.open)
|
2013-05-30 01:17:05 -06:00
|
|
|
}
|
2013-05-14 23:48:56 -06:00
|
|
|
|
2014-03-12 14:33:12 -06:00
|
|
|
def toggleHide(categ: Categ, topic: Topic, mod: User): Funit =
|
2019-12-05 14:51:18 -07:00
|
|
|
env.topicRepo.hide(topic.id, topic.visibleOnHome) >> {
|
2014-03-12 14:33:12 -06:00
|
|
|
MasterGranter(_.ModerateForum)(mod) ?? {
|
2019-12-05 14:51:18 -07:00
|
|
|
env.postRepo.hideByTopic(topic.id, topic.visibleOnHome) >>
|
2016-04-01 22:01:52 -06:00
|
|
|
modLog.toggleHideTopic(mod.id, categ.name, topic.name, topic.visibleOnHome)
|
2020-07-07 02:34:48 -06:00
|
|
|
} >>- env.recent.invalidate()
|
2014-03-12 14:33:12 -06:00
|
|
|
}
|
|
|
|
|
2017-07-07 08:27:13 -06:00
|
|
|
def toggleSticky(categ: Categ, topic: Topic, mod: User): Funit =
|
2019-12-05 14:51:18 -07:00
|
|
|
env.topicRepo.sticky(topic.id, !topic.isSticky) >> {
|
2017-07-07 08:27:13 -06:00
|
|
|
MasterGranter(_.ModerateForum)(mod) ??
|
2017-07-08 02:05:52 -06:00
|
|
|
modLog.toggleStickyTopic(mod.id, categ.name, topic.name, topic.isSticky)
|
2017-07-07 08:27:13 -06:00
|
|
|
}
|
|
|
|
|
2019-12-13 07:30:20 -07:00
|
|
|
def denormalize(topic: Topic): Funit =
|
|
|
|
for {
|
|
|
|
nbPosts <- env.postRepo countByTopic topic
|
|
|
|
lastPost <- env.postRepo lastByTopic topic
|
2020-01-29 17:57:34 -07:00
|
|
|
nbPostsTroll <- env.postRepo.unsafe countByTopic topic
|
|
|
|
lastPostTroll <- env.postRepo.unsafe lastByTopic topic
|
2020-05-05 22:11:15 -06:00
|
|
|
_ <-
|
|
|
|
env.topicRepo.coll.update
|
|
|
|
.one(
|
|
|
|
$id(topic.id),
|
|
|
|
topic.copy(
|
|
|
|
nbPosts = nbPosts,
|
|
|
|
lastPostId = lastPost ?? (_.id),
|
|
|
|
updatedAt = lastPost.fold(topic.updatedAt)(_.createdAt),
|
|
|
|
nbPostsTroll = nbPostsTroll,
|
|
|
|
lastPostIdTroll = lastPostTroll ?? (_.id),
|
|
|
|
updatedAtTroll = lastPostTroll.fold(topic.updatedAtTroll)(_.createdAt)
|
|
|
|
)
|
2019-12-13 07:30:20 -07:00
|
|
|
)
|
2020-05-05 22:11:15 -06:00
|
|
|
.void
|
2019-12-13 07:30:20 -07:00
|
|
|
} yield ()
|
2013-03-31 12:36:48 -06:00
|
|
|
}
|