From af109ccf5c350cef551c2c473ad1a51546adbdc7 Mon Sep 17 00:00:00 2001 From: Athou Date: Thu, 18 Apr 2013 12:50:44 +0200 Subject: [PATCH] fix for admin api --- .../backend/services/FeedEntryService.java | 21 ++ .../com/commafeed/frontend/model/Entry.java | 46 ++- .../commafeed/frontend/model/MarkRequest.java | 41 --- .../model/request/CollapseRequest.java | 40 +++ .../frontend/model/request/IDRequest.java | 29 ++ .../frontend/model/request/MarkRequest.java | 51 ++++ .../ProfileModificationRequest.java | 2 +- .../{ => request}/RegistrationRequest.java | 2 +- .../frontend/model/request/RenameRequest.java | 40 +++ .../SubscribeRequest.java} | 4 +- .../pages/components/RegisterPanel.java | 2 +- .../com/commafeed/frontend/rest/Enums.java | 14 + .../frontend/rest/RESTApplication.java | 16 +- .../frontend/rest/resources/AbstractREST.java | 6 +- .../rest/resources/AbstractResourceREST.java | 3 + .../frontend/rest/resources/AdminREST.java | 29 +- .../rest/resources/ApiDocumentationREST.java | 2 + .../frontend/rest/resources/CategoryREST.java | 257 ++++++++++++++++ .../frontend/rest/resources/EntriesREST.java | 231 -------------- .../frontend/rest/resources/EntryREST.java | 67 +++++ .../frontend/rest/resources/FeedREST.java | 205 +++++++++++++ .../frontend/rest/resources/SessionREST.java | 56 ---- .../rest/resources/SubscriptionsREST.java | 277 ----------------- .../{SettingsREST.java => UserREST.java} | 55 +++- src/main/webapp/api/index.html | 2 +- src/main/webapp/js/controllers.js | 51 ++-- src/main/webapp/js/directives.js | 23 +- src/main/webapp/js/services.js | 281 +++++++----------- src/main/webapp/templates/_subscribe.html | 6 +- src/main/webapp/templates/_tree.html | 2 +- 30 files changed, 1000 insertions(+), 861 deletions(-) create mode 100644 src/main/java/com/commafeed/backend/services/FeedEntryService.java delete mode 100644 src/main/java/com/commafeed/frontend/model/MarkRequest.java create mode 100644 src/main/java/com/commafeed/frontend/model/request/CollapseRequest.java create mode 100644 src/main/java/com/commafeed/frontend/model/request/IDRequest.java create mode 100644 src/main/java/com/commafeed/frontend/model/request/MarkRequest.java rename src/main/java/com/commafeed/frontend/model/{ => request}/ProfileModificationRequest.java (90%) rename src/main/java/com/commafeed/frontend/model/{ => request}/RegistrationRequest.java (90%) create mode 100644 src/main/java/com/commafeed/frontend/model/request/RenameRequest.java rename src/main/java/com/commafeed/frontend/model/{SubscriptionRequest.java => request/SubscribeRequest.java} (87%) create mode 100644 src/main/java/com/commafeed/frontend/rest/Enums.java create mode 100644 src/main/java/com/commafeed/frontend/rest/resources/CategoryREST.java delete mode 100644 src/main/java/com/commafeed/frontend/rest/resources/EntriesREST.java create mode 100644 src/main/java/com/commafeed/frontend/rest/resources/EntryREST.java create mode 100644 src/main/java/com/commafeed/frontend/rest/resources/FeedREST.java delete mode 100644 src/main/java/com/commafeed/frontend/rest/resources/SessionREST.java delete mode 100644 src/main/java/com/commafeed/frontend/rest/resources/SubscriptionsREST.java rename src/main/java/com/commafeed/frontend/rest/resources/{SettingsREST.java => UserREST.java} (51%) diff --git a/src/main/java/com/commafeed/backend/services/FeedEntryService.java b/src/main/java/com/commafeed/backend/services/FeedEntryService.java new file mode 100644 index 00000000..927dfe77 --- /dev/null +++ b/src/main/java/com/commafeed/backend/services/FeedEntryService.java @@ -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); + } +} diff --git a/src/main/java/com/commafeed/frontend/model/Entry.java b/src/main/java/com/commafeed/frontend/model/Entry.java index 96041981..2bd417fb 100644 --- a/src/main/java/com/commafeed/frontend/model/Entry.java +++ b/src/main/java/com/commafeed/frontend/model/Entry.java @@ -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; diff --git a/src/main/java/com/commafeed/frontend/model/MarkRequest.java b/src/main/java/com/commafeed/frontend/model/MarkRequest.java deleted file mode 100644 index 622d9be6..00000000 --- a/src/main/java/com/commafeed/frontend/model/MarkRequest.java +++ /dev/null @@ -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; - } - -} diff --git a/src/main/java/com/commafeed/frontend/model/request/CollapseRequest.java b/src/main/java/com/commafeed/frontend/model/request/CollapseRequest.java new file mode 100644 index 00000000..fb45c11e --- /dev/null +++ b/src/main/java/com/commafeed/frontend/model/request/CollapseRequest.java @@ -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; + } + +} diff --git a/src/main/java/com/commafeed/frontend/model/request/IDRequest.java b/src/main/java/com/commafeed/frontend/model/request/IDRequest.java new file mode 100644 index 00000000..bfc4dbe8 --- /dev/null +++ b/src/main/java/com/commafeed/frontend/model/request/IDRequest.java @@ -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; + } + +} diff --git a/src/main/java/com/commafeed/frontend/model/request/MarkRequest.java b/src/main/java/com/commafeed/frontend/model/request/MarkRequest.java new file mode 100644 index 00000000..c057d84a --- /dev/null +++ b/src/main/java/com/commafeed/frontend/model/request/MarkRequest.java @@ -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; + } + +} diff --git a/src/main/java/com/commafeed/frontend/model/ProfileModificationRequest.java b/src/main/java/com/commafeed/frontend/model/request/ProfileModificationRequest.java similarity index 90% rename from src/main/java/com/commafeed/frontend/model/ProfileModificationRequest.java rename to src/main/java/com/commafeed/frontend/model/request/ProfileModificationRequest.java index 2c1a7c1f..9916f883 100644 --- a/src/main/java/com/commafeed/frontend/model/ProfileModificationRequest.java +++ b/src/main/java/com/commafeed/frontend/model/request/ProfileModificationRequest.java @@ -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; diff --git a/src/main/java/com/commafeed/frontend/model/RegistrationRequest.java b/src/main/java/com/commafeed/frontend/model/request/RegistrationRequest.java similarity index 90% rename from src/main/java/com/commafeed/frontend/model/RegistrationRequest.java rename to src/main/java/com/commafeed/frontend/model/request/RegistrationRequest.java index 20b9bd08..90b04d7b 100644 --- a/src/main/java/com/commafeed/frontend/model/RegistrationRequest.java +++ b/src/main/java/com/commafeed/frontend/model/request/RegistrationRequest.java @@ -1,4 +1,4 @@ -package com.commafeed.frontend.model; +package com.commafeed.frontend.model.request; import java.io.Serializable; diff --git a/src/main/java/com/commafeed/frontend/model/request/RenameRequest.java b/src/main/java/com/commafeed/frontend/model/request/RenameRequest.java new file mode 100644 index 00000000..3320a285 --- /dev/null +++ b/src/main/java/com/commafeed/frontend/model/request/RenameRequest.java @@ -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; + } + +} diff --git a/src/main/java/com/commafeed/frontend/model/SubscriptionRequest.java b/src/main/java/com/commafeed/frontend/model/request/SubscribeRequest.java similarity index 87% rename from src/main/java/com/commafeed/frontend/model/SubscriptionRequest.java rename to src/main/java/com/commafeed/frontend/model/request/SubscribeRequest.java index aeaaf67c..a36502fb 100644 --- a/src/main/java/com/commafeed/frontend/model/SubscriptionRequest.java +++ b/src/main/java/com/commafeed/frontend/model/request/SubscribeRequest.java @@ -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; diff --git a/src/main/java/com/commafeed/frontend/pages/components/RegisterPanel.java b/src/main/java/com/commafeed/frontend/pages/components/RegisterPanel.java index 503def7a..cee247ac 100644 --- a/src/main/java/com/commafeed/frontend/pages/components/RegisterPanel.java +++ b/src/main/java/com/commafeed/frontend/pages/components/RegisterPanel.java @@ -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; diff --git a/src/main/java/com/commafeed/frontend/rest/Enums.java b/src/main/java/com/commafeed/frontend/rest/Enums.java new file mode 100644 index 00000000..f217aaca --- /dev/null +++ b/src/main/java/com/commafeed/frontend/rest/Enums.java @@ -0,0 +1,14 @@ +package com.commafeed.frontend.rest; + + +public class Enums { + + public enum Type { + category, feed, entry; + } + + public enum ReadType { + all, unread; + } + +} diff --git a/src/main/java/com/commafeed/frontend/rest/RESTApplication.java b/src/main/java/com/commafeed/frontend/rest/RESTApplication.java index fd5db21e..8972b943 100644 --- a/src/main/java/com/commafeed/frontend/rest/RESTApplication.java +++ b/src/main/java/com/commafeed/frontend/rest/RESTApplication.java @@ -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> 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); diff --git a/src/main/java/com/commafeed/frontend/rest/resources/AbstractREST.java b/src/main/java/com/commafeed/frontend/rest/resources/AbstractREST.java index dc0d8fc7..6f17f39d 100644 --- a/src/main/java/com/commafeed/frontend/rest/resources/AbstractREST.java +++ b/src/main/java/com/commafeed/frontend/rest/resources/AbstractREST.java @@ -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; diff --git a/src/main/java/com/commafeed/frontend/rest/resources/AbstractResourceREST.java b/src/main/java/com/commafeed/frontend/rest/resources/AbstractResourceREST.java index 52334879..d8120f96 100644 --- a/src/main/java/com/commafeed/frontend/rest/resources/AbstractResourceREST.java +++ b/src/main/java/com/commafeed/frontend/rest/resources/AbstractResourceREST.java @@ -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 diff --git a/src/main/java/com/commafeed/frontend/rest/resources/AdminREST.java b/src/main/java/com/commafeed/frontend/rest/resources/AdminREST.java index 06950ef6..8b871b3e 100644 --- a/src/main/java/com/commafeed/frontend/rest/resources/AdminREST.java +++ b/src/main/java/com/commafeed/frontend/rest/resources/AdminREST.java @@ -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(), diff --git a/src/main/java/com/commafeed/frontend/rest/resources/ApiDocumentationREST.java b/src/main/java/com/commafeed/frontend/rest/resources/ApiDocumentationREST.java index 017339d4..8f36a28b 100644 --- a/src/main/java/com/commafeed/frontend/rest/resources/ApiDocumentationREST.java +++ b/src/main/java/com/commafeed/frontend/rest/resources/ApiDocumentationREST.java @@ -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()) { diff --git a/src/main/java/com/commafeed/frontend/rest/resources/CategoryREST.java b/src/main/java/com/commafeed/frontend/rest/resources/CategoryREST.java new file mode 100644 index 00000000..545bc77d --- /dev/null +++ b/src/main/java/com/commafeed/frontend/rest/resources/CategoryREST.java @@ -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 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 childrenCategories = feedCategoryDAO + .findAllChildrenCategories(getUser(), feedCategory); + List 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 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 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 categories = feedCategoryDAO.findAll(getUser()); + List subscriptions = feedSubscriptionDAO + .findAll(getUser()); + Map 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 categories, + List subscriptions, Map 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() { + @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() { + @Override + public int compare(Subscription o1, Subscription o2) { + return ObjectUtils.compare(o1.getName(), o2.getName()); + } + }); + return category; + } + +} diff --git a/src/main/java/com/commafeed/frontend/rest/resources/EntriesREST.java b/src/main/java/com/commafeed/frontend/rest/resources/EntriesREST.java deleted file mode 100644 index 7991c743..00000000 --- a/src/main/java/com/commafeed/frontend/rest/resources/EntriesREST.java +++ /dev/null @@ -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 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 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 childrenCategories = feedCategoryDAO - .findAllChildrenCategories(getUser(), feedCategory); - List 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 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 list = Lists.newArrayList(); - List 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; - } - -} diff --git a/src/main/java/com/commafeed/frontend/rest/resources/EntryREST.java b/src/main/java/com/commafeed/frontend/rest/resources/EntryREST.java new file mode 100644 index 00000000..20ea8d07 --- /dev/null +++ b/src/main/java/com/commafeed/frontend/rest/resources/EntryREST.java @@ -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 list = Lists.newArrayList(); + List 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; + } + +} diff --git a/src/main/java/com/commafeed/frontend/rest/resources/FeedREST.java b/src/main/java/com/commafeed/frontend/rest/resources/FeedREST.java new file mode 100644 index 00000000..b08d3daa --- /dev/null +++ b/src/main/java/com/commafeed/frontend/rest/resources/FeedREST.java @@ -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 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(); + } + +} diff --git a/src/main/java/com/commafeed/frontend/rest/resources/SessionREST.java b/src/main/java/com/commafeed/frontend/rest/resources/SessionREST.java deleted file mode 100644 index 5bcecece..00000000 --- a/src/main/java/com/commafeed/frontend/rest/resources/SessionREST.java +++ /dev/null @@ -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(); - } -} diff --git a/src/main/java/com/commafeed/frontend/rest/resources/SubscriptionsREST.java b/src/main/java/com/commafeed/frontend/rest/resources/SubscriptionsREST.java deleted file mode 100644 index 61f9b8bd..00000000 --- a/src/main/java/com/commafeed/frontend/rest/resources/SubscriptionsREST.java +++ /dev/null @@ -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 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 categories = feedCategoryDAO.findAll(getUser()); - List subscriptions = feedSubscriptionDAO - .findAll(getUser()); - Map 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 categories, - List subscriptions, Map 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() { - @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() { - @Override - public int compare(Subscription o1, Subscription o2) { - return ObjectUtils.compare(o1.getName(), o2.getName()); - } - }); - return category; - } -} diff --git a/src/main/java/com/commafeed/frontend/rest/resources/SettingsREST.java b/src/main/java/com/commafeed/frontend/rest/resources/UserREST.java similarity index 51% rename from src/main/java/com/commafeed/frontend/rest/resources/SettingsREST.java rename to src/main/java/com/commafeed/frontend/rest/resources/UserREST.java index a786155a..5ad9f9bb 100644 --- a/src/main/java/com/commafeed/frontend/rest/resources/SettingsREST.java +++ b/src/main/java/com/commafeed/frontend/rest/resources/UserREST.java @@ -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(); + } } diff --git a/src/main/webapp/api/index.html b/src/main/webapp/api/index.html index 7af86ff1..8959896b 100644 --- a/src/main/webapp/api/index.html +++ b/src/main/webapp/api/index.html @@ -30,7 +30,7 @@ apiKey:"", dom_id:"swagger-ui-container", supportHeaderParams: false, - supportedSubmitMethods: ['get', 'post', 'put'], + supportedSubmitMethods: ['get', 'post', 'put', 'delete'], onComplete: function(swaggerApi, swaggerUi){ if(console) { console.log("Loaded SwaggerUI") diff --git a/src/main/webapp/js/controllers.js b/src/main/webapp/js/controllers.js index 1f4fefa7..537c0363 100644 --- a/src/main/webapp/js/controllers.js +++ b/src/main/webapp/js/controllers.js @@ -16,7 +16,8 @@ module.run(function($rootScope) { }); }); -module.controller('SubscribeCtrl', function($scope, SubscriptionService) { +module.controller('SubscribeCtrl', function($scope, FeedService, + CategoryService) { $scope.opts = { backdropFade : true, @@ -27,7 +28,7 @@ module.controller('SubscribeCtrl', function($scope, SubscriptionService) { $scope.isOpenImport = false; $scope.sub = {}; - $scope.SubscriptionService = SubscriptionService; + $scope.CategoryService = CategoryService; $scope.open = function() { $scope.sub = {}; @@ -42,7 +43,7 @@ module.controller('SubscribeCtrl', function($scope, SubscriptionService) { var msg = 'Loading...'; if ($scope.sub.url && (!$scope.sub.title || $scope.sub.title == msg)) { $scope.sub.title = msg; - SubscriptionService.fetch({ + FeedService.fetch({ url : $scope.sub.url }, function(data) { $scope.sub.title = data.title; @@ -52,7 +53,9 @@ module.controller('SubscribeCtrl', function($scope, SubscriptionService) { }; $scope.save = function() { - SubscriptionService.subscribe($scope.sub); + FeedService.subscribe($scope.sub, function() { + CategoryService.init(); + }); $scope.close(); }; @@ -65,7 +68,7 @@ module.controller('SubscribeCtrl', function($scope, SubscriptionService) { }; $scope.uploadComplete = function(contents, completed) { - SubscriptionService.init(); + CategoryService.init(); $scope.closeImport(); }; @@ -81,13 +84,13 @@ module.controller('SubscribeCtrl', function($scope, SubscriptionService) { }; $scope.saveCategory = function() { - SubscriptionService.addCategory($scope.cat); + CategoryService.add($scope.cat); $scope.closeCategory(); }; }); module.controller('CategoryTreeCtrl', function($scope, $timeout, $stateParams, - $window, $location, $state, $route, SubscriptionService) { + $window, $location, $state, $route, CategoryService) { $scope.selectedType = $stateParams._type; $scope.selectedId = $stateParams._id; @@ -98,12 +101,12 @@ module.controller('CategoryTreeCtrl', function($scope, $timeout, $stateParams, }); $timeout(function refreshTree() { - SubscriptionService.init(function() { + CategoryService.init(function() { $timeout(refreshTree, 15000); }); }, 15000); - $scope.SubscriptionService = SubscriptionService; + $scope.CategoryService = CategoryService; $scope.unreadCount = function(category) { var count = 0; @@ -123,7 +126,7 @@ module.controller('CategoryTreeCtrl', function($scope, $timeout, $stateParams, }; var rootUnreadCount = function() { - return $scope.unreadCount($scope.SubscriptionService.subscriptions); + return $scope.unreadCount($scope.CategoryService.subscriptions); }; $scope.$watch(rootUnreadCount, function(value) { @@ -192,20 +195,19 @@ module.controller('CategoryTreeCtrl', function($scope, $timeout, $stateParams, }; $scope.$on('mark', function(event, args) { - mark($scope.SubscriptionService.subscriptions, args.entry); + mark($scope.CategoryService.subscriptions, args.entry); }); }); module.controller('ToolbarCtrl', function($scope, $http, $state, $stateParams, $route, $location, - SettingsService, EntryService, SubscriptionService, - SessionService) { + SettingsService, EntryService, ProfileService) { function totalActiveAjaxRequests() { return ($http.pendingRequests.length + $.active); } - $scope.session = SessionService.get(); + $scope.session = ProfileService.get(); $scope.loading = true; $scope.$watch(totalActiveAjaxRequests, function() { @@ -271,7 +273,7 @@ module.controller('ToolbarCtrl', }); module.controller('FeedListCtrl', function($scope, $stateParams, $http, $route, - $window, EntryService, SettingsService, SubscriptionService) { + $window, EntryService, SettingsService, FeedService, CategoryService) { $scope.selectedType = $stateParams._type; $scope.selectedId = $stateParams._id; @@ -327,8 +329,9 @@ module.controller('FeedListCtrl', function($scope, $stateParams, $http, $route, $scope.hasMore = data.entries.length == limit; }; if (!$scope.keywords) { - EntryService.get({ - type : $scope.selectedType, + var service = $scope.selectedType == 'feed' ? FeedService + : CategoryService; + service.entries({ id : $scope.selectedId, readType : $scope.settingsService.settings.readingMode, order : $scope.settingsService.settings.readingOrder, @@ -351,7 +354,6 @@ module.controller('FeedListCtrl', function($scope, $stateParams, $http, $route, entry : entry }); EntryService.mark({ - type : 'entry', id : entry.id, read : read }); @@ -442,13 +444,14 @@ module.controller('FeedListCtrl', function($scope, $stateParams, $http, $route, }); $scope.$on('markAll', function(event, args) { - EntryService.mark({ - type : $scope.selectedType, + var service = $scope.selectedType == 'feed' ? FeedService + : CategoryService; + service.mark({ id : $scope.selectedId, olderThan : $scope.timestamp, read : true }, function() { - SubscriptionService.init(function() { + CategoryService.init(function() { $scope.$emit('emitReload'); }); }); @@ -559,8 +562,8 @@ module.controller('SettingsCtrl', function($scope, $location, SettingsService) { }; }); -module.controller('ProfileCtrl', function($scope, $location, SessionService) { - $scope.user = SessionService.get(); +module.controller('ProfileCtrl', function($scope, $location, ProfileService) { + $scope.user = ProfileService.get(); $scope.cancel = function() { $location.path('/'); @@ -574,7 +577,7 @@ module.controller('ProfileCtrl', function($scope, $location, SessionService) { password : $scope.user.password }; - SessionService.save(o, function() { + ProfileService.save(o, function() { $location.path('/'); }); diff --git a/src/main/webapp/js/directives.js b/src/main/webapp/js/directives.js index 4e034fda..28d821bc 100644 --- a/src/main/webapp/js/directives.js +++ b/src/main/webapp/js/directives.js @@ -86,7 +86,7 @@ module.directive('category', function($compile) { restrict : 'E', replace : true, templateUrl : 'directives/category.html', - controller : function($scope, $dialog, SubscriptionService, + controller : function($scope, $dialog, FeedService, CategoryService, SettingsService) { $scope.settingsService = SettingsService; $scope.unsubscribe = function(subscription) { @@ -104,8 +104,12 @@ module.directive('category', function($compile) { $dialog.messageBox(title, msg, btns).open().then( function(result) { if (result == 'ok') { - SubscriptionService - .unsubscribe(subscription.id); + var data = { + id : subscription.id + }; + FeedService.unsubscribe(data, function() { + CategoryService.init(); + }); } }); }; @@ -114,7 +118,7 @@ module.directive('category', function($compile) { var name = window.prompt('Rename feed : ', feed.name); if (name && name != feed.name) { feed.name = name; - SubscriptionService.rename({ + FeedService.rename({ id : feed.id, name : name }); @@ -125,7 +129,7 @@ module.directive('category', function($compile) { var name = window.prompt('Rename category: ', category.name); if (name && name != category.name) { category.name = name; - SubscriptionService.renameCategory({ + CategoryService.rename({ id : category.id, name : name }); @@ -147,10 +151,10 @@ module.directive('category', function($compile) { $dialog.messageBox(title, msg, btns).open().then( function(result) { if (result == 'ok') { - SubscriptionService.deleteCategory({ + CategoryService.remove({ id : category.id }, function() { - SubscriptionService.init(); + CategoryService.init(); }); } }); @@ -158,7 +162,10 @@ module.directive('category', function($compile) { $scope.toggleCategory = function(category) { category.expanded = !category.expanded; - SubscriptionService.collapse({ + if (category.id == 'all') { + return; + } + CategoryService.collapse({ id : category.id, collapse : !category.expanded }); diff --git a/src/main/webapp/js/services.js b/src/main/webapp/js/services.js index 609c652e..e079e192 100644 --- a/src/main/webapp/js/services.js +++ b/src/main/webapp/js/services.js @@ -1,24 +1,78 @@ var module = angular.module('commafeed.services', [ 'ngResource' ]); -module.factory('SessionService', function($resource) { - var actions = { - get : { - method : 'GET', - params : { - _method : 'get' - } - }, - save : { - method : 'POST', - params : { - _method : 'save' - } - } - }; - return $resource('rest/session/:_method', {}, actions); +module.factory('ProfileService', function($resource) { + return $resource('rest/user/profile/'); }); -module.factory('SubscriptionService', function($resource, $http) { +module.factory('SettingsService', function($resource) { + var res = $resource('rest/user/settings'); + + var s = {}; + s.settings = {}; + s.save = function(callback) { + res.save(s.settings, function(data) { + if (callback) { + callback(data); + } + }); + }; + s.init = function(callback) { + res.get(function(data) { + s.settings = data; + if (callback) { + callback(data); + } + }); + }; + s.init(); + return s; +}); + +module.factory('FeedService', function($resource, $http) { + + var actions = { + entries : { + method : 'GET', + params : { + _method : 'entries' + } + }, + fetch : { + method : 'GET', + params : { + _method : 'fetch' + } + }, + mark : { + method : 'POST', + params : { + _method : 'mark' + } + }, + subscribe : { + method : 'POST', + params : { + _method : 'subscribe' + } + }, + unsubscribe : { + method : 'POST', + params : { + _method : 'unsubscribe' + } + }, + rename : { + method : 'POST', + params : { + _method : 'rename' + } + } + }; + var res = $resource('rest/feed/:_method', {}, actions); + return res; +}); + +module.factory('CategoryService', function($resource, $http) { var flatten = function(category, parentName, array) { if (!array) @@ -39,131 +93,72 @@ module.factory('SubscriptionService', function($resource, $http) { return array; }; var actions = { - fetch : { + get : { method : 'GET', params : { - _type : 'feed', - _method : 'fetch' + _method : 'get' } }, - subscribe : { - method : 'POST', + entries : { + method : 'GET', params : { - _type : 'feed', - _method : 'subscribe' + _method : 'entries' } }, - unsubscribe : { + mark : { method : 'POST', params : { - _type : 'feed', - _method : 'unsubscribe' + _method : 'mark' + } + }, + add : { + method : 'POST', + params : { + _method : 'add' + } + }, + remove : { + method : 'POST', + params : { + _method : 'delete' } }, rename : { method : 'POST', params : { - _type : 'feed', _method : 'rename' } }, collapse : { method : 'POST', params : { - _type : 'category', _method : 'collapse' } - }, - addCategory : { - method : 'POST', - params : { - _type : 'category', - _method : 'add' - } - }, - deleteCategory : { - method : 'POST', - params : { - _type : 'category', - _method : 'delete' - } - }, - renameCategory : { - method : 'POST', - params : { - _type : 'category', - _method : 'rename' - } } }; - var s = {}; - s.get = $resource('rest/subscriptions/get').get; - s.subscriptions = {}; - s.flatCategories = {}; + var res = $resource('rest/category/:_method', {}, actions); + res.subscriptions = {}; + res.flatCategories = {}; - var res = $resource('rest/subscriptions/:_type/:_method', {}, actions); - s.init = function(callback) { - s.get(function(data) { - s.subscriptions = data; - s.flatCategories = flatten(s.subscriptions); - if (callback) - callback(data); - }); - }; - s.fetch = res.fetch; - s.rename = res.rename; - s.subscribe = function(sub, callback) { - res.subscribe(sub, function(data) { - s.init(); + res.init = function(callback) { + res.get(function(data) { + res.subscriptions = data; + res.flatCategories = flatten(data); if (callback) callback(data); }); }; - var removeSubscription = function(node, subId) { - if (node.children) { - $.each(node.children, function(k, v) { - removeSubscription(v, subId); - }); - } - if (node.feeds) { - var foundAtIndex = -1; - $.each(node.feeds, function(k, v) { - if (v.id == subId) { - foundAtIndex = k; - } - }); - if (foundAtIndex > -1) { - node.feeds.splice(foundAtIndex, 1); - } - } - - }; - s.unsubscribe = function(id) { - removeSubscription(s.subscriptions, id); - res.unsubscribe({ - id : id - }); - }; - s.addCategory = function(cat, callback) { - res.addCategory(cat, function(data) { - s.init(); - if (callback) - callback(data); - }); - }; - s.deleteCategory = res.deleteCategory; - s.collapse = res.collapse; - s.init(); - return s; + res.init(); + return res; }); module.factory('EntryService', function($resource, $http) { var actions = { - get : { + search : { method : 'GET', params : { - _method : 'get' + _method : 'search' } }, mark : { @@ -173,80 +168,20 @@ module.factory('EntryService', function($resource, $http) { } } }; - var res = $resource('rest/entries/:type/:_method', {}, actions); - res.search = $resource('rest/entries/search', {}, actions).get; + var res = $resource('rest/entry/:_method', {}, actions); return res; }); -module.factory('SettingsService', function($resource) { - var s = {}; - s.settings = {}; - s.save = function(callback) { - $resource('rest/settings/save').save(s.settings, function(data) { - if (callback) { - callback(data); - } - }); - }; - s.init = function(callback) { - $resource('rest/settings/get').get(function(data) { - s.settings = data; - if (callback) { - callback(data); - } - }); - }; - s.init(); - return s; -}); - module.factory('AdminUsersService', function($resource) { - var actions = { - get : { - method : 'GET', - params : { - _method : 'get' - } - }, - getAll : { - method : 'GET', - params : { - _method : 'getAll' - }, - isArray : true - }, - save : { - method : 'POST', - params : { - _method : 'save' - } - }, - remove : { - method : 'POST', - params : { - _method : 'delete' - } - } - }; - var res = $resource('rest/admin/user/:_method', {}, actions); + var res = {}; + res.get = $resource('rest/admin/user/get/:id').get; + res.getAll = $resource('rest/admin/user/getAll').query; + res.save = $resource('rest/admin/user/save').save; + res.remove = $resource('rest/admin/user/delete').save; return res; }); module.factory('AdminSettingsService', function($resource) { - var actions = { - get : { - method : 'GET', - params : { - _method : 'get' - } - }, - save : { - method : 'POST', - params : { - _method : 'save' - } - } - }; - var res = $resource('rest/admin/settings/:_method', {}, actions); + var res = $resource('rest/admin/settings/'); return res; }); \ No newline at end of file diff --git a/src/main/webapp/templates/_subscribe.html b/src/main/webapp/templates/_subscribe.html index dd3bedcb..c04fd45a 100644 --- a/src/main/webapp/templates/_subscribe.html +++ b/src/main/webapp/templates/_subscribe.html @@ -34,7 +34,7 @@
Required
@@ -51,7 +51,7 @@

Import

-
+