/**
* Copyright (C) 2011 JTalks.org Team
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.jtalks.jcommune.service.transactional;
import org.jtalks.common.service.security.SecurityContextFacade;
import org.jtalks.jcommune.model.dao.TopicDraftDao;
import org.jtalks.jcommune.model.entity.JCUser;
import org.jtalks.jcommune.model.entity.TopicDraft;
import org.jtalks.jcommune.plugin.api.PluginLoader;
import org.jtalks.jcommune.plugin.api.core.Plugin;
import org.jtalks.jcommune.plugin.api.core.TopicPlugin;
import org.jtalks.jcommune.plugin.api.filters.StateFilter;
import org.jtalks.jcommune.plugin.api.filters.TopicTypeFilter;
import org.jtalks.jcommune.plugin.api.filters.TypeFilter;
import org.jtalks.jcommune.plugin.api.service.PluginTopicDraftService;
import org.jtalks.jcommune.service.TopicDraftService;
import org.jtalks.jcommune.service.UserService;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import java.util.List;
/**
* The implementation of TopicDraftService interface.
*
* @author Dmitry S. Dolzhenko
*/
public class TransactionalTopicDraftService implements TopicDraftService, PluginTopicDraftService {
private final UserService userService;
private final TopicDraftDao topicDraftDao;
private final SecurityContextFacade securityContextFacade;
private final PluginLoader pluginLoader;
private final PermissionEvaluator permissionEvaluator;
public TransactionalTopicDraftService(UserService userService,
TopicDraftDao topicDraftDao,
SecurityContextFacade securityContextFacade,
PermissionEvaluator permissionEvaluator,
PluginLoader pluginLoader) {
this.userService = userService;
this.topicDraftDao = topicDraftDao;
this.securityContextFacade = securityContextFacade;
this.permissionEvaluator = permissionEvaluator;
this.pluginLoader = pluginLoader;
}
/**
* {@inheritDoc}
*/
@Override
@PreAuthorize("isAuthenticated()")
public TopicDraft getDraft() {
JCUser user = userService.getCurrentUser();
return topicDraftDao.getForUser(user);
}
/**
* {@inheritDoc}
*/
@Override
@PreAuthorize("( (not #draft.codeReview) and (not #draft.plugable) " +
"and hasPermission(#draft.branchId, 'BRANCH', 'BranchPermission.CREATE_POSTS')) " +
"or (#draft.codeReview " +
"and hasPermission(#draft.branchId, 'BRANCH', 'BranchPermission.CREATE_CODE_REVIEW')) " +
" or #draft.plugable")
public TopicDraft saveOrUpdateDraft(TopicDraft draft) {
assertCreationAllowedForPlugableTopic(draft);
JCUser user = userService.getCurrentUser();
TopicDraft currentDraft = topicDraftDao.getForUser(user);
if (currentDraft == null) {
currentDraft = draft;
currentDraft.setTopicStarter(user);
} else {
currentDraft.setContent(draft.getContent());
currentDraft.setTitle(draft.getTitle());
currentDraft.setBranchId(draft.getBranchId());
currentDraft.setTopicType(draft.getTopicType());
/* When we save draft that does not contain pollTitle and pollItemsValue (e.g. code review),
we should not overwrite already existing values of these fields. */
if (draft.getPollTitle() != null || draft.getPollItemsValue() != null) {
currentDraft.setPollTitle(draft.getPollTitle());
currentDraft.setPollItemsValue(draft.getPollItemsValue());
}
}
currentDraft.updateLastSavedTime();
topicDraftDao.saveOrUpdate(currentDraft);
return currentDraft;
}
/**
* {@inheritDoc}
*/
@Override
@PreAuthorize("isAuthenticated()")
public void deleteDraft() {
JCUser user = userService.getCurrentUser();
topicDraftDao.deleteByUser(user);
}
/**
* Checks for draft of plugable topic if current user is granted to create topics with type.
*
* @param draft draft topic to be checked
* @throws AccessDeniedException if user not granted to create current topic type
* or if type of current topic is unknown
*/
private void assertCreationAllowedForPlugableTopic(TopicDraft draft) {
if (!draft.isPlugable()) {
return;
}
Authentication auth = securityContextFacade.getContext().getAuthentication();
List<Plugin> topicPlugins = pluginLoader.getPlugins(new TypeFilter(TopicPlugin.class),
new StateFilter(Plugin.State.ENABLED), new TopicTypeFilter(draft.getTopicType()));
if (topicPlugins.size() == 0) {
throw new AccessDeniedException("Creating of unknown (" + draft.getTopicType() + ") topic type is forbidden");
} else {
for (Plugin plugin : topicPlugins) {
TopicPlugin topicPlugin = (TopicPlugin) plugin;
if (!permissionEvaluator.hasPermission(auth, draft.getBranchId(),
"BRANCH", topicPlugin.getCreateTopicPermission())) {
throw new AccessDeniedException("Creating of draft topic with type " + draft.getTopicType() + " is forbidden");
}
}
}
}
}