package org.iatoki.judgels.raguel.forum;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.apache.commons.lang3.EnumUtils;
import org.iatoki.judgels.api.jophiel.JophielClientAPI;
import org.iatoki.judgels.api.jophiel.JophielPublicAPI;
import org.iatoki.judgels.jophiel.avatar.BaseAvatarCacheService;
import org.iatoki.judgels.jophiel.activity.UserActivityMessageService;
import org.iatoki.judgels.play.Page;
import org.iatoki.judgels.play.jid.BaseJidCacheService;
import org.iatoki.judgels.play.template.HtmlTemplate;
import org.iatoki.judgels.raguel.controllers.securities.Authenticated;
import org.iatoki.judgels.raguel.controllers.securities.Authorized;
import org.iatoki.judgels.raguel.controllers.securities.GuestView;
import org.iatoki.judgels.raguel.controllers.securities.HasRole;
import org.iatoki.judgels.raguel.controllers.securities.LoggedIn;
import org.iatoki.judgels.raguel.forum.html.createForumView;
import org.iatoki.judgels.raguel.forum.html.editForumGeneralView;
import org.iatoki.judgels.raguel.forum.html.editForumSpecificView;
import org.iatoki.judgels.raguel.forum.html.listBaseForumsView;
import org.iatoki.judgels.raguel.forum.html.listBaseForumsWithStatusView;
import org.iatoki.judgels.raguel.forum.html.listForumsAndThreadsView;
import org.iatoki.judgels.raguel.forum.html.listForumsAndThreadsWithStatusView;
import org.iatoki.judgels.raguel.forum.html.listForumsView;
import org.iatoki.judgels.raguel.forum.html.listForumsWithStatusView;
import org.iatoki.judgels.raguel.forum.member.ForumMemberService;
import org.iatoki.judgels.raguel.forum.module.ForumModule;
import org.iatoki.judgels.raguel.forum.module.ForumModuleService;
import org.iatoki.judgels.raguel.forum.module.ForumModuleUtils;
import org.iatoki.judgels.raguel.forum.module.ForumModules;
import org.iatoki.judgels.raguel.forum.module.InheritedForumModules;
import org.iatoki.judgels.raguel.forum.module.html.listModulesView;
import org.iatoki.judgels.raguel.forum.thread.ForumThreadService;
import org.iatoki.judgels.raguel.forum.thread.ForumThreadWithStatistics;
import org.iatoki.judgels.raguel.forum.thread.ForumThreadWithStatisticsAndStatus;
import play.data.Form;
import play.db.jpa.Transactional;
import play.filters.csrf.AddCSRFToken;
import play.filters.csrf.RequireCSRFCheck;
import play.i18n.Messages;
import play.mvc.Result;
import play.twirl.api.Html;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Singleton
public final class ForumController extends AbstractForumController {
private static final long PAGE_SIZE = 20;
private final ForumModuleService forumModuleService;
private final ForumService forumService;
private final ForumThreadService forumThreadService;
@Inject
public ForumController(BaseJidCacheService jidCacheService, BaseAvatarCacheService avatarCacheService, JophielClientAPI jophielClientAPI, JophielPublicAPI jophielPublicAPI, UserActivityMessageService userActivityMessageService, ForumMemberService forumMemberService, ForumModuleService forumModuleService, ForumService forumService, ForumThreadService forumThreadService) {
super(jidCacheService, avatarCacheService, jophielClientAPI, jophielPublicAPI, userActivityMessageService, forumMemberService);
this.forumModuleService = forumModuleService;
this.forumService = forumService;
this.forumThreadService = forumThreadService;
}
@Authenticated(value = {LoggedIn.class, HasRole.class})
@Authorized(value = {"moderator", "admin"})
public Result jumpToMembers(long forumId) {
return redirect(org.iatoki.judgels.raguel.forum.member.routes.ForumMemberController.viewMembers(forumId));
}
@Authenticated(value = GuestView.class)
@Transactional(readOnly = true)
public Result index() throws ForumNotFoundException {
return viewForums(0);
}
@Authenticated(value = GuestView.class)
@Transactional(readOnly = true)
public Result viewForums(long forumId) throws ForumNotFoundException {
return showListForumsThreads(forumId, 0, "timeUpdate", "desc", "");
}
@Authenticated(value = GuestView.class)
@Transactional(readOnly = true)
public Result listForumsThreads(long forumId, long pageIndex, String orderBy, String orderDir, String filterString) throws ForumNotFoundException {
return showListForumsThreads(forumId, pageIndex, orderBy, orderDir, filterString);
}
@Authenticated(value = {LoggedIn.class, HasRole.class})
@Authorized(value = {"moderator", "admin"})
@Transactional(readOnly = true)
@AddCSRFToken
public Result createForum(long parentId) throws ForumNotFoundException {
ForumUpsertForm forumUpsertData = new ForumUpsertForm();
if (parentId != 0) {
Forum forum = forumService.findForumById(parentId);
forumUpsertData.parentJid = forum.getJid();
}
Form<ForumUpsertForm> forumUpsertForm = Form.form(ForumUpsertForm.class).fill(forumUpsertData);
return showCreateForum(parentId, forumUpsertForm);
}
@Authenticated(value = {LoggedIn.class, HasRole.class})
@Authorized(value = {"moderator", "admin"})
@Transactional
@RequireCSRFCheck
public Result postCreateForum() {
Form<ForumUpsertForm> forumUpsertForm = Form.form(ForumUpsertForm.class).bindFromRequest();
if (formHasErrors(forumUpsertForm)) {
return showCreateForum(0, forumUpsertForm);
}
ForumUpsertForm forumUpsertData = forumUpsertForm.get();
Forum forum = null;
if (forumService.forumExistsByJid(forumUpsertData.parentJid)) {
forum = forumService.findForumByJid(forumUpsertData.parentJid);
}
forumService.createForum(forum, forumUpsertData.name, forumUpsertData.description, getCurrentUserJid(), getCurrentUserIpAddress());
return redirect(routes.ForumController.index());
}
@Authenticated(value = {LoggedIn.class, HasRole.class})
@Authorized(value = {"moderator", "admin"})
@Transactional(readOnly = true)
@AddCSRFToken
public Result editForumGeneralConfig(long forumId) throws ForumNotFoundException {
Forum forum = forumService.findForumById(forumId);
ForumUpsertForm forumUpsertData = new ForumUpsertForm();
if (forum.getParentForum() != null) {
forumUpsertData.parentJid = forum.getParentForum().getJid();
}
forumUpsertData.name = forum.getName();
forumUpsertData.description = forum.getDescription();
Form<ForumUpsertForm> forumUpsertForm = Form.form(ForumUpsertForm.class).fill(forumUpsertData);
return showEditForumGeneral(forumUpsertForm, forum);
}
@Authenticated(value = {LoggedIn.class, HasRole.class})
@Authorized(value = {"moderator", "admin"})
@Transactional
@RequireCSRFCheck
public Result postEditForumGeneralConfig(long forumId) throws ForumNotFoundException {
Forum forum = forumService.findForumById(forumId);
Form<ForumUpsertForm> forumUpsertForm = Form.form(ForumUpsertForm.class).bindFromRequest();
if (formHasErrors(forumUpsertForm)) {
return showEditForumGeneral(forumUpsertForm, forum);
}
ForumUpsertForm forumUpsertData = forumUpsertForm.get();
Forum parentForum = null;
if (forumService.forumExistsByJid(forumUpsertData.parentJid)) {
parentForum = forumService.findForumByJid(forumUpsertData.parentJid);
}
forumService.updateForum(forum, parentForum, forumUpsertData.name, forumUpsertData.description, getCurrentUserJid(), getCurrentUserIpAddress());
return redirect(routes.ForumController.index());
}
@Authenticated(value = {LoggedIn.class, HasRole.class})
@Authorized(value = {"moderator", "admin"})
@Transactional(readOnly = true)
public Result editForumModuleConfig(long forumId) throws ForumNotFoundException {
Forum forum = forumService.findForumById(forumId);
return showEditForumModuleConfig(forum);
}
@Authenticated(value = {LoggedIn.class, HasRole.class})
@Authorized(value = {"moderator", "admin"})
@Transactional
public Result enableModule(long forumId, String forumModule) throws ForumNotFoundException {
Forum forum = forumService.findForumById(forumId);
if (!EnumUtils.isValidEnum(ForumModules.class, forumModule)) {
return redirect(routes.ForumController.editForumModuleConfig(forum.getId()));
}
ForumModules forumModuleType = ForumModules.valueOf(forumModule);
if (!ForumModuleUtils.getModuleContradiction(forumModuleType).isEmpty() && forum.getModulesSet().containsAll(ForumModuleUtils.getModuleContradiction(forumModuleType))) {
flashError(Messages.get("forum.module.enable.error.contradiction", ForumModuleUtils.getModuleContradiction(forumModuleType).toString()));
return redirect(routes.ForumController.editForumModuleConfig(forum.getId()));
}
if (!forum.getModulesSet().containsAll(ForumModuleUtils.getModuleDependencies(forumModuleType))) {
flashError(Messages.get("forum.module.enable.error.dependencies", ForumModuleUtils.getModuleDependencies(forumModuleType).toString()));
return redirect(routes.ForumController.editForumModuleConfig(forum.getId()));
}
// error if inherited
if (EnumUtils.isValidEnum(InheritedForumModules.class, forumModule) && (forum.inheritModule(forumModuleType))) {
flashError(Messages.get("forum.module.enable.error.inherited", ForumModuleUtils.getModuleDependencies(forumModuleType).toString()));
return redirect(routes.ForumController.editForumModuleConfig(forum.getId()));
}
forumModuleService.enableModule(forum.getJid(), ForumModules.valueOf(forumModule));
return redirect(routes.ForumController.editForumModuleConfig(forum.getId()));
}
@Authenticated(value = {LoggedIn.class, HasRole.class})
@Authorized(value = {"moderator", "admin"})
@Transactional
public Result disableModule(long forumId, String forumModule) throws ForumNotFoundException {
Forum forum = forumService.findForumById(forumId);
if (!EnumUtils.isValidEnum(ForumModules.class, forumModule)) {
return redirect(routes.ForumController.editForumModuleConfig(forum.getId()));
}
ForumModules forumModuleType = ForumModules.valueOf(forumModule);
if (forum.getModulesSet().containsAll(ForumModuleUtils.getDependedModules(forumModuleType)) && !ForumModuleUtils.getDependedModules(forumModuleType).isEmpty()) {
flashError(Messages.get("forum.module.disable.error.dependencies", ForumModuleUtils.getDependedModules(forumModuleType).toString()));
return redirect(routes.ForumController.editForumModuleConfig(forum.getId()));
}
forumModuleService.disableModule(forum.getJid(), ForumModules.valueOf(forumModule));
return redirect(routes.ForumController.editForumModuleConfig(forum.getId()));
}
@Authenticated(value = {LoggedIn.class, HasRole.class})
@Authorized(value = {"moderator", "admin"})
@Transactional(readOnly = true)
@AddCSRFToken
public Result editForumSpecificConfig(long forumId) throws ForumNotFoundException {
Forum forum = forumService.findForumById(forumId);
ImmutableMap.Builder<ForumModule, Form<?>> moduleFormMapBuilder = ImmutableMap.builder();
for (ForumModule forumModule : forum.getModules()) {
moduleFormMapBuilder.put(forumModule, forumModule.generateConfigForm());
}
return showEditForumSpecificConfig(forum, moduleFormMapBuilder.build());
}
@Authenticated(value = {LoggedIn.class, HasRole.class})
@Authorized(value = {"moderator", "admin"})
@Transactional
@RequireCSRFCheck
public Result postEditForumSpecificConfig(long forumId) throws ForumNotFoundException {
Forum forum = forumService.findForumById(forumId);
boolean checkError = false;
ImmutableMap.Builder<ForumModule, Form<?>> moduleFormMap = ImmutableMap.builder();
ImmutableList.Builder<ForumModule> updatedForumModuleBuilder = ImmutableList.builder();
for (ForumModule forumModule : forum.getModules()) {
Form<?> moduleForm = forumModule.updateModuleByFormFromRequest(request());
moduleFormMap.put(forumModule, moduleForm);
updatedForumModuleBuilder.add(forumModule);
if (formHasErrors(moduleForm)) {
checkError = true;
}
}
if (checkError) {
return showEditForumSpecificConfig(forum, moduleFormMap.build());
}
forumService.updateForumModuleConfiguration(forum.getJid(), updatedForumModuleBuilder.build(), getCurrentUserJid(), getCurrentUserIpAddress());
return redirect(routes.ForumController.editForumSpecificConfig(forum.getId()));
}
private Result showListForumsThreads(long forumId, long pageIndex, String orderBy, String orderDir, String filterString) throws ForumNotFoundException {
Forum currentForum;
Html content;
if (forumId == 0) {
currentForum = null;
content = getBaseForumContent();
} else {
currentForum = forumService.findForumById(forumId);
if (!isCurrentUserModeratorOrAdmin() && !isCurrentUserAllowedToEnterForum(currentForum)) {
long parentForumId;
if (currentForum.getParentForum() != null) {
parentForumId = currentForum.getParentForum().getId();
} else {
parentForumId = 0;
}
return redirect(routes.ForumController.viewForums(parentForumId));
}
content = getNonBaseForumContent(currentForum, pageIndex, orderBy, orderDir, filterString);
}
HtmlTemplate htmlTemplate;
if (currentForum != null) {
htmlTemplate = super.getBaseHtmlTemplate(currentForum);
if (!currentForum.getDescription().isEmpty()) {
htmlTemplate.setDescription(currentForum.getDescription());
}
} else {
htmlTemplate = super.getBaseHtmlTemplate();
if (isCurrentUserModeratorOrAdmin()) {
htmlTemplate.addMainButton(Messages.get("commons.button.new1", Messages.get("forum.text.forum")), routes.ForumController.createForum(0));
}
}
htmlTemplate.setContent(content);
htmlTemplate.setMainTitle(Messages.get("forum.text.forum"));
return renderTemplate(htmlTemplate);
}
private Html getBaseForumContent() {
if (isCurrentUserGuest()) {
List<Forum> childForums = forumService.getAllowedChildForums("", 2);
return listBaseForumsView.render(childForums);
}
List<Forum> childForums;
if (isCurrentUserModeratorOrAdmin()) {
childForums = forumService.getChildForums("", 2);
} else {
childForums = forumService.getAllowedChildForums("", 2);
}
ImmutableMap.Builder<String, List<ForumWithStatus>> mapForumJidToForumsWithStatusBuilder = ImmutableMap.builder();
for (Forum childForum : childForums) {
if (isCurrentUserModeratorOrAdmin()) {
mapForumJidToForumsWithStatusBuilder.put(childForum.getJid(), forumService.getChildForumsWithStatus(childForum.getJid(), getCurrentUserJid(), 2));
} else {
mapForumJidToForumsWithStatusBuilder.put(childForum.getJid(), forumService.getAllowedChildForumsWithStatus(childForum.getJid(), getCurrentUserJid(), 2));
}
}
return listBaseForumsWithStatusView.render(childForums, mapForumJidToForumsWithStatusBuilder.build());
}
private Html getNonBaseForumContent(Forum forum, long pageIndex, String orderBy, String orderDir, String filterString) {
if (isCurrentUserGuest()) {
List<Forum> childForums = forumService.getAllowedChildForums(forum.getJid(), 1);
if (forum.containModule(ForumModules.THREAD)) {
Page<ForumThreadWithStatistics> pageOfForumThreads = forumThreadService.getPageOfForumThreadsWithStatistic(forum, pageIndex, PAGE_SIZE, orderBy, orderDir, filterString);
return listForumsAndThreadsView.render(forum, childForums, pageOfForumThreads, orderBy, orderDir, filterString);
}
return listForumsView.render(forum, childForums);
}
List<ForumWithStatus> childForumsWithStatus;
if (isCurrentUserModeratorOrAdmin()) {
childForumsWithStatus = forumService.getChildForumsWithStatus(forum.getJid(), getCurrentUserJid(), 1);
} else {
childForumsWithStatus = forumService.getAllowedChildForumsWithStatus(forum.getJid(), getCurrentUserJid(), 1);
}
if (forum.containModule(ForumModules.THREAD)) {
Page<ForumThreadWithStatisticsAndStatus> pageOfForumThreads = forumThreadService.getPageOfForumThreadsWithStatisticAndStatus(forum, getCurrentUserJid(), pageIndex, PAGE_SIZE, orderBy, orderDir, filterString);
return listForumsAndThreadsWithStatusView.render(forum, childForumsWithStatus, pageOfForumThreads, orderBy, orderDir, filterString);
}
return listForumsWithStatusView.render(forum, childForumsWithStatus);
}
private Result showCreateForum(long parentId, Form<ForumUpsertForm> forumUpsertForm) {
HtmlTemplate htmlTemplate = super.getBaseHtmlTemplate();
htmlTemplate.setContent(createForumView.render(forumUpsertForm, forumService.getAllForumsForReferences()));
htmlTemplate.setMainTitle(Messages.get("commons.text.new1", Messages.get("forum.text.forum")));
htmlTemplate.markBreadcrumbLocation(Messages.get("commons.text.new"), routes.ForumController.createForum(parentId));
return renderTemplate(htmlTemplate);
}
private Result showEditForumGeneral(Form<ForumUpsertForm> forumUpsertForm, Forum forum) {
HtmlTemplate htmlTemplate = super.getBaseHtmlTemplate();
htmlTemplate.setContent(editForumGeneralView.render(forumUpsertForm, forum.getId(), forumService.getAllForumsForReferences().stream().filter(f -> !f.containsJidInHierarchy(forum.getJid())).collect(Collectors.toList())));
addUpdateView(htmlTemplate, forum);
htmlTemplate.addMainButton(Messages.get("commons.text.view"), routes.ForumController.viewForums(forum.getId()));
htmlTemplate.markBreadcrumbLocation(Messages.get("forum.config.text.general"), routes.ForumController.editForumGeneralConfig(forum.getId()));
return renderTemplate(htmlTemplate);
}
private Result showEditForumModuleConfig(Forum forum) {
HtmlTemplate htmlTemplate = super.getBaseHtmlTemplate();
htmlTemplate.setContent(listModulesView.render(forum));
addUpdateView(htmlTemplate, forum);
htmlTemplate.markBreadcrumbLocation(Messages.get("forum.config.text.specific"), routes.ForumController.editForumModuleConfig(forum.getId()));
return renderTemplate(htmlTemplate);
}
private Result showEditForumSpecificConfig(Forum forum, Map<ForumModule, Form<?>> moduleFormMap) {
HtmlTemplate htmlTemplate = super.getBaseHtmlTemplate();
htmlTemplate.setContent(editForumSpecificView.render(forum, moduleFormMap));
addUpdateView(htmlTemplate, forum);
htmlTemplate.markBreadcrumbLocation(Messages.get("forum.config.text.specific"), routes.ForumController.editForumSpecificConfig(forum.getId()));
return renderTemplate(htmlTemplate);
}
private void addUpdateView(HtmlTemplate htmlTemplate, Forum forum) {
htmlTemplate.addCategoryTab(Messages.get("forum.config.text.general"), routes.ForumController.editForumGeneralConfig(forum.getId()));
htmlTemplate.addCategoryTab(Messages.get("forum.config.text.modules"), routes.ForumController.editForumModuleConfig(forum.getId()));
htmlTemplate.addCategoryTab(Messages.get("forum.config.text.specific"), routes.ForumController.editForumSpecificConfig(forum.getId()));
htmlTemplate.setMainTitle(Messages.get("forum.text.forum1", forum.getName()));
htmlTemplate.markBreadcrumbLocation(Messages.get("commons.text.edit"), routes.ForumController.editForumGeneralConfig(forum.getId()));
}
}