/**
* Copyright © 2014 Instituto Superior Técnico
*
* This file is part of FenixEdu CMS.
*
* FenixEdu CMS 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 3 of the License, or
* (at your option) any later version.
*
* FenixEdu CMS 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 FenixEdu CMS. If not, see <http://www.gnu.org/licenses/>.
*/
package org.fenixedu.cms.ui;
import static org.fenixedu.cms.domain.PermissionEvaluation.ensureCanDoThis;
import static org.fenixedu.cms.ui.SearchUtils.searchPosts;
import java.util.Collection;
import java.util.Optional;
import java.util.stream.Collectors;
import org.fenixedu.bennu.core.security.Authenticate;
import org.fenixedu.bennu.spring.portal.BennuSpringController;
import org.fenixedu.cms.domain.Category;
import org.fenixedu.cms.domain.PermissionEvaluation;
import org.fenixedu.cms.domain.PermissionsArray.Permission;
import org.fenixedu.cms.domain.Post;
import org.fenixedu.cms.domain.PostFile;
import org.fenixedu.cms.domain.PostMetadata;
import org.fenixedu.cms.domain.Site;
import org.fenixedu.cms.domain.SiteActivity;
import org.fenixedu.commons.i18n.LocalizedString;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.view.RedirectView;
import com.google.common.base.Strings;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import pt.ist.fenixframework.Atomic;
import pt.ist.fenixframework.FenixFramework;
@BennuSpringController(AdminSites.class)
@RequestMapping("/cms/posts")
public class AdminPosts {
private static final int PER_PAGE = 10;
private static final String JSON = "application/json;charset=utf-8";
private static final JsonParser JSON_PARSER = new JsonParser();
@Autowired
AdminPostsService service;
@RequestMapping(value = "{slug}", method = RequestMethod.GET)
public String posts(Model model, @PathVariable String slug,
@RequestParam(required = false, defaultValue = "1") int page,
@RequestParam(required = false) String query, @RequestParam(required = false) String category,
@RequestParam(required = false, defaultValue = "false") boolean showAll) {
Site site = Site.fromSlug(slug);
ensureCanDoThis(site,Permission.SEE_POSTS);
Collection<Post> posts = site.getPostSet();
if (!Strings.isNullOrEmpty(category)) {
Category cat = site.categoryForSlug(category);
posts = cat.getPostsSet();
model.addAttribute("category", cat);
}
if(!showAll) {
posts = posts.stream().filter(post -> !post.isStaticPost()).collect(Collectors.toList());
}
if (!Strings.isNullOrEmpty(query)) {
posts = searchPosts(posts, query);
}
SearchUtils.Partition<Post> partition = new SearchUtils.Partition<>(posts, Post.CREATION_DATE_COMPARATOR, PER_PAGE, page);
model.addAttribute("site", site);
model.addAttribute("query", query);
model.addAttribute("partition", partition);
model.addAttribute("posts", partition.getItems());
return "fenixedu-cms/posts";
}
@RequestMapping(value = "{slugSite}/{slugPost}/data", method = RequestMethod.GET, produces = JSON)
public @ResponseBody String data(@PathVariable String slugSite, @PathVariable String slugPost) {
Site s = Site.fromSlug(slugSite);
Post post = s.postForSlug(slugPost);
ensureCanEditPost(post);
JsonObject data = new JsonObject();
data.add("post", service.serializePost(post));
return data.toString();
}
@RequestMapping(value = "{slug}/create", method = RequestMethod.POST)
public RedirectView createPost(@PathVariable(value = "slug") String slug, @RequestParam LocalizedString name) {
Site s = Site.fromSlug(slug);
Post post = createPost(s, name);
return new RedirectView("/cms/posts/" + s.getSlug() + "/" + post.getSlug() + "/edit", true);
}
@RequestMapping(value = "{siteSlug}/{postSlug}/edit", method = RequestMethod.GET)
public String viewEditPost(Model model, @PathVariable String siteSlug, @PathVariable String postSlug) {
Site site = Site.fromSlug(siteSlug);
Post post = site.postForSlug(postSlug);
ensureCanEditPost(post);
model.addAttribute("site", site);
model.addAttribute("post", post);
return "fenixedu-cms/editPost";
}
@RequestMapping(value = "{slugSite}/{slugPost}/edit", method = RequestMethod.POST, consumes = JSON, produces = JSON)
public @ResponseBody String edit(@PathVariable String slugSite, @PathVariable String slugPost, HttpEntity<String> httpEntity) {
JsonObject postJson = JSON_PARSER.parse(httpEntity.getBody()).getAsJsonObject();
Site site = Site.fromSlug(slugSite);
Post post = site.postForSlug(slugPost);
ensureCanEditPost(post);
service.processPostChanges(site, post, postJson);
return data(site.getSlug(), post.getSlug());
}
@RequestMapping(value = "{slugSite}/{slugPost}/delete", method = RequestMethod.POST)
public RedirectView delete(@PathVariable String slugSite, @PathVariable String slugPost) {
FenixFramework.atomic(() -> {
Site s = Site.fromSlug(slugSite);
Post post = s.postForSlug(slugPost);
ensureCanEditPost(post);
ensureCanDoThis(s, Permission.DELETE_POSTS);
if(post.isVisible()) {
ensureCanDoThis(s, Permission.DELETE_POSTS_PUBLISHED);
}
if(!Authenticate.getUser().equals(post.getCreatedBy())) {
ensureCanDoThis(s, Permission.DELETE_OTHERS_POSTS);
}
SiteActivity.deletedPost(post, Site.fromSlug(slugSite), Authenticate.getUser());
post.delete();
});
return new RedirectView("/cms/posts/" + slugSite + "", true);
}
@RequestMapping(value = "{slugSite}/{slugPost}/files", method = RequestMethod.POST, produces = JSON)
public @ResponseBody String addFile(@PathVariable String slugSite, @PathVariable String slugPost,
@RequestParam String name, @RequestParam boolean embedded, @RequestParam MultipartFile file) {
Site s = Site.fromSlug(slugSite);
Post p = s.postForSlug(slugPost);
ensureCanEditPost(p);
PostFile postFile = service.createFile(p, name, embedded, p.getCanViewGroup(), file);
return service.serializePostFile(postFile).toString();
}
@RequestMapping(value = "{slugSite}/{slugPost}/metadata", method = RequestMethod.GET)
public String viewEditMetadata(Model model, @PathVariable String slugSite, @PathVariable String slugPost) {
Site s = Site.fromSlug(slugSite);
Post post = s.postForSlug(slugPost);
ensureCanEditPost(post);
PermissionEvaluation.ensureCanDoThis(s, Permission.SEE_METADATA, Permission.EDIT_METADATA);
model.addAttribute("site", s);
model.addAttribute("post", post);
model.addAttribute("metadata", Optional.ofNullable(post.getMetadata()).map(PostMetadata::json).map(
JsonElement::toString).orElseGet(()->new JsonObject().toString()));
return "fenixedu-cms/editMetadata";
}
@RequestMapping(value = "{slugSite}/{slugPost}/metadata", method = RequestMethod.POST)
public RedirectView editMetadata(@PathVariable String slugSite,
@PathVariable String slugPost,
@RequestParam String metadata) {
Site s = Site.fromSlug(slugSite);
Post post = s.postForSlug(slugPost);
FenixFramework.atomic(()-> {
ensureCanEditPost(post);
PermissionEvaluation.ensureCanDoThis(s, Permission.SEE_METADATA, Permission.EDIT_METADATA);
post.setMetadata(PostMetadata.internalize(metadata));
});
SiteActivity.editedPost(post, Authenticate.getUser());
return new RedirectView("/cms/posts/" + s.getSlug() + "/" + post.getSlug() + "/metadata", true);
}
public static void ensureCanEditPost(Post post) {
PermissionEvaluation.ensureCanDoThis(post.getSite(), Permission.EDIT_POSTS);
if(!Authenticate.getUser().equals(post.getCreatedBy())) {
PermissionEvaluation.ensureCanDoThis(post.getSite(), Permission.EDIT_OTHERS_POSTS);
}
if(post.isVisible()) {
PermissionEvaluation.ensureCanDoThis(post.getSite(), Permission.EDIT_POSTS_PUBLISHED);
}
}
@Atomic(mode = Atomic.TxMode.WRITE)
private Post createPost(Site site, LocalizedString name) {
PermissionEvaluation.ensureCanDoThis(site, Permission.CREATE_POST, Permission.EDIT_POSTS);
Post post = service.createPost(site, name);
SiteActivity.createdPost(post, Authenticate.getUser());
return post;
}
}