fix for admin api

This commit is contained in:
Athou
2013-04-18 12:50:44 +02:00
parent 9bd825d786
commit af109ccf5c
30 changed files with 1000 additions and 861 deletions

View File

@@ -0,0 +1,21 @@
package com.commafeed.backend.services;
import javax.ejb.Stateless;
import javax.inject.Inject;
import com.commafeed.backend.dao.FeedEntryStatusDAO;
import com.commafeed.backend.model.FeedEntryStatus;
import com.commafeed.backend.model.User;
@Stateless
public class FeedEntryService {
@Inject
FeedEntryStatusDAO feedEntryStatusDAO;
public void markEntry(User user, Long entryId, boolean read) {
FeedEntryStatus status = feedEntryStatusDAO.findById(user, entryId);
status.setRead(read);
feedEntryStatusDAO.update(status);
}
}

View File

@@ -7,6 +7,8 @@ import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import com.commafeed.backend.model.FeedEntry;
import com.commafeed.backend.model.FeedEntryStatus;
import com.wordnik.swagger.annotations.ApiClass;
import com.wordnik.swagger.annotations.ApiProperty;
@@ -16,39 +18,61 @@ import com.wordnik.swagger.annotations.ApiProperty;
@ApiClass("Entry details")
public class Entry implements Serializable {
public static Entry build(FeedEntryStatus status) {
Entry entry = new Entry();
FeedEntry feedEntry = status.getEntry();
entry.setId(String.valueOf(status.getId()));
entry.setTitle(feedEntry.getContent().getTitle());
entry.setContent(feedEntry.getContent().getContent());
entry.setEnclosureUrl(status.getEntry().getContent().getEnclosureUrl());
entry.setEnclosureType(status.getEntry().getContent()
.getEnclosureType());
entry.setDate(feedEntry.getUpdated());
entry.setUrl(feedEntry.getUrl());
entry.setRead(status.isRead());
entry.setFeedName(status.getSubscription().getTitle());
entry.setFeedId(String.valueOf(status.getSubscription().getId()));
entry.setFeedUrl(status.getSubscription().getFeed().getLink());
return entry;
}
@ApiProperty("entry id")
private String id;
@ApiProperty("entry title")
private String title;
@ApiProperty("entry content")
private String content;
@ApiProperty("entry enclosure url, if any")
private String enclosureUrl;
@ApiProperty("entry enclosure mime type, if any")
private String enclosureType;
@ApiProperty("entry publication date")
private Date date;
@ApiProperty("feed id")
private String feedId;
@ApiProperty("feed name")
private String feedName;
@ApiProperty("feed url")
private String feedUrl;
@ApiProperty("entry url")
private String url;
@ApiProperty("read sttaus")
private boolean read;
@ApiProperty("starred status")
private boolean starred;

View File

@@ -1,41 +0,0 @@
package com.commafeed.frontend.model;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
@SuppressWarnings("serial")
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class MarkRequest implements Serializable {
private String type;
private String id;
private boolean read;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public boolean isRead() {
return read;
}
public void setRead(boolean read) {
this.read = read;
}
}

View File

@@ -0,0 +1,40 @@
package com.commafeed.frontend.model.request;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import com.wordnik.swagger.annotations.ApiClass;
import com.wordnik.swagger.annotations.ApiProperty;
@SuppressWarnings("serial")
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@ApiClass("Mark Request")
public class CollapseRequest implements Serializable {
@ApiProperty(value = "category id", required = true)
private Long id;
@ApiProperty(value = "collapse", required = true)
private boolean collapse;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public boolean isCollapse() {
return collapse;
}
public void setCollapse(boolean collapse) {
this.collapse = collapse;
}
}

View File

@@ -0,0 +1,29 @@
package com.commafeed.frontend.model.request;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import com.wordnik.swagger.annotations.ApiClass;
import com.wordnik.swagger.annotations.ApiProperty;
@SuppressWarnings("serial")
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@ApiClass
public class IDRequest implements Serializable {
@ApiProperty
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}

View File

@@ -0,0 +1,51 @@
package com.commafeed.frontend.model.request;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import com.wordnik.swagger.annotations.ApiClass;
import com.wordnik.swagger.annotations.ApiProperty;
@SuppressWarnings("serial")
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@ApiClass("Mark Request")
public class MarkRequest implements Serializable {
@ApiProperty(value = "id", required = true)
private String id;
@ApiProperty(value = "mark as read or unread")
private boolean read;
@ApiProperty(value = "only entries older than this, prevent marking an entry that was not retrieved", required = false)
private Long olderThan;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public boolean isRead() {
return read;
}
public void setRead(boolean read) {
this.read = read;
}
public Long getOlderThan() {
return olderThan;
}
public void setOlderThan(Long olderThan) {
this.olderThan = olderThan;
}
}

View File

@@ -1,4 +1,4 @@
package com.commafeed.frontend.model;
package com.commafeed.frontend.model.request;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;

View File

@@ -1,4 +1,4 @@
package com.commafeed.frontend.model;
package com.commafeed.frontend.model.request;
import java.io.Serializable;

View File

@@ -0,0 +1,40 @@
package com.commafeed.frontend.model.request;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import com.wordnik.swagger.annotations.ApiClass;
import com.wordnik.swagger.annotations.ApiProperty;
@SuppressWarnings("serial")
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@ApiClass("Rename Request")
public class RenameRequest implements Serializable {
@ApiProperty(value = "id", required = true)
private Long id;
@ApiProperty(value = "mark as read or unread")
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@@ -1,4 +1,4 @@
package com.commafeed.frontend.model;
package com.commafeed.frontend.model.request;
import java.io.Serializable;
@@ -13,7 +13,7 @@ import com.wordnik.swagger.annotations.ApiProperty;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@ApiClass("Subscription request")
public class SubscriptionRequest implements Serializable {
public class SubscribeRequest implements Serializable {
@ApiProperty(value = "url of the feed", required = true)
private String url;

View File

@@ -26,7 +26,7 @@ import com.commafeed.backend.model.UserRole.Role;
import com.commafeed.backend.services.ApplicationSettingsService;
import com.commafeed.backend.services.UserService;
import com.commafeed.frontend.CommaFeedSession;
import com.commafeed.frontend.model.RegistrationRequest;
import com.commafeed.frontend.model.request.RegistrationRequest;
import com.commafeed.frontend.pages.GoogleImportRedirectPage;
import com.commafeed.frontend.utils.ModelFactory.MF;

View File

@@ -0,0 +1,14 @@
package com.commafeed.frontend.rest;
public class Enums {
public enum Type {
category, feed, entry;
}
public enum ReadType {
all, unread;
}
}

View File

@@ -7,10 +7,10 @@ import javax.ws.rs.core.Application;
import com.commafeed.frontend.rest.resources.AdminREST;
import com.commafeed.frontend.rest.resources.ApiDocumentationREST;
import com.commafeed.frontend.rest.resources.EntriesREST;
import com.commafeed.frontend.rest.resources.SessionREST;
import com.commafeed.frontend.rest.resources.SettingsREST;
import com.commafeed.frontend.rest.resources.SubscriptionsREST;
import com.commafeed.frontend.rest.resources.CategoryREST;
import com.commafeed.frontend.rest.resources.EntryREST;
import com.commafeed.frontend.rest.resources.FeedREST;
import com.commafeed.frontend.rest.resources.UserREST;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import com.google.common.collect.Sets;
import com.wordnik.swagger.jaxrs.JaxrsApiReader;
@@ -27,10 +27,10 @@ public class RESTApplication extends Application {
Set<Class<?>> set = Sets.newHashSet();
set.add(JacksonJsonProvider.class);
set.add(EntriesREST.class);
set.add(SubscriptionsREST.class);
set.add(SettingsREST.class);
set.add(SessionREST.class);
set.add(EntryREST.class);
set.add(FeedREST.class);
set.add(CategoryREST.class);
set.add(UserREST.class);
set.add(AdminREST.class);
set.add(ApiDocumentationREST.class);

View File

@@ -37,6 +37,7 @@ import com.commafeed.backend.feeds.OPMLImporter;
import com.commafeed.backend.model.User;
import com.commafeed.backend.model.UserRole.Role;
import com.commafeed.backend.services.ApplicationSettingsService;
import com.commafeed.backend.services.FeedEntryService;
import com.commafeed.backend.services.FeedSubscriptionService;
import com.commafeed.backend.services.PasswordEncryptionService;
import com.commafeed.backend.services.UserService;
@@ -46,7 +47,7 @@ import com.commafeed.frontend.SecurityCheck;
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class AbstractREST {
public abstract class AbstractREST {
@Context
HttpServletRequest request;
@@ -73,6 +74,9 @@ public class AbstractREST {
@Inject
FeedEntryStatusDAO feedEntryStatusDAO;
@Inject
FeedEntryService feedEntryService;
@Inject
UserDAO userDAO;

View File

@@ -13,6 +13,7 @@ import org.apache.commons.lang.StringUtils;
import com.commafeed.backend.model.UserRole.Role;
import com.commafeed.frontend.SecurityCheck;
import com.commafeed.frontend.model.Entries;
import com.commafeed.frontend.model.request.MarkRequest;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.core.Documentation;
@@ -31,6 +32,8 @@ public abstract class AbstractResourceREST extends AbstractREST {
@Context HttpHeaders headers, @Context UriInfo uriInfo) {
TypeUtil.addAllowablePackage(Entries.class.getPackage().getName());
TypeUtil.addAllowablePackage(MarkRequest.class.getPackage().getName());
String apiVersion = ApiDocumentationREST.API_VERSION;
String swaggerVersion = SwaggerSpec.version();
String basePath = ApiDocumentationREST

View File

@@ -7,7 +7,7 @@ import java.util.Set;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
@@ -21,6 +21,7 @@ import com.commafeed.backend.model.UserRole.Role;
import com.commafeed.backend.model.UserSettings.ReadingOrder;
import com.commafeed.frontend.SecurityCheck;
import com.commafeed.frontend.model.UserModel;
import com.commafeed.frontend.model.request.IDRequest;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@@ -35,7 +36,7 @@ public class AdminREST extends AbstractResourceREST {
@Path("/user/save")
@POST
@ApiOperation(value = "Manually save or update a user", notes = "Manually save or update a user. If the id is not specified, a new user will be created")
@ApiOperation(value = "Save or update a user", notes = "Save or update a user. If the id is not specified, a new user will be created")
public Response save(@ApiParam(required = true) UserModel userModel) {
Preconditions.checkNotNull(userModel);
Preconditions.checkNotNull(userModel.getName());
@@ -92,11 +93,11 @@ public class AdminREST extends AbstractResourceREST {
}
@Path("/user/get")
@Path("/user/get/{id}")
@GET
@ApiOperation(value = "Get user information", notes = "Get user information", responseClass = "com.commafeed.frontend.model.UserModel")
public UserModel getUser(
@ApiParam(value = "user id", required = true) @QueryParam("id") Long id) {
@ApiParam(value = "user id", required = true) @PathParam("id") Long id) {
Preconditions.checkNotNull(id);
User user = userDAO.findById(id);
UserModel userModel = new UserModel();
@@ -137,11 +138,11 @@ public class AdminREST extends AbstractResourceREST {
@Path("/user/delete")
@POST
@ApiOperation(value = "Delete a user", notes = "Delete a user, and all his subscriptions")
public Response delete(
@ApiParam(value = "user id", required = true) @QueryParam("id") Long id) {
Preconditions.checkNotNull(id);
public Response delete(@ApiParam(required = true) IDRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
User user = userDAO.findById(id);
User user = userDAO.findById(req.getId());
if (user == null) {
return Response.status(Status.NOT_FOUND).build();
}
@@ -159,24 +160,24 @@ public class AdminREST extends AbstractResourceREST {
return Response.ok().build();
}
@Path("/settings/get")
@Path("/settings")
@GET
@ApiOperation(value = "Retrieve application settings", notes = "Retrieve application settings", responseClass = "com.commafeed.backend.model.ApplicationSettings")
public ApplicationSettings getSettings() {
return applicationSettingsService.get();
}
@Path("/settings/save")
@Path("/settings")
@POST
@ApiOperation(value = "Save application settings", notes = "Save application settings")
public void saveSettings(@ApiParam(required = true) ApplicationSettings settings) {
public void saveSettings(
@ApiParam(required = true) ApplicationSettings settings) {
Preconditions.checkNotNull(settings);
applicationSettingsService.save(settings);
}
@Path("/metrics/get")
@Path("/metrics")
@GET
public int[] getMetrics() {
return new int[] { metricsBean.getFeedsRefreshedLastMinute(),

View File

@@ -7,6 +7,7 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import com.commafeed.frontend.model.Entries;
import com.commafeed.frontend.model.request.MarkRequest;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.core.Documentation;
@@ -25,6 +26,7 @@ public class ApiDocumentationREST extends AbstractREST {
public Response getAllApis(@Context Application app) {
TypeUtil.addAllowablePackage(Entries.class.getPackage().getName());
TypeUtil.addAllowablePackage(MarkRequest.class.getPackage().getName());
Documentation doc = new Documentation();
for (Class<?> resource : app.getClasses()) {

View File

@@ -0,0 +1,257 @@
package com.commafeed.frontend.rest.resources;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import com.commafeed.backend.model.FeedCategory;
import com.commafeed.backend.model.FeedEntryStatus;
import com.commafeed.backend.model.FeedSubscription;
import com.commafeed.backend.model.UserSettings.ReadingOrder;
import com.commafeed.frontend.model.Category;
import com.commafeed.frontend.model.Entries;
import com.commafeed.frontend.model.Entry;
import com.commafeed.frontend.model.Subscription;
import com.commafeed.frontend.model.request.CollapseRequest;
import com.commafeed.frontend.model.request.IDRequest;
import com.commafeed.frontend.model.request.MarkRequest;
import com.commafeed.frontend.model.request.RenameRequest;
import com.commafeed.frontend.rest.Enums.ReadType;
import com.google.common.base.Preconditions;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
@Path("/category")
@Api(value = "/category", description = "Operations about user categories")
public class CategoryREST extends AbstractResourceREST {
public static final String ALL = "all";
@Path("/entries")
@GET
@ApiOperation(value = "Get category entries", notes = "Get a list of category entries", responseClass = "com.commafeed.frontend.model.Entries")
public Entries getCategoryEntries(
@ApiParam(value = "id of the category, or 'all'", required = true) @QueryParam("id") String id,
@ApiParam(value = "all entries or only unread ones", allowableValues = "all,unread", required = true) @QueryParam("readType") ReadType readType,
@ApiParam(value = "offset for paging") @DefaultValue("0") @QueryParam("offset") int offset,
@ApiParam(value = "limit for paging") @DefaultValue("-1") @QueryParam("limit") int limit,
@ApiParam(value = "date ordering", allowableValues = "asc,desc") @QueryParam("order") @DefaultValue("desc") ReadingOrder order) {
Preconditions.checkNotNull(id);
Preconditions.checkNotNull(readType);
Entries entries = new Entries();
boolean unreadOnly = readType == ReadType.unread;
if (ALL.equals(id)) {
entries.setName("All");
List<FeedEntryStatus> unreadEntries = feedEntryStatusDAO.findAll(
getUser(), unreadOnly, offset, limit, order, true);
for (FeedEntryStatus status : unreadEntries) {
entries.getEntries().add(Entry.build(status));
}
} else {
FeedCategory feedCategory = feedCategoryDAO.findById(getUser(),
Long.valueOf(id));
if (feedCategory != null) {
List<FeedCategory> childrenCategories = feedCategoryDAO
.findAllChildrenCategories(getUser(), feedCategory);
List<FeedEntryStatus> unreadEntries = feedEntryStatusDAO
.findByCategories(childrenCategories, getUser(),
unreadOnly, offset, limit, order, true);
for (FeedEntryStatus status : unreadEntries) {
entries.getEntries().add(Entry.build(status));
}
entries.setName(feedCategory.getName());
}
}
entries.setTimestamp(Calendar.getInstance().getTimeInMillis());
return entries;
}
@Path("/mark")
@POST
@ApiOperation(value = "Mark category entries", notes = "Mark feed entries of this category as read")
public Response markCategoryEntries(
@ApiParam(value = "category id, or 'all'", required = true) MarkRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
Date olderThan = req.getOlderThan() == null ? null : new Date(
req.getOlderThan());
if (ALL.equals(req.getId())) {
feedEntryStatusDAO.markAllEntries(getUser(), olderThan);
} else {
List<FeedCategory> categories = feedCategoryDAO
.findAllChildrenCategories(
getUser(),
feedCategoryDAO.findById(getUser(),
Long.valueOf(req.getId())));
feedEntryStatusDAO.markCategoryEntries(getUser(), categories,
olderThan);
}
return Response.ok(Status.OK).build();
}
@Path("/add")
@POST
@ApiOperation(value = "Add a category", notes = "Add a new feed category")
public Response addCategory(
@ApiParam(value = "new name", required = true) @QueryParam("name") String name,
@ApiParam(value = "parent category id, if any") @QueryParam("parentId") String parentId) {
Preconditions.checkNotNull(name);
FeedCategory cat = new FeedCategory();
cat.setName(name);
cat.setUser(getUser());
if (parentId != null && !ALL.equals(parentId)) {
FeedCategory parent = new FeedCategory();
parent.setId(Long.valueOf(parentId));
cat.setParent(parent);
}
feedCategoryDAO.save(cat);
return Response.ok().build();
}
@POST
@Path("/delete")
@ApiOperation(value = "Delete a category", notes = "Delete an existing feed category")
public Response deleteCategory(@ApiParam(required = true) IDRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
FeedCategory cat = feedCategoryDAO.findById(getUser(), req.getId());
if (cat != null) {
List<FeedSubscription> subs = feedSubscriptionDAO.findByCategory(
getUser(), cat);
for (FeedSubscription sub : subs) {
sub.setCategory(null);
}
feedSubscriptionDAO.update(subs);
feedCategoryDAO.delete(cat);
return Response.ok().build();
} else {
return Response.status(Status.NOT_FOUND).build();
}
}
@POST
@Path("/rename")
@ApiOperation(value = "Rename a category", notes = "Rename an existing feed category")
public Response renameCategory(@ApiParam(required = true) RenameRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
Preconditions.checkArgument(StringUtils.isNotBlank(req.getName()));
FeedCategory category = feedCategoryDAO
.findById(getUser(), req.getId());
category.setName(req.getName());
feedCategoryDAO.update(category);
return Response.ok(Status.OK).build();
}
@POST
@Path("/collapse")
@ApiOperation(value = "Collapse a category", notes = "Save collapsed or expanded status for a category")
public Response collapse(@ApiParam(required = true) CollapseRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
FeedCategory category = feedCategoryDAO.findById(getUser(),
Long.valueOf(req.getId()));
category.setCollapsed(req.isCollapse());
feedCategoryDAO.update(category);
return Response.ok(Status.OK).build();
}
@GET
@Path("/get")
@ApiOperation(value = "Get feed categories", notes = "Get all categories and subscriptions of the user", responseClass = "com.commafeed.frontend.model.Category")
public Category getSubscriptions() {
List<FeedCategory> categories = feedCategoryDAO.findAll(getUser());
List<FeedSubscription> subscriptions = feedSubscriptionDAO
.findAll(getUser());
Map<Long, Long> unreadCount = feedEntryStatusDAO
.getUnreadCount(getUser());
Category root = buildCategory(null, categories, subscriptions,
unreadCount);
root.setId("all");
root.setName("All");
return root;
}
private Category buildCategory(Long id, List<FeedCategory> categories,
List<FeedSubscription> subscriptions, Map<Long, Long> unreadCount) {
Category category = new Category();
category.setId(String.valueOf(id));
category.setExpanded(true);
for (FeedCategory c : categories) {
if ((id == null && c.getParent() == null)
|| (c.getParent() != null && ObjectUtils.equals(c
.getParent().getId(), id))) {
Category child = buildCategory(c.getId(), categories,
subscriptions, unreadCount);
child.setId(String.valueOf(c.getId()));
child.setName(c.getName());
child.setExpanded(!c.isCollapsed());
category.getChildren().add(child);
}
}
Collections.sort(category.getChildren(), new Comparator<Category>() {
@Override
public int compare(Category o1, Category o2) {
return ObjectUtils.compare(o1.getName(), o2.getName());
}
});
for (FeedSubscription subscription : subscriptions) {
if ((id == null && subscription.getCategory() == null)
|| (subscription.getCategory() != null && ObjectUtils
.equals(subscription.getCategory().getId(), id))) {
Subscription sub = new Subscription();
sub.setId(subscription.getId());
sub.setName(subscription.getTitle());
sub.setMessage(subscription.getFeed().getMessage());
sub.setErrorCount(subscription.getFeed().getErrorCount());
sub.setFeedUrl(subscription.getFeed().getLink());
Long size = unreadCount.get(subscription.getId());
sub.setUnread(size == null ? 0 : size);
category.getFeeds().add(sub);
}
}
Collections.sort(category.getFeeds(), new Comparator<Subscription>() {
@Override
public int compare(Subscription o1, Subscription o2) {
return ObjectUtils.compare(o1.getName(), o2.getName());
}
});
return category;
}
}

View File

@@ -1,231 +0,0 @@
package com.commafeed.frontend.rest.resources;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.apache.commons.lang.StringUtils;
import com.commafeed.backend.model.FeedCategory;
import com.commafeed.backend.model.FeedEntry;
import com.commafeed.backend.model.FeedEntryStatus;
import com.commafeed.backend.model.FeedSubscription;
import com.commafeed.backend.model.UserSettings.ReadingOrder;
import com.commafeed.frontend.model.Entries;
import com.commafeed.frontend.model.Entry;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
@Path("/entries/")
@Api(value = "/entries", description = "Operations about feed entries")
public class EntriesREST extends AbstractResourceREST {
public static final String ALL = "all";
public enum Type {
category, feed, entry;
}
public enum ReadType {
all, unread;
}
@Path("/feed/get")
@GET
@ApiOperation(value = "Get feed entries", notes = "Get a list of feed entries", responseClass = "com.commafeed.frontend.model.Entries")
public Entries getFeedEntries(
@ApiParam(value = "id of the feed", required = true) @QueryParam("id") String id,
@ApiParam(value = "all entries or only unread ones", allowableValues = "all,unread", required = true) @QueryParam("readType") ReadType readType,
@ApiParam(value = "offset for paging") @DefaultValue("0") @QueryParam("offset") int offset,
@ApiParam(value = "limit for paging") @DefaultValue("-1") @QueryParam("limit") int limit,
@ApiParam(value = "date ordering", allowableValues = "asc,desc") @QueryParam("order") @DefaultValue("desc") ReadingOrder order) {
Preconditions.checkNotNull(id);
Preconditions.checkNotNull(readType);
Entries entries = new Entries();
boolean unreadOnly = readType == ReadType.unread;
FeedSubscription subscription = feedSubscriptionDAO.findById(getUser(),
Long.valueOf(id));
if (subscription != null) {
entries.setName(subscription.getTitle());
entries.setMessage(subscription.getFeed().getMessage());
entries.setErrorCount(subscription.getFeed().getErrorCount());
List<FeedEntryStatus> unreadEntries = feedEntryStatusDAO
.findByFeed(subscription.getFeed(), getUser(), unreadOnly,
offset, limit, order, true);
for (FeedEntryStatus status : unreadEntries) {
entries.getEntries().add(buildEntry(status));
}
}
entries.setTimestamp(Calendar.getInstance().getTimeInMillis());
return entries;
}
@Path("/category/get")
@GET
@ApiOperation(value = "Get category entries", notes = "Get a list of category entries", responseClass = "com.commafeed.frontend.model.Entries")
public Entries getCategoryEntries(
@ApiParam(value = "id of the category, or 'all'", required = true) @QueryParam("id") String id,
@ApiParam(value = "all entries or only unread ones", allowableValues = "all,unread", required = true) @QueryParam("readType") ReadType readType,
@ApiParam(value = "offset for paging") @DefaultValue("0") @QueryParam("offset") int offset,
@ApiParam(value = "limit for paging") @DefaultValue("-1") @QueryParam("limit") int limit,
@ApiParam(value = "date ordering", allowableValues = "asc,desc") @QueryParam("order") @DefaultValue("desc") ReadingOrder order) {
Preconditions.checkNotNull(id);
Preconditions.checkNotNull(readType);
Entries entries = new Entries();
boolean unreadOnly = readType == ReadType.unread;
if (ALL.equals(id)) {
entries.setName("All");
List<FeedEntryStatus> unreadEntries = feedEntryStatusDAO.findAll(
getUser(), unreadOnly, offset, limit, order, true);
for (FeedEntryStatus status : unreadEntries) {
entries.getEntries().add(buildEntry(status));
}
} else {
FeedCategory feedCategory = feedCategoryDAO.findById(getUser(),
Long.valueOf(id));
if (feedCategory != null) {
List<FeedCategory> childrenCategories = feedCategoryDAO
.findAllChildrenCategories(getUser(), feedCategory);
List<FeedEntryStatus> unreadEntries = feedEntryStatusDAO
.findByCategories(childrenCategories, getUser(),
unreadOnly, offset, limit, order, true);
for (FeedEntryStatus status : unreadEntries) {
entries.getEntries().add(buildEntry(status));
}
entries.setName(feedCategory.getName());
}
}
entries.setTimestamp(Calendar.getInstance().getTimeInMillis());
return entries;
}
private Entry buildEntry(FeedEntryStatus status) {
Entry entry = new Entry();
FeedEntry feedEntry = status.getEntry();
entry.setId(String.valueOf(status.getId()));
entry.setTitle(feedEntry.getContent().getTitle());
entry.setContent(feedEntry.getContent().getContent());
entry.setEnclosureUrl(status.getEntry().getContent().getEnclosureUrl());
entry.setEnclosureType(status.getEntry().getContent()
.getEnclosureType());
entry.setDate(feedEntry.getUpdated());
entry.setUrl(feedEntry.getUrl());
entry.setRead(status.isRead());
entry.setFeedName(status.getSubscription().getTitle());
entry.setFeedId(String.valueOf(status.getSubscription().getId()));
entry.setFeedUrl(status.getSubscription().getFeed().getLink());
return entry;
}
@Path("/entry/mark")
@POST
@ApiOperation(value = "Mark a feed entry", notes = "Mark a feed entry as read/unread")
public Response markFeedEntry(
@ApiParam(value = "entry id", required = true) @QueryParam("id") String id,
@ApiParam(value = "read status", required = true) @QueryParam("read") boolean read) {
Preconditions.checkNotNull(id);
Preconditions.checkNotNull(read);
FeedEntryStatus status = feedEntryStatusDAO.findById(getUser(),
Long.valueOf(id));
status.setRead(read);
feedEntryStatusDAO.update(status);
return Response.ok(Status.OK).build();
}
@Path("/feed/mark")
@POST
@ApiOperation(value = "Mark feed entries", notes = "Mark feed entries as read")
public Response markFeedEntries(
@ApiParam(value = "feed id", required = true) @QueryParam("id") String id,
@ApiParam(value = "only entries older than this, prevent marking an entry that was not retrieved") @QueryParam("olderThan") Long olderThanTimestamp) {
Preconditions.checkNotNull(id);
Date olderThan = olderThanTimestamp == null ? null : new Date(
olderThanTimestamp);
FeedSubscription subscription = feedSubscriptionDAO.findById(getUser(),
Long.valueOf(id));
feedEntryStatusDAO.markFeedEntries(getUser(), subscription.getFeed(),
olderThan);
return Response.ok(Status.OK).build();
}
@Path("/category/mark")
@POST
@ApiOperation(value = "Mark category entries", notes = "Mark feed entries as read")
public Response markCategoryEntries(
@ApiParam(value = "category id, or 'all'", required = true) @QueryParam("id") String id,
@ApiParam(value = "only entries older than this, prevent marking an entry that was not retrieved") @QueryParam("olderThan") Long olderThanTimestamp) {
Preconditions.checkNotNull(id);
Date olderThan = olderThanTimestamp == null ? null : new Date(
olderThanTimestamp);
if (ALL.equals(id)) {
feedEntryStatusDAO.markAllEntries(getUser(), olderThan);
} else {
List<FeedCategory> categories = feedCategoryDAO
.findAllChildrenCategories(
getUser(),
feedCategoryDAO.findById(getUser(),
Long.valueOf(id)));
feedEntryStatusDAO.markCategoryEntries(getUser(), categories,
olderThan);
}
return Response.ok(Status.OK).build();
}
@Path("/search")
@GET
@ApiOperation(value = "Search for entries", notes = "Look through title and content of entries by keywords", responseClass = "com.commafeed.frontend.model.Entries")
public Entries searchEntries(
@ApiParam(value = "keywords separated by spaces, 3 characters minimum", required = true) @QueryParam("keywords") String keywords,
@ApiParam(value = "offset for paging") @DefaultValue("0") @QueryParam("offset") int offset,
@ApiParam(value = "limit for paging") @DefaultValue("-1") @QueryParam("limit") int limit) {
keywords = StringUtils.trimToEmpty(keywords);
Preconditions.checkArgument(StringUtils.length(keywords) >= 3);
Entries entries = new Entries();
List<Entry> list = Lists.newArrayList();
List<FeedEntryStatus> entriesStatus = feedEntryStatusDAO
.findByKeywords(getUser(), keywords, offset, limit, true);
for (FeedEntryStatus status : entriesStatus) {
list.add(buildEntry(status));
}
entries.setName("Search for : " + keywords);
entries.getEntries().addAll(list);
return entries;
}
}

View File

@@ -0,0 +1,67 @@
package com.commafeed.frontend.rest.resources;
import java.util.List;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.apache.commons.lang.StringUtils;
import com.commafeed.backend.model.FeedEntryStatus;
import com.commafeed.frontend.model.Entries;
import com.commafeed.frontend.model.Entry;
import com.commafeed.frontend.model.request.MarkRequest;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
@Path("/entry")
@Api(value = "/entry", description = "Operations about feed entries")
public class EntryREST extends AbstractResourceREST {
@Path("/mark")
@POST
@ApiOperation(value = "Mark a feed entry", notes = "Mark a feed entry as read/unread")
public Response markFeedEntry(
@ApiParam(value = "Mark Request", required = true) MarkRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
feedEntryService.markEntry(getUser(), Long.valueOf(req.getId()),
req.isRead());
return Response.ok(Status.OK).build();
}
@Path("/search")
@GET
@ApiOperation(value = "Search for entries", notes = "Look through title and content of entries by keywords", responseClass = "com.commafeed.frontend.model.Entries")
public Entries searchEntries(
@ApiParam(value = "keywords separated by spaces, 3 characters minimum", required = true) @QueryParam("keywords") String keywords,
@ApiParam(value = "offset for paging") @DefaultValue("0") @QueryParam("offset") int offset,
@ApiParam(value = "limit for paging") @DefaultValue("-1") @QueryParam("limit") int limit) {
keywords = StringUtils.trimToEmpty(keywords);
Preconditions.checkArgument(StringUtils.length(keywords) >= 3);
Entries entries = new Entries();
List<Entry> list = Lists.newArrayList();
List<FeedEntryStatus> entriesStatus = feedEntryStatusDAO
.findByKeywords(getUser(), keywords, offset, limit, true);
for (FeedEntryStatus status : entriesStatus) {
list.add(Entry.build(status));
}
entries.setName("Search for : " + keywords);
entries.getEntries().addAll(list);
return entries;
}
}

View File

@@ -0,0 +1,205 @@
package com.commafeed.frontend.rest.resources;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import com.commafeed.backend.model.Feed;
import com.commafeed.backend.model.FeedCategory;
import com.commafeed.backend.model.FeedEntryStatus;
import com.commafeed.backend.model.FeedSubscription;
import com.commafeed.backend.model.UserSettings.ReadingOrder;
import com.commafeed.frontend.model.Entries;
import com.commafeed.frontend.model.Entry;
import com.commafeed.frontend.model.request.MarkRequest;
import com.commafeed.frontend.model.request.RenameRequest;
import com.commafeed.frontend.model.request.SubscribeRequest;
import com.commafeed.frontend.model.request.IDRequest;
import com.commafeed.frontend.rest.Enums.ReadType;
import com.google.common.base.Preconditions;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
@Path("/feed")
@Api(value = "/feed", description = "Operations about feeds")
public class FeedREST extends AbstractResourceREST {
@Path("/entries")
@GET
@ApiOperation(value = "Get feed entries", notes = "Get a list of feed entries", responseClass = "com.commafeed.frontend.model.Entries")
public Entries getFeedEntries(
@ApiParam(value = "id of the feed", required = true) @QueryParam("id") String id,
@ApiParam(value = "all entries or only unread ones", allowableValues = "all,unread", required = true) @QueryParam("readType") ReadType readType,
@ApiParam(value = "offset for paging") @DefaultValue("0") @QueryParam("offset") int offset,
@ApiParam(value = "limit for paging") @DefaultValue("-1") @QueryParam("limit") int limit,
@ApiParam(value = "date ordering", allowableValues = "asc,desc") @QueryParam("order") @DefaultValue("desc") ReadingOrder order) {
Preconditions.checkNotNull(id);
Preconditions.checkNotNull(readType);
Entries entries = new Entries();
boolean unreadOnly = readType == ReadType.unread;
FeedSubscription subscription = feedSubscriptionDAO.findById(getUser(),
Long.valueOf(id));
if (subscription != null) {
entries.setName(subscription.getTitle());
entries.setMessage(subscription.getFeed().getMessage());
entries.setErrorCount(subscription.getFeed().getErrorCount());
List<FeedEntryStatus> unreadEntries = feedEntryStatusDAO
.findByFeed(subscription.getFeed(), getUser(), unreadOnly,
offset, limit, order, true);
for (FeedEntryStatus status : unreadEntries) {
entries.getEntries().add(Entry.build(status));
}
}
entries.setTimestamp(Calendar.getInstance().getTimeInMillis());
return entries;
}
@GET
@Path("/fetch")
@ApiOperation(value = "Fetch a feed", notes = "Fetch a feed by its url", responseClass = "com.commafeed.backend.model.Feed")
public Feed fetchFeed(
@ApiParam(value = "the feed's url", required = true) @QueryParam("url") String url) {
Preconditions.checkNotNull(url);
url = StringUtils.trimToEmpty(url);
url = prependHttp(url);
Feed feed = null;
try {
feed = feedFetcher.fetch(url, true, null, null);
} catch (Exception e) {
throw new WebApplicationException(e, Response
.status(Status.INTERNAL_SERVER_ERROR)
.entity(e.getMessage()).build());
}
return feed;
}
@Path("/mark")
@POST
@ApiOperation(value = "Mark feed entries", notes = "Mark feed entries as read (unread is not supported)")
public Response markFeedEntries(
@ApiParam(value = "Mark request") MarkRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
Date olderThan = req.getOlderThan() == null ? null : new Date(
req.getOlderThan());
FeedSubscription subscription = feedSubscriptionDAO.findById(getUser(),
Long.valueOf(req.getId()));
feedEntryStatusDAO.markFeedEntries(getUser(), subscription.getFeed(),
olderThan);
return Response.ok(Status.OK).build();
}
@POST
@Path("/subscribe")
@ApiOperation(value = "Subscribe to a feed", notes = "Subscribe to a feed")
public Response subscribe(
@ApiParam(value = "subscription request", required = true) SubscribeRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getTitle());
Preconditions.checkNotNull(req.getUrl());
String url = prependHttp(req.getUrl());
url = fetchFeed(url).getUrl();
FeedCategory category = CategoryREST.ALL.equals(req.getCategoryId()) ? null
: feedCategoryDAO.findById(Long.valueOf(req.getCategoryId()));
Feed fetchedFeed = fetchFeed(url);
feedSubscriptionService.subscribe(getUser(), fetchedFeed.getUrl(),
req.getTitle(), category);
return Response.ok(Status.OK).build();
}
private String prependHttp(String url) {
if (!url.startsWith("http")) {
url = "http://" + url;
}
return url;
}
@POST
@Path("/unsubscribe")
@ApiOperation(value = "Unsubscribe to a feed", notes = "Unsubscribe to a feed")
public Response unsubscribe(
@ApiParam(required = true) IDRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
FeedSubscription sub = feedSubscriptionDAO.findById(getUser(),
req.getId());
if (sub != null) {
feedSubscriptionDAO.delete(sub);
return Response.ok(Status.OK).build();
} else {
return Response.status(Status.NOT_FOUND).build();
}
}
@POST
@Path("/rename")
@ApiOperation(value = "Rename a subscription", notes = "Rename a feed subscription")
public Response rename(
@ApiParam(value = "subscription id", required = true) RenameRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
Preconditions.checkNotNull(req.getName());
FeedSubscription subscription = feedSubscriptionDAO.findById(getUser(),
req.getId());
subscription.setTitle(req.getName());
feedSubscriptionDAO.update(subscription);
return Response.ok(Status.OK).build();
}
@POST
@Path("/import")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@ApiOperation(value = "OPML Import", notes = "Import an OPML file, posted as a FORM with the 'file' name")
public Response importOpml() {
try {
FileItemFactory factory = new DiskFileItemFactory(1000000, null);
ServletFileUpload upload = new ServletFileUpload(factory);
for (FileItem item : upload.parseRequest(request)) {
if ("file".equals(item.getFieldName())) {
opmlImporter.importOpml(getUser(),
IOUtils.toString(item.getInputStream(), "UTF-8"));
break;
}
}
} catch (Exception e) {
throw new WebApplicationException(Response
.status(Status.INTERNAL_SERVER_ERROR)
.entity(e.getMessage()).build());
}
return Response.ok(Status.OK).build();
}
}

View File

@@ -1,56 +0,0 @@
package com.commafeed.frontend.rest.resources;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import org.apache.commons.lang.StringUtils;
import com.commafeed.backend.model.User;
import com.commafeed.backend.model.UserRole;
import com.commafeed.backend.model.UserRole.Role;
import com.commafeed.frontend.model.ProfileModificationRequest;
import com.commafeed.frontend.model.UserModel;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
@Path("/session")
@Api(value = "/session", description = "Operations about user profile")
public class SessionREST extends AbstractResourceREST {
@Path("/get")
@GET
@ApiOperation(value = "Retrieve user's profile", responseClass = "com.commafeed.frontend.model.UserModel")
public UserModel get() {
User user = getUser();
UserModel userModel = new UserModel();
userModel.setId(user.getId());
userModel.setName(user.getName());
userModel.setEmail(user.getEmail());
userModel.setEnabled(!user.isDisabled());
for (UserRole role : userRoleDAO.findAll(user)) {
if (role.getRole() == Role.ADMIN) {
userModel.setAdmin(true);
}
}
return userModel;
}
@Path("/save")
@POST
@ApiOperation(value = "Save user's profile")
public Response save(
@ApiParam(required = true) ProfileModificationRequest request) {
User user = getUser();
user.setEmail(request.getEmail());
if (StringUtils.isNotBlank(request.getPassword())) {
byte[] password = encryptionService.getEncryptedPassword(
request.getPassword(), user.getSalt());
user.setPassword(password);
}
userDAO.update(user);
return Response.ok().build();
}
}

View File

@@ -1,277 +0,0 @@
package com.commafeed.frontend.rest.resources;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import com.commafeed.backend.model.Feed;
import com.commafeed.backend.model.FeedCategory;
import com.commafeed.backend.model.FeedSubscription;
import com.commafeed.frontend.model.Category;
import com.commafeed.frontend.model.Subscription;
import com.commafeed.frontend.model.SubscriptionRequest;
import com.google.common.base.Preconditions;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
@Path("/subscriptions")
@Api(value = "/subscriptions", description = "Operations about user feed subscriptions")
public class SubscriptionsREST extends AbstractResourceREST {
@GET
@Path("/feed/fetch")
@ApiOperation(value = "Fetch a feed", notes = "Fetch a feed by its url", responseClass = "com.commafeed.backend.model.Feed")
public Feed fetchFeed(
@ApiParam(value = "the feed's url", required = true) @QueryParam("url") String url) {
Preconditions.checkNotNull(url);
url = StringUtils.trimToEmpty(url);
url = prependHttp(url);
Feed feed = null;
try {
feed = feedFetcher.fetch(url, true, null, null);
} catch (Exception e) {
throw new WebApplicationException(e, Response
.status(Status.INTERNAL_SERVER_ERROR)
.entity(e.getMessage()).build());
}
return feed;
}
@POST
@Path("/feed/subscribe")
@ApiOperation(value = "Subscribe to a feed", notes = "Subscribe to a feed")
public Response subscribe(
@ApiParam(value = "subscription request", required = true) SubscriptionRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getTitle());
Preconditions.checkNotNull(req.getUrl());
String url = prependHttp(req.getUrl());
url = fetchFeed(url).getUrl();
FeedCategory category = EntriesREST.ALL.equals(req.getCategoryId()) ? null
: feedCategoryDAO.findById(Long.valueOf(req.getCategoryId()));
Feed fetchedFeed = fetchFeed(url);
feedSubscriptionService.subscribe(getUser(), fetchedFeed.getUrl(),
req.getTitle(), category);
return Response.ok(Status.OK).build();
}
private String prependHttp(String url) {
if (!url.startsWith("http")) {
url = "http://" + url;
}
return url;
}
@POST
@Path("/feed/unsubscribe")
@ApiOperation(value = "Unsubscribe to a feed", notes = "Unsubscribe to a feed")
public Response unsubscribe(
@ApiParam(value = "subscription id", required = true) @QueryParam("id") Long subscriptionId) {
FeedSubscription sub = feedSubscriptionDAO.findById(getUser(),
subscriptionId);
if (sub != null) {
feedSubscriptionDAO.delete(sub);
return Response.ok(Status.OK).build();
} else {
return Response.status(Status.NOT_FOUND).build();
}
}
@POST
@Path("/feed/rename")
@ApiOperation(value = "Rename a subscription", notes = "Rename a feed subscription")
public Response rename(
@ApiParam(value = "subscription id", required = true) @QueryParam("id") Long id,
@ApiParam(value = "new name", required = true) @QueryParam("name") String name) {
FeedSubscription subscription = feedSubscriptionDAO.findById(getUser(),
id);
subscription.setTitle(name);
feedSubscriptionDAO.update(subscription);
return Response.ok(Status.OK).build();
}
@Path("/category/add")
@POST
@ApiOperation(value = "Add a category", notes = "Add a new feed category")
public Response addCategory(
@ApiParam(value = "new name", required = true) @QueryParam("name") String name,
@ApiParam(value = "parent category id, if any") @QueryParam("parentId") String parentId) {
Preconditions.checkNotNull(name);
FeedCategory cat = new FeedCategory();
cat.setName(name);
cat.setUser(getUser());
if (parentId != null && !EntriesREST.ALL.equals(parentId)) {
FeedCategory parent = new FeedCategory();
parent.setId(Long.valueOf(parentId));
cat.setParent(parent);
}
feedCategoryDAO.save(cat);
return Response.ok().build();
}
@POST
@Path("/category/delete")
@ApiOperation(value = "Delete a category", notes = "Delete an existing feed category")
public Response deleteCategory(
@ApiParam(value = "category id", required = true) @QueryParam("id") Long id) {
FeedCategory cat = feedCategoryDAO.findById(getUser(), id);
if (cat != null) {
List<FeedSubscription> subs = feedSubscriptionDAO.findByCategory(
getUser(), cat);
for (FeedSubscription sub : subs) {
sub.setCategory(null);
}
feedSubscriptionDAO.update(subs);
feedCategoryDAO.delete(cat);
return Response.ok().build();
} else {
return Response.status(Status.NOT_FOUND).build();
}
}
@POST
@Path("/category/rename")
@ApiOperation(value = "Rename a category", notes = "Rename an existing feed category")
public Response renameCategory(
@ApiParam(value = "category id", required = true) @QueryParam("id") Long id,
@ApiParam(value = "new name", required = true) @QueryParam("name") String name) {
FeedCategory category = feedCategoryDAO.findById(getUser(), id);
category.setName(name);
feedCategoryDAO.update(category);
return Response.ok(Status.OK).build();
}
@POST
@Path("/category/collapse")
@ApiOperation(value = "Collapse a category", notes = "Save collapsed or expanded status for a category")
public Response collapse(
@ApiParam(value = "category id", required = true) @QueryParam("id") String id,
@ApiParam(value = "true if collapsed", required = true) @QueryParam("collapse") boolean collapse) {
Preconditions.checkNotNull(id);
if (!EntriesREST.ALL.equals(id)) {
FeedCategory category = feedCategoryDAO.findById(getUser(),
Long.valueOf(id));
category.setCollapsed(collapse);
feedCategoryDAO.update(category);
}
return Response.ok(Status.OK).build();
}
@POST
@Path("/import")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@ApiOperation(value = "OPML Import", notes = "Import an OPML file, posted as a FORM with the 'file' name")
public Response importOpml() {
try {
FileItemFactory factory = new DiskFileItemFactory(1000000, null);
ServletFileUpload upload = new ServletFileUpload(factory);
for (FileItem item : upload.parseRequest(request)) {
if ("file".equals(item.getFieldName())) {
opmlImporter.importOpml(getUser(),
IOUtils.toString(item.getInputStream(), "UTF-8"));
break;
}
}
} catch (Exception e) {
throw new WebApplicationException(Response
.status(Status.INTERNAL_SERVER_ERROR)
.entity(e.getMessage()).build());
}
return Response.ok(Status.OK).build();
}
@GET
@Path("/get")
@ApiOperation(value = "Get feed subscriptions", notes = "Get all subscriptions of the user", responseClass = "com.commafeed.frontend.model.Category")
public Category getSubscriptions() {
List<FeedCategory> categories = feedCategoryDAO.findAll(getUser());
List<FeedSubscription> subscriptions = feedSubscriptionDAO
.findAll(getUser());
Map<Long, Long> unreadCount = feedEntryStatusDAO
.getUnreadCount(getUser());
Category root = buildCategory(null, categories, subscriptions,
unreadCount);
root.setId("all");
root.setName("All");
return root;
}
private Category buildCategory(Long id, List<FeedCategory> categories,
List<FeedSubscription> subscriptions, Map<Long, Long> unreadCount) {
Category category = new Category();
category.setId(String.valueOf(id));
category.setExpanded(true);
for (FeedCategory c : categories) {
if ((id == null && c.getParent() == null)
|| (c.getParent() != null && ObjectUtils.equals(c
.getParent().getId(), id))) {
Category child = buildCategory(c.getId(), categories,
subscriptions, unreadCount);
child.setId(String.valueOf(c.getId()));
child.setName(c.getName());
child.setExpanded(!c.isCollapsed());
category.getChildren().add(child);
}
}
Collections.sort(category.getChildren(), new Comparator<Category>() {
@Override
public int compare(Category o1, Category o2) {
return ObjectUtils.compare(o1.getName(), o2.getName());
}
});
for (FeedSubscription subscription : subscriptions) {
if ((id == null && subscription.getCategory() == null)
|| (subscription.getCategory() != null && ObjectUtils
.equals(subscription.getCategory().getId(), id))) {
Subscription sub = new Subscription();
sub.setId(subscription.getId());
sub.setName(subscription.getTitle());
sub.setMessage(subscription.getFeed().getMessage());
sub.setErrorCount(subscription.getFeed().getErrorCount());
sub.setFeedUrl(subscription.getFeed().getLink());
Long size = unreadCount.get(subscription.getId());
sub.setUnread(size == null ? 0 : size);
category.getFeeds().add(sub);
}
}
Collections.sort(category.getFeeds(), new Comparator<Subscription>() {
@Override
public int compare(Subscription o1, Subscription o2) {
return ObjectUtils.compare(o1.getName(), o2.getName());
}
});
return category;
}
}

View File

@@ -6,23 +6,30 @@ import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.apache.commons.lang.StringUtils;
import com.commafeed.backend.model.User;
import com.commafeed.backend.model.UserRole;
import com.commafeed.backend.model.UserSettings;
import com.commafeed.backend.model.UserRole.Role;
import com.commafeed.backend.model.UserSettings.ReadingMode;
import com.commafeed.backend.model.UserSettings.ReadingOrder;
import com.commafeed.frontend.model.Settings;
import com.commafeed.frontend.model.UserModel;
import com.commafeed.frontend.model.request.ProfileModificationRequest;
import com.google.common.base.Preconditions;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
@Path("/settings")
@Api(value = "/settings", description = "Operations about user settings")
public class SettingsREST extends AbstractResourceREST {
@Path("/user")
@Api(value = "/user", description = "Operations about the user")
public class UserREST extends AbstractResourceREST {
@Path("/get")
@Path("/settings")
@GET
@ApiOperation(value = "Retrieve user settings", notes = "Retrieve user settings", responseClass = "com.commafeed.frontend.model.Settings")
public Settings get() {
public Settings getSettings() {
Settings s = new Settings();
UserSettings settings = userSettingsDAO.findByUser(getUser());
if (settings != null) {
@@ -38,10 +45,10 @@ public class SettingsREST extends AbstractResourceREST {
return s;
}
@Path("/save")
@Path("/settings")
@POST
@ApiOperation(value = "Save user settings", notes = "Save user settings")
public Response save(@ApiParam Settings settings) {
public Response saveSettings(@ApiParam Settings settings) {
Preconditions.checkNotNull(settings);
UserSettings s = userSettingsDAO.findByUser(getUser());
@@ -57,4 +64,38 @@ public class SettingsREST extends AbstractResourceREST {
return Response.ok(Status.OK).build();
}
@Path("/profile")
@GET
@ApiOperation(value = "Retrieve user's profile", responseClass = "com.commafeed.frontend.model.UserModel")
public UserModel get() {
User user = getUser();
UserModel userModel = new UserModel();
userModel.setId(user.getId());
userModel.setName(user.getName());
userModel.setEmail(user.getEmail());
userModel.setEnabled(!user.isDisabled());
for (UserRole role : userRoleDAO.findAll(user)) {
if (role.getRole() == Role.ADMIN) {
userModel.setAdmin(true);
}
}
return userModel;
}
@Path("/profile")
@POST
@ApiOperation(value = "Save user's profile")
public Response save(
@ApiParam(required = true) ProfileModificationRequest request) {
User user = getUser();
user.setEmail(request.getEmail());
if (StringUtils.isNotBlank(request.getPassword())) {
byte[] password = encryptionService.getEncryptedPassword(
request.getPassword(), user.getSalt());
user.setPassword(password);
}
userDAO.update(user);
return Response.ok().build();
}
}