mirror of
https://github.com/Athou/commafeed.git
synced 2026-03-21 21:37:29 +00:00
removed wicket and tomee, use dropwizard instead. remove wro4j, use gulp instead
This commit is contained in:
182
src/main/java/com/commafeed/CommaFeedApplication.java
Normal file
182
src/main/java/com/commafeed/CommaFeedApplication.java
Normal file
@@ -0,0 +1,182 @@
|
||||
package com.commafeed;
|
||||
|
||||
import io.dropwizard.Application;
|
||||
import io.dropwizard.assets.AssetsBundle;
|
||||
import io.dropwizard.auth.CachingAuthenticator;
|
||||
import io.dropwizard.auth.basic.BasicAuthProvider;
|
||||
import io.dropwizard.auth.basic.BasicCredentials;
|
||||
import io.dropwizard.db.DataSourceFactory;
|
||||
import io.dropwizard.hibernate.HibernateBundle;
|
||||
import io.dropwizard.migrations.MigrationsBundle;
|
||||
import io.dropwizard.setup.Bootstrap;
|
||||
import io.dropwizard.setup.Environment;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.commafeed.backend.HttpGetter;
|
||||
import com.commafeed.backend.cache.CacheService;
|
||||
import com.commafeed.backend.cache.NoopCacheService;
|
||||
import com.commafeed.backend.dao.FeedCategoryDAO;
|
||||
import com.commafeed.backend.dao.FeedDAO;
|
||||
import com.commafeed.backend.dao.FeedEntryContentDAO;
|
||||
import com.commafeed.backend.dao.FeedEntryDAO;
|
||||
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
||||
import com.commafeed.backend.dao.FeedEntryTagDAO;
|
||||
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
||||
import com.commafeed.backend.dao.UserDAO;
|
||||
import com.commafeed.backend.dao.UserRoleDAO;
|
||||
import com.commafeed.backend.dao.UserSettingsDAO;
|
||||
import com.commafeed.backend.feed.FaviconFetcher;
|
||||
import com.commafeed.backend.feed.FeedFetcher;
|
||||
import com.commafeed.backend.feed.FeedParser;
|
||||
import com.commafeed.backend.feed.FeedQueues;
|
||||
import com.commafeed.backend.feed.FeedRefreshTaskGiver;
|
||||
import com.commafeed.backend.feed.FeedRefreshUpdater;
|
||||
import com.commafeed.backend.feed.FeedRefreshWorker;
|
||||
import com.commafeed.backend.model.AbstractModel;
|
||||
import com.commafeed.backend.model.Feed;
|
||||
import com.commafeed.backend.model.FeedCategory;
|
||||
import com.commafeed.backend.model.FeedEntry;
|
||||
import com.commafeed.backend.model.FeedEntryContent;
|
||||
import com.commafeed.backend.model.FeedEntryStatus;
|
||||
import com.commafeed.backend.model.FeedEntryTag;
|
||||
import com.commafeed.backend.model.FeedSubscription;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.model.UserRole;
|
||||
import com.commafeed.backend.model.UserSettings;
|
||||
import com.commafeed.backend.opml.OPMLExporter;
|
||||
import com.commafeed.backend.opml.OPMLImporter;
|
||||
import com.commafeed.backend.service.ApplicationPropertiesService;
|
||||
import com.commafeed.backend.service.DatabaseCleaningService;
|
||||
import com.commafeed.backend.service.FeedEntryContentService;
|
||||
import com.commafeed.backend.service.FeedEntryService;
|
||||
import com.commafeed.backend.service.FeedEntryTagService;
|
||||
import com.commafeed.backend.service.FeedService;
|
||||
import com.commafeed.backend.service.FeedSubscriptionService;
|
||||
import com.commafeed.backend.service.FeedUpdateService;
|
||||
import com.commafeed.backend.service.PasswordEncryptionService;
|
||||
import com.commafeed.backend.service.PubSubService;
|
||||
import com.commafeed.backend.service.StartupService;
|
||||
import com.commafeed.backend.service.UserService;
|
||||
import com.commafeed.frontend.resource.AdminREST;
|
||||
import com.commafeed.frontend.resource.CategoryREST;
|
||||
import com.commafeed.frontend.resource.EntryREST;
|
||||
import com.commafeed.frontend.resource.FeedREST;
|
||||
import com.commafeed.frontend.resource.PubSubHubbubCallbackREST;
|
||||
import com.commafeed.frontend.resource.ServerREST;
|
||||
import com.commafeed.frontend.resource.UserREST;
|
||||
|
||||
public class CommaFeedApplication extends Application<CommaFeedConfiguration> {
|
||||
|
||||
public static final String USERNAME_ADMIN = "admin";
|
||||
public static final String USERNAME_DEMO = "demo";
|
||||
|
||||
public static final Date STARTUP_TIME = new Date();
|
||||
|
||||
private HibernateBundle<CommaFeedConfiguration> hibernateBundle;
|
||||
private MigrationsBundle<CommaFeedConfiguration> migrationsBundle;
|
||||
|
||||
@Override
|
||||
public void initialize(Bootstrap<CommaFeedConfiguration> bootstrap) {
|
||||
hibernateBundle = new HibernateBundle<CommaFeedConfiguration>(AbstractModel.class, Feed.class, FeedCategory.class, FeedEntry.class,
|
||||
FeedEntryContent.class, FeedEntryStatus.class, FeedEntryTag.class, FeedSubscription.class, User.class, UserRole.class,
|
||||
UserSettings.class) {
|
||||
@Override
|
||||
public DataSourceFactory getDataSourceFactory(CommaFeedConfiguration configuration) {
|
||||
return configuration.getDatabase();
|
||||
}
|
||||
};
|
||||
bootstrap.addBundle(hibernateBundle);
|
||||
|
||||
migrationsBundle = new MigrationsBundle<CommaFeedConfiguration>() {
|
||||
@Override
|
||||
public DataSourceFactory getDataSourceFactory(CommaFeedConfiguration configuration) {
|
||||
return configuration.getDatabase();
|
||||
}
|
||||
};
|
||||
bootstrap.addBundle(migrationsBundle);
|
||||
|
||||
bootstrap.addBundle(new AssetsBundle("/assets/", "/", "index.html"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(CommaFeedConfiguration config, Environment environment) throws Exception {
|
||||
MetricRegistry metrics = environment.metrics();
|
||||
SessionFactory sessionFactory = hibernateBundle.getSessionFactory();
|
||||
|
||||
// TODO select cache service at runtime from config
|
||||
CacheService cacheService = new NoopCacheService();
|
||||
|
||||
FeedCategoryDAO feedCategoryDAO = new FeedCategoryDAO(sessionFactory);
|
||||
FeedDAO feedDAO = new FeedDAO(sessionFactory);
|
||||
FeedEntryContentDAO feedEntryContentDAO = new FeedEntryContentDAO(sessionFactory);
|
||||
FeedEntryDAO feedEntryDAO = new FeedEntryDAO(sessionFactory);
|
||||
FeedEntryTagDAO feedEntryTagDAO = new FeedEntryTagDAO(sessionFactory);
|
||||
FeedSubscriptionDAO feedSubscriptionDAO = new FeedSubscriptionDAO(sessionFactory);
|
||||
UserDAO userDAO = new UserDAO(sessionFactory);
|
||||
UserRoleDAO userRoleDAO = new UserRoleDAO(sessionFactory);
|
||||
UserSettingsDAO userSettingsDAO = new UserSettingsDAO(sessionFactory);
|
||||
FeedEntryStatusDAO feedEntryStatusDAO = new FeedEntryStatusDAO(sessionFactory, feedEntryDAO, feedEntryTagDAO, config);
|
||||
|
||||
FeedQueues queues = new FeedQueues(feedDAO, config, metrics);
|
||||
|
||||
ApplicationPropertiesService applicationPropertiesService = new ApplicationPropertiesService();
|
||||
DatabaseCleaningService cleaningService = new DatabaseCleaningService(feedDAO, feedEntryDAO, feedEntryContentDAO,
|
||||
feedEntryStatusDAO, feedSubscriptionDAO);
|
||||
FeedEntryContentService feedEntryContentService = new FeedEntryContentService(feedEntryContentDAO);
|
||||
FeedEntryService feedEntryService = new FeedEntryService(feedSubscriptionDAO, feedEntryDAO, feedEntryStatusDAO, cacheService);
|
||||
FeedEntryTagService feedEntryTagService = new FeedEntryTagService(feedEntryDAO, feedEntryTagDAO);
|
||||
FeedService feedService = new FeedService(feedDAO);
|
||||
FeedSubscriptionService feedSubscriptionService = new FeedSubscriptionService(feedEntryStatusDAO, feedSubscriptionDAO, feedService,
|
||||
queues, cacheService, config);
|
||||
FeedUpdateService feedUpdateService = new FeedUpdateService(feedEntryDAO, feedEntryContentService);
|
||||
PasswordEncryptionService encryptionService = new PasswordEncryptionService();
|
||||
PubSubService pubSubService = new PubSubService(config, queues);
|
||||
UserService userService = new UserService(feedCategoryDAO, userDAO, userSettingsDAO, feedSubscriptionService, encryptionService,
|
||||
config);
|
||||
StartupService startupService = new StartupService(sessionFactory, userDAO, userService);
|
||||
|
||||
OPMLImporter opmlImporter = new OPMLImporter(feedCategoryDAO, feedSubscriptionService, cacheService);
|
||||
OPMLExporter opmlExporter = new OPMLExporter(feedCategoryDAO, feedSubscriptionDAO);
|
||||
|
||||
HttpGetter httpGetter = new HttpGetter();
|
||||
FeedParser feedParser = new FeedParser();
|
||||
FaviconFetcher faviconFetcher = new FaviconFetcher(httpGetter);
|
||||
|
||||
FeedFetcher feedFetcher = new FeedFetcher(feedParser, httpGetter);
|
||||
FeedRefreshUpdater feedUpdater = new FeedRefreshUpdater(sessionFactory, feedUpdateService, pubSubService, queues, config, metrics,
|
||||
feedSubscriptionDAO, cacheService);
|
||||
FeedRefreshWorker feedWorker = new FeedRefreshWorker(feedUpdater, feedFetcher, queues, config, metrics);
|
||||
FeedRefreshTaskGiver taskGiver = new FeedRefreshTaskGiver(sessionFactory, queues, feedDAO, feedWorker, config, metrics);
|
||||
|
||||
CachingAuthenticator<BasicCredentials, User> cachingAuthenticator = new CachingAuthenticator<BasicCredentials, User>(
|
||||
environment.metrics(), new CommaFeedAuthenticator(userService), config.getAuthenticationCachePolicy());
|
||||
environment.jersey().register(new BasicAuthProvider<User>(cachingAuthenticator, "CommaFeed"));
|
||||
|
||||
environment.jersey().setUrlPattern("/rest/*");
|
||||
environment.jersey()
|
||||
.register(new AdminREST(userDAO, userRoleDAO, userService, encryptionService, cleaningService, config, metrics));
|
||||
environment.jersey().register(
|
||||
new CategoryREST(feedCategoryDAO, feedEntryStatusDAO, feedSubscriptionDAO, feedEntryService, feedSubscriptionService,
|
||||
cacheService, config));
|
||||
environment.jersey().register(new EntryREST(feedEntryTagDAO, feedEntryService, feedEntryTagService));
|
||||
environment.jersey().register(
|
||||
new FeedREST(feedSubscriptionDAO, feedCategoryDAO, feedEntryStatusDAO, faviconFetcher, feedFetcher, feedEntryService,
|
||||
feedSubscriptionService, queues, opmlImporter, opmlExporter, cacheService, config));
|
||||
environment.jersey().register(new PubSubHubbubCallbackREST(feedDAO, feedParser, queues, config, metrics));
|
||||
environment.jersey().register(new ServerREST(httpGetter, config, applicationPropertiesService));
|
||||
environment.jersey().register(new UserREST(userDAO, userRoleDAO, userSettingsDAO, userService, encryptionService));
|
||||
|
||||
environment.lifecycle().manage(startupService);
|
||||
environment.lifecycle().manage(taskGiver);
|
||||
environment.lifecycle().manage(feedWorker);
|
||||
environment.lifecycle().manage(feedUpdater);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new CommaFeedApplication().run(args);
|
||||
}
|
||||
}
|
||||
21
src/main/java/com/commafeed/CommaFeedAuthenticator.java
Normal file
21
src/main/java/com/commafeed/CommaFeedAuthenticator.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package com.commafeed;
|
||||
|
||||
import io.dropwizard.auth.AuthenticationException;
|
||||
import io.dropwizard.auth.Authenticator;
|
||||
import io.dropwizard.auth.basic.BasicCredentials;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.service.UserService;
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class CommaFeedAuthenticator implements Authenticator<BasicCredentials, User> {
|
||||
|
||||
private final UserService userService;
|
||||
|
||||
@Override
|
||||
public Optional<User> authenticate(final BasicCredentials credentials) throws AuthenticationException {
|
||||
return Optional.fromNullable(userService.login(credentials.getUsername(), credentials.getPassword()));
|
||||
}
|
||||
}
|
||||
105
src/main/java/com/commafeed/CommaFeedConfiguration.java
Normal file
105
src/main/java/com/commafeed/CommaFeedConfiguration.java
Normal file
@@ -0,0 +1,105 @@
|
||||
package com.commafeed;
|
||||
|
||||
import io.dropwizard.Configuration;
|
||||
import io.dropwizard.db.DataSourceFactory;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.google.common.cache.CacheBuilderSpec;
|
||||
|
||||
@Getter
|
||||
public class CommaFeedConfiguration extends Configuration {
|
||||
|
||||
@Valid
|
||||
@NotNull
|
||||
@JsonProperty("database")
|
||||
private DataSourceFactory database = new DataSourceFactory();
|
||||
|
||||
@Valid
|
||||
@NotNull
|
||||
@JsonProperty("authenticationCachePolicy")
|
||||
private CacheBuilderSpec authenticationCachePolicy;
|
||||
|
||||
@Valid
|
||||
@NotNull
|
||||
@JsonProperty("app")
|
||||
private ApplicationSettings applicationSettings;
|
||||
|
||||
@Getter
|
||||
public static class ApplicationSettings {
|
||||
@JsonProperty
|
||||
private String publicUrl;
|
||||
|
||||
@JsonProperty
|
||||
private boolean allowRegistrations;
|
||||
|
||||
@JsonProperty
|
||||
private String googleAnalyticsTrackingCode;
|
||||
|
||||
@JsonProperty
|
||||
private String googleClientId;
|
||||
|
||||
@JsonProperty
|
||||
private String googleClientSecret;
|
||||
|
||||
@JsonProperty
|
||||
private int backgroundThreads;
|
||||
|
||||
@JsonProperty
|
||||
private int databaseUpdateThreads;
|
||||
|
||||
@JsonProperty
|
||||
private String smtpHost;
|
||||
|
||||
@JsonProperty
|
||||
private int smtpPort;
|
||||
|
||||
@JsonProperty
|
||||
private boolean smtpTls;
|
||||
|
||||
@JsonProperty
|
||||
private String smtpUserName;
|
||||
|
||||
@JsonProperty
|
||||
private String smtpPassword;
|
||||
|
||||
@JsonProperty
|
||||
private boolean heavyLoad;
|
||||
|
||||
@JsonProperty
|
||||
private boolean pubsubhubbub;
|
||||
|
||||
@JsonProperty
|
||||
private boolean imageProxyEnabled;
|
||||
|
||||
@JsonProperty
|
||||
private int queryTimeout;
|
||||
|
||||
@JsonProperty
|
||||
private boolean crawlingPaused;
|
||||
|
||||
@JsonProperty
|
||||
private int keepStatusDays;
|
||||
|
||||
@JsonProperty
|
||||
private int refreshIntervalMinutes;
|
||||
|
||||
@JsonProperty
|
||||
private String announcement;
|
||||
|
||||
public Date getUnreadThreshold() {
|
||||
int keepStatusDays = getKeepStatusDays();
|
||||
return keepStatusDays > 0 ? DateUtils.addDays(new Date(), -1 * keepStatusDays) : null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.http.Consts;
|
||||
import org.apache.http.Header;
|
||||
@@ -42,7 +43,6 @@ import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.apache.wicket.util.io.IOUtils;
|
||||
|
||||
/**
|
||||
* Smart HTTP getter: handles gzip, ssl, last modified and etag headers
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
package com.commafeed.backend;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.ejb.Schedule;
|
||||
import javax.ejb.Stateless;
|
||||
import javax.ejb.TransactionManagement;
|
||||
import javax.ejb.TransactionManagementType;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.commafeed.backend.services.ApplicationSettingsService;
|
||||
import com.commafeed.backend.services.DatabaseCleaningService;
|
||||
|
||||
/**
|
||||
* Contains all scheduled tasks
|
||||
*
|
||||
*/
|
||||
@Stateless
|
||||
@TransactionManagement(TransactionManagementType.BEAN)
|
||||
public class ScheduledTasks {
|
||||
|
||||
@Inject
|
||||
ApplicationSettingsService applicationSettingsService;
|
||||
|
||||
@Inject
|
||||
DatabaseCleaningService cleaner;
|
||||
|
||||
/**
|
||||
* clean old read statuses
|
||||
*/
|
||||
@Schedule(hour = "*", persistent = false)
|
||||
private void cleanupOldStatuses() {
|
||||
Date threshold = applicationSettingsService.getUnreadThreshold();
|
||||
if (threshold != null) {
|
||||
cleaner.cleanStatusesOlderThan(threshold);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clean feeds without subscriptions, then clean contents without entries
|
||||
*/
|
||||
@Schedule(hour = "*", persistent = false)
|
||||
private void cleanFeedsAndContents() {
|
||||
cleaner.cleanEntriesWithoutSubscriptions();
|
||||
cleaner.cleanFeedsWithoutSubscriptions();
|
||||
cleaner.cleanContentsWithoutEntries();
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,12 @@ package com.commafeed.backend.cache;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
import javax.enterprise.inject.Alternative;
|
||||
|
||||
import com.commafeed.backend.model.Feed;
|
||||
import com.commafeed.backend.model.FeedSubscription;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.frontend.model.Category;
|
||||
import com.commafeed.frontend.model.UnreadCount;
|
||||
|
||||
@Alternative
|
||||
@ApplicationScoped
|
||||
public class NoopCacheService extends CacheService {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,13 +4,10 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
import javax.enterprise.inject.Alternative;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.pool.impl.GenericObjectPool;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
@@ -26,8 +23,6 @@ import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
@Alternative
|
||||
@ApplicationScoped
|
||||
@Slf4j
|
||||
public class RedisCacheService extends CacheService {
|
||||
|
||||
@@ -35,8 +30,7 @@ public class RedisCacheService extends CacheService {
|
||||
|
||||
private JedisPool pool;
|
||||
|
||||
@PostConstruct
|
||||
private void init() {
|
||||
public RedisCacheService() {
|
||||
JedisPoolConfig config = new JedisPoolConfig();
|
||||
config.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_GROW);
|
||||
pool = new JedisPool(config, "localhost");
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
package com.commafeed.backend.dao;
|
||||
|
||||
import javax.ejb.Stateless;
|
||||
|
||||
import com.commafeed.backend.model.ApplicationSettings;
|
||||
|
||||
@Stateless
|
||||
public class ApplicationSettingsDAO extends GenericDAO<ApplicationSettings> {
|
||||
|
||||
}
|
||||
@@ -2,91 +2,50 @@ package com.commafeed.backend.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.ejb.Stateless;
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Join;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.apache.commons.lang.ObjectUtils;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.commafeed.backend.model.FeedCategory;
|
||||
import com.commafeed.backend.model.FeedCategory_;
|
||||
import com.commafeed.backend.model.QFeedCategory;
|
||||
import com.commafeed.backend.model.QUser;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.model.User_;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mysema.query.types.Predicate;
|
||||
|
||||
@Stateless
|
||||
public class FeedCategoryDAO extends GenericDAO<FeedCategory> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private QFeedCategory category = QFeedCategory.feedCategory;
|
||||
|
||||
public FeedCategoryDAO(SessionFactory sessionFactory) {
|
||||
super(sessionFactory);
|
||||
}
|
||||
|
||||
public List<FeedCategory> findAll(User user) {
|
||||
|
||||
CriteriaQuery<FeedCategory> query = builder.createQuery(getType());
|
||||
Root<FeedCategory> root = query.from(getType());
|
||||
Join<FeedCategory, User> userJoin = (Join<FeedCategory, User>) root.fetch(FeedCategory_.user);
|
||||
|
||||
query.where(builder.equal(userJoin.get(User_.id), user.getId()));
|
||||
|
||||
return cache(em.createQuery(query)).getResultList();
|
||||
return newQuery().from(category).where(category.user.eq(user)).join(category.user, QUser.user).fetch().list(category);
|
||||
}
|
||||
|
||||
public FeedCategory findById(User user, Long id) {
|
||||
CriteriaQuery<FeedCategory> query = builder.createQuery(getType());
|
||||
Root<FeedCategory> root = query.from(getType());
|
||||
|
||||
Predicate p1 = builder.equal(root.get(FeedCategory_.user).get(User_.id), user.getId());
|
||||
Predicate p2 = builder.equal(root.get(FeedCategory_.id), id);
|
||||
|
||||
query.where(p1, p2);
|
||||
|
||||
return Iterables.getFirst(cache(em.createQuery(query)).getResultList(), null);
|
||||
return newQuery().from(category).where(category.user.eq(user), category.id.eq(id)).uniqueResult(category);
|
||||
}
|
||||
|
||||
public FeedCategory findByName(User user, String name, FeedCategory parent) {
|
||||
CriteriaQuery<FeedCategory> query = builder.createQuery(getType());
|
||||
Root<FeedCategory> root = query.from(getType());
|
||||
|
||||
List<Predicate> predicates = Lists.newArrayList();
|
||||
|
||||
predicates.add(builder.equal(root.get(FeedCategory_.user), user));
|
||||
predicates.add(builder.equal(root.get(FeedCategory_.name), name));
|
||||
|
||||
Predicate parentPredicate = null;
|
||||
if (parent == null) {
|
||||
predicates.add(builder.isNull(root.get(FeedCategory_.parent)));
|
||||
parentPredicate = category.parent.isNull();
|
||||
} else {
|
||||
predicates.add(builder.equal(root.get(FeedCategory_.parent), parent));
|
||||
parentPredicate = category.parent.eq(parent);
|
||||
}
|
||||
|
||||
query.where(predicates.toArray(new Predicate[0]));
|
||||
|
||||
FeedCategory category = null;
|
||||
try {
|
||||
category = em.createQuery(query).getSingleResult();
|
||||
} catch (NoResultException e) {
|
||||
category = null;
|
||||
}
|
||||
return category;
|
||||
return newQuery().from(category).where(category.user.eq(user), category.name.eq(name), parentPredicate).uniqueResult(category);
|
||||
}
|
||||
|
||||
public List<FeedCategory> findByParent(User user, FeedCategory parent) {
|
||||
CriteriaQuery<FeedCategory> query = builder.createQuery(getType());
|
||||
Root<FeedCategory> root = query.from(getType());
|
||||
|
||||
List<Predicate> predicates = Lists.newArrayList();
|
||||
|
||||
predicates.add(builder.equal(root.get(FeedCategory_.user), user));
|
||||
Predicate parentPredicate = null;
|
||||
if (parent == null) {
|
||||
predicates.add(builder.isNull(root.get(FeedCategory_.parent)));
|
||||
parentPredicate = category.parent.isNull();
|
||||
} else {
|
||||
predicates.add(builder.equal(root.get(FeedCategory_.parent), parent));
|
||||
parentPredicate = category.parent.eq(parent);
|
||||
}
|
||||
|
||||
query.where(predicates.toArray(new Predicate[0]));
|
||||
|
||||
return em.createQuery(query).getResultList();
|
||||
return newQuery().from(category).where(category.user.eq(user), parentPredicate).list(category);
|
||||
}
|
||||
|
||||
public List<FeedCategory> findAllChildrenCategories(User user, FeedCategory parent) {
|
||||
|
||||
@@ -3,104 +3,75 @@ package com.commafeed.backend.dao;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.ejb.Stateless;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Join;
|
||||
import javax.persistence.criteria.JoinType;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.persistence.criteria.SetJoin;
|
||||
import javax.persistence.criteria.Subquery;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.commafeed.backend.feeds.FeedUtils;
|
||||
import com.commafeed.backend.model.Feed;
|
||||
import com.commafeed.backend.model.FeedSubscription;
|
||||
import com.commafeed.backend.model.FeedSubscription_;
|
||||
import com.commafeed.backend.model.Feed_;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.model.User_;
|
||||
import com.commafeed.backend.model.QFeed;
|
||||
import com.commafeed.backend.model.QFeedSubscription;
|
||||
import com.commafeed.backend.model.QUser;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mysema.query.BooleanBuilder;
|
||||
import com.mysema.query.jpa.hibernate.HibernateQuery;
|
||||
import com.mysema.query.jpa.hibernate.HibernateSubQuery;
|
||||
|
||||
@Stateless
|
||||
public class FeedDAO extends GenericDAO<Feed> {
|
||||
|
||||
private List<Predicate> getUpdatablePredicates(CriteriaQuery<?> query, Root<Feed> root, Date lastLoginThreshold) {
|
||||
private QFeed feed = QFeed.feed;
|
||||
|
||||
List<Predicate> preds = Lists.newArrayList();
|
||||
Predicate isNull = builder.isNull(root.get(Feed_.disabledUntil));
|
||||
Predicate lessThan = builder.lessThan(root.get(Feed_.disabledUntil), new Date());
|
||||
preds.add(builder.or(isNull, lessThan));
|
||||
|
||||
if (lastLoginThreshold != null) {
|
||||
Subquery<Long> subquery = query.subquery(Long.class);
|
||||
Root<FeedSubscription> subroot = subquery.from(FeedSubscription.class);
|
||||
subquery.select(builder.count(subroot.get(FeedSubscription_.id)));
|
||||
|
||||
Join<FeedSubscription, User> userJoin = subroot.join(FeedSubscription_.user);
|
||||
Predicate p1 = builder.equal(subroot.get(FeedSubscription_.feed), root);
|
||||
Predicate p2 = builder.greaterThanOrEqualTo(userJoin.get(User_.lastLogin), lastLoginThreshold);
|
||||
subquery.where(p1, p2);
|
||||
|
||||
preds.add(builder.exists(subquery));
|
||||
}
|
||||
|
||||
return preds;
|
||||
public FeedDAO(SessionFactory sessionFactory) {
|
||||
super(sessionFactory);
|
||||
}
|
||||
|
||||
public Long getUpdatableCount(Date lastLoginThreshold) {
|
||||
CriteriaQuery<Long> query = builder.createQuery(Long.class);
|
||||
Root<Feed> root = query.from(getType());
|
||||
BooleanBuilder disabledDatePredicate = new BooleanBuilder();
|
||||
disabledDatePredicate.or(feed.disabledUntil.isNull());
|
||||
disabledDatePredicate.or(feed.disabledUntil.lt(new Date()));
|
||||
|
||||
query.select(builder.count(root));
|
||||
query.where(getUpdatablePredicates(query, root, lastLoginThreshold).toArray(new Predicate[0]));
|
||||
|
||||
TypedQuery<Long> q = em.createQuery(query);
|
||||
return q.getSingleResult();
|
||||
HibernateQuery query = newQuery().from(feed).where(disabledDatePredicate);
|
||||
if (lastLoginThreshold != null) {
|
||||
QFeedSubscription sub = QFeedSubscription.feedSubscription;
|
||||
QUser user = QUser.user;
|
||||
HibernateSubQuery subquery = new HibernateSubQuery();
|
||||
subquery.from(sub).join(sub.user, user).where(sub.feed.eq(feed), user.lastLogin.gt(lastLoginThreshold));
|
||||
query.where(subquery.exists());
|
||||
}
|
||||
return query.orderBy(feed.disabledUntil.asc()).count();
|
||||
}
|
||||
|
||||
public List<Feed> findNextUpdatable(int count, Date lastLoginThreshold) {
|
||||
CriteriaQuery<Feed> query = builder.createQuery(getType());
|
||||
Root<Feed> root = query.from(getType());
|
||||
BooleanBuilder disabledDatePredicate = new BooleanBuilder();
|
||||
disabledDatePredicate.or(feed.disabledUntil.isNull());
|
||||
disabledDatePredicate.or(feed.disabledUntil.lt(new Date()));
|
||||
|
||||
query.where(getUpdatablePredicates(query, root, lastLoginThreshold).toArray(new Predicate[0]));
|
||||
query.orderBy(builder.asc(root.get(Feed_.disabledUntil)));
|
||||
|
||||
TypedQuery<Feed> q = em.createQuery(query);
|
||||
q.setMaxResults(count);
|
||||
|
||||
return q.getResultList();
|
||||
}
|
||||
|
||||
public Feed findByUrl(String url) {
|
||||
|
||||
String normalized = FeedUtils.normalizeURL(url);
|
||||
List<Feed> feeds = findByField(Feed_.normalizedUrlHash, DigestUtils.sha1Hex(normalized));
|
||||
Feed feed = Iterables.getFirst(feeds, null);
|
||||
if (feed != null && StringUtils.equals(normalized, feed.getNormalizedUrl())) {
|
||||
return feed;
|
||||
HibernateQuery query = newQuery().from(feed).where(disabledDatePredicate);
|
||||
if (lastLoginThreshold != null) {
|
||||
QFeedSubscription sub = QFeedSubscription.feedSubscription;
|
||||
QUser user = QUser.user;
|
||||
HibernateSubQuery subquery = new HibernateSubQuery();
|
||||
subquery.from(sub).join(sub.user, user).where(sub.feed.eq(feed), user.lastLogin.gt(lastLoginThreshold));
|
||||
query.where(subquery.exists());
|
||||
}
|
||||
|
||||
return query.orderBy(feed.disabledUntil.asc()).limit(count).list(feed);
|
||||
}
|
||||
|
||||
public Feed findByUrl(String normalizedUrl) {
|
||||
List<Feed> feeds = newQuery().from(feed).where(feed.normalizedUrlHash.eq(DigestUtils.sha1Hex(normalizedUrl))).list(feed);
|
||||
Feed feed = Iterables.getFirst(feeds, null);
|
||||
if (feed != null && StringUtils.equals(normalizedUrl, feed.getNormalizedUrl())) {
|
||||
return feed;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<Feed> findByTopic(String topic) {
|
||||
return findByField(Feed_.pushTopicHash, DigestUtils.sha1Hex(topic));
|
||||
return newQuery().from(feed).where(feed.pushTopicHash.eq(DigestUtils.sha1Hex(topic))).list(feed);
|
||||
}
|
||||
|
||||
|
||||
public List<Feed> findWithoutSubscriptions(int max) {
|
||||
CriteriaQuery<Feed> query = builder.createQuery(getType());
|
||||
Root<Feed> root = query.from(getType());
|
||||
|
||||
SetJoin<Feed, FeedSubscription> join = root.join(Feed_.subscriptions, JoinType.LEFT);
|
||||
query.where(builder.isNull(join.get(FeedSubscription_.id)));
|
||||
TypedQuery<Feed> q = em.createQuery(query);
|
||||
q.setMaxResults(max);
|
||||
|
||||
return q.getResultList();
|
||||
QFeedSubscription sub = QFeedSubscription.feedSubscription;
|
||||
return newQuery().from(feed).leftJoin(feed.subscriptions, sub).where(sub.id.isNull()).limit(max).list(feed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,52 +2,34 @@ package com.commafeed.backend.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.ejb.Stateless;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Join;
|
||||
import javax.persistence.criteria.JoinType;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.commafeed.backend.model.FeedEntry;
|
||||
import com.commafeed.backend.model.FeedEntryContent;
|
||||
import com.commafeed.backend.model.FeedEntryContent_;
|
||||
import com.commafeed.backend.model.FeedEntry_;
|
||||
import com.commafeed.backend.model.QFeedEntry;
|
||||
import com.commafeed.backend.model.QFeedEntryContent;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.mysema.query.types.ConstructorExpression;
|
||||
|
||||
@Stateless
|
||||
public class FeedEntryContentDAO extends GenericDAO<FeedEntryContent> {
|
||||
|
||||
private QFeedEntryContent content = QFeedEntryContent.feedEntryContent;
|
||||
|
||||
public FeedEntryContentDAO(SessionFactory sessionFactory) {
|
||||
super(sessionFactory);
|
||||
}
|
||||
|
||||
public Long findExisting(String contentHash, String titleHash) {
|
||||
|
||||
CriteriaQuery<Long> query = builder.createQuery(Long.class);
|
||||
Root<FeedEntryContent> root = query.from(getType());
|
||||
query.select(root.get(FeedEntryContent_.id));
|
||||
|
||||
Predicate p1 = builder.equal(root.get(FeedEntryContent_.contentHash), contentHash);
|
||||
Predicate p2 = builder.equal(root.get(FeedEntryContent_.titleHash), titleHash);
|
||||
|
||||
query.where(p1, p2);
|
||||
TypedQuery<Long> q = em.createQuery(query);
|
||||
limit(q, 0, 1);
|
||||
return Iterables.getFirst(q.getResultList(), null);
|
||||
|
||||
List<Long> list = newQuery().from(content).where(content.contentHash.eq(contentHash), content.titleHash.eq(titleHash)).limit(1)
|
||||
.list(ConstructorExpression.create(Long.class, content.id));
|
||||
return Iterables.getFirst(list, null);
|
||||
}
|
||||
|
||||
public int deleteWithoutEntries(int max) {
|
||||
CriteriaQuery<FeedEntryContent> query = builder.createQuery(getType());
|
||||
Root<FeedEntryContent> root = query.from(getType());
|
||||
|
||||
Join<FeedEntryContent, FeedEntry> join = root.join(FeedEntryContent_.entries, JoinType.LEFT);
|
||||
query.where(builder.isNull(join.get(FeedEntry_.id)));
|
||||
TypedQuery<FeedEntryContent> q = em.createQuery(query);
|
||||
q.setMaxResults(max);
|
||||
|
||||
List<FeedEntryContent> list = q.getResultList();
|
||||
QFeedEntry entry = QFeedEntry.feedEntry;
|
||||
List<FeedEntryContent> list = newQuery().from(content).leftJoin(content.entries, entry).where(entry.id.isNull()).limit(max)
|
||||
.list(content);
|
||||
int deleted = list.size();
|
||||
delete(list);
|
||||
return deleted;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,82 +3,47 @@ package com.commafeed.backend.dao;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.ejb.Stateless;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Join;
|
||||
import javax.persistence.criteria.JoinType;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.persistence.criteria.SetJoin;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.commafeed.backend.model.Feed;
|
||||
import com.commafeed.backend.model.FeedEntry;
|
||||
import com.commafeed.backend.model.FeedEntry_;
|
||||
import com.commafeed.backend.model.FeedSubscription;
|
||||
import com.commafeed.backend.model.FeedSubscription_;
|
||||
import com.commafeed.backend.model.Feed_;
|
||||
import com.commafeed.backend.model.QFeed;
|
||||
import com.commafeed.backend.model.QFeedEntry;
|
||||
import com.commafeed.backend.model.QFeedSubscription;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.mysema.query.types.ConstructorExpression;
|
||||
|
||||
@Stateless
|
||||
public class FeedEntryDAO extends GenericDAO<FeedEntry> {
|
||||
|
||||
public Long findExisting(String guid, Long feedId) {
|
||||
private QFeedEntry entry = QFeedEntry.feedEntry;
|
||||
|
||||
CriteriaQuery<Long> query = builder.createQuery(Long.class);
|
||||
Root<FeedEntry> root = query.from(getType());
|
||||
query.select(root.get(FeedEntry_.id));
|
||||
public FeedEntryDAO(SessionFactory sessionFactory) {
|
||||
super(sessionFactory);
|
||||
}
|
||||
|
||||
Predicate p1 = builder.equal(root.get(FeedEntry_.guidHash), DigestUtils.sha1Hex(guid));
|
||||
Predicate p2 = builder.equal(root.get(FeedEntry_.feed).get(Feed_.id), feedId);
|
||||
|
||||
query.where(p1, p2);
|
||||
|
||||
TypedQuery<Long> q = em.createQuery(query);
|
||||
limit(q, 0, 1);
|
||||
List<Long> list = q.getResultList();
|
||||
public Long findExisting(String guid, Feed feed) {
|
||||
List<Long> list = newQuery().from(entry).where(entry.guidHash.eq(DigestUtils.sha1Hex(guid)), entry.feed.eq(feed)).limit(1)
|
||||
.list(ConstructorExpression.create(Long.class, entry.id));
|
||||
return Iterables.getFirst(list, null);
|
||||
}
|
||||
|
||||
public List<FeedEntry> findWithoutSubscriptions(int max) {
|
||||
CriteriaQuery<FeedEntry> query = builder.createQuery(getType());
|
||||
Root<FeedEntry> root = query.from(getType());
|
||||
|
||||
Join<FeedEntry, Feed> feedJoin = root.join(FeedEntry_.feed);
|
||||
SetJoin<Feed, FeedSubscription> subJoin = feedJoin.join(Feed_.subscriptions, JoinType.LEFT);
|
||||
query.where(builder.isNull(subJoin.get(FeedSubscription_.id)));
|
||||
TypedQuery<FeedEntry> q = em.createQuery(query);
|
||||
q.setMaxResults(max);
|
||||
|
||||
return q.getResultList();
|
||||
QFeed feed = QFeed.feed;
|
||||
QFeedSubscription sub = QFeedSubscription.feedSubscription;
|
||||
return newQuery().from(entry).join(entry.feed, feed).leftJoin(feed.subscriptions, sub).where(sub.id.isNull()).limit(max)
|
||||
.list(entry);
|
||||
}
|
||||
|
||||
public int delete(Feed feed, int max) {
|
||||
|
||||
CriteriaQuery<FeedEntry> query = builder.createQuery(getType());
|
||||
Root<FeedEntry> root = query.from(getType());
|
||||
|
||||
query.where(builder.equal(root.get(FeedEntry_.feed), feed));
|
||||
TypedQuery<FeedEntry> q = em.createQuery(query);
|
||||
q.setMaxResults(max);
|
||||
|
||||
List<FeedEntry> list = q.getResultList();
|
||||
List<FeedEntry> list = newQuery().from(entry).where(entry.feed.eq(feed)).limit(max).list(entry);
|
||||
int deleted = list.size();
|
||||
delete(list);
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public int delete(Date olderThan, int max) {
|
||||
CriteriaQuery<FeedEntry> query = builder.createQuery(getType());
|
||||
Root<FeedEntry> root = query.from(getType());
|
||||
query.where(builder.lessThan(root.get(FeedEntry_.inserted), olderThan));
|
||||
|
||||
TypedQuery<FeedEntry> q = em.createQuery(query);
|
||||
q.setMaxResults(max);
|
||||
List<FeedEntry> list = q.getResultList();
|
||||
|
||||
List<FeedEntry> list = newQuery().from(entry).where(entry.inserted.lt(olderThan)).limit(max).list(entry);
|
||||
int deleted = list.size();
|
||||
delete(list);
|
||||
return deleted;
|
||||
|
||||
@@ -5,18 +5,10 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.ejb.Stateless;
|
||||
import javax.inject.Inject;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Path;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang3.builder.CompareToBuilder;
|
||||
import org.apache.commons.lang.builder.CompareToBuilder;
|
||||
import org.hibernate.Criteria;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.criterion.Conjunction;
|
||||
import org.hibernate.criterion.Disjunction;
|
||||
import org.hibernate.criterion.MatchMode;
|
||||
@@ -27,33 +19,44 @@ import org.hibernate.criterion.Restrictions;
|
||||
import org.hibernate.sql.JoinType;
|
||||
import org.hibernate.transform.Transformers;
|
||||
|
||||
import com.commafeed.CommaFeedConfiguration;
|
||||
import com.commafeed.backend.FixedSizeSortedSet;
|
||||
import com.commafeed.backend.model.FeedEntry;
|
||||
import com.commafeed.backend.model.FeedEntryContent_;
|
||||
import com.commafeed.backend.model.FeedEntryStatus;
|
||||
import com.commafeed.backend.model.FeedEntryStatus_;
|
||||
import com.commafeed.backend.model.FeedEntryTag;
|
||||
import com.commafeed.backend.model.FeedEntryTag_;
|
||||
import com.commafeed.backend.model.FeedEntry_;
|
||||
import com.commafeed.backend.model.FeedSubscription;
|
||||
import com.commafeed.backend.model.Models;
|
||||
import com.commafeed.backend.model.QFeedEntry;
|
||||
import com.commafeed.backend.model.QFeedEntryContent;
|
||||
import com.commafeed.backend.model.QFeedEntryStatus;
|
||||
import com.commafeed.backend.model.QFeedEntryTag;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.model.UserSettings.ReadingOrder;
|
||||
import com.commafeed.backend.services.ApplicationSettingsService;
|
||||
import com.commafeed.frontend.model.UnreadCount;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.mysema.query.jpa.hibernate.HibernateQuery;
|
||||
|
||||
@Stateless
|
||||
public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
||||
|
||||
private static final String ALIAS_STATUS = "status";
|
||||
private static final String ALIAS_ENTRY = "entry";
|
||||
private static final String ALIAS_TAG = "tag";
|
||||
|
||||
@Inject
|
||||
FeedEntryTagDAO feedEntryTagDAO;
|
||||
private FeedEntryDAO feedEntryDAO;
|
||||
private FeedEntryTagDAO feedEntryTagDAO;
|
||||
private CommaFeedConfiguration config;
|
||||
|
||||
private QFeedEntryStatus status = QFeedEntryStatus.feedEntryStatus;
|
||||
|
||||
public FeedEntryStatusDAO(SessionFactory sessionFactory, FeedEntryDAO feedEntryDAO, FeedEntryTagDAO feedEntryTagDAO,
|
||||
CommaFeedConfiguration config) {
|
||||
super(sessionFactory);
|
||||
this.feedEntryDAO = feedEntryDAO;
|
||||
this.feedEntryTagDAO = feedEntryTagDAO;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
private static final Comparator<FeedEntryStatus> STATUS_COMPARATOR_DESC = new Comparator<FeedEntryStatus>() {
|
||||
@Override
|
||||
@@ -61,34 +64,21 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
||||
CompareToBuilder builder = new CompareToBuilder();
|
||||
builder.append(o2.getEntryUpdated(), o1.getEntryUpdated());
|
||||
builder.append(o2.getId(), o1.getId());
|
||||
return builder.build();
|
||||
return builder.toComparison();
|
||||
};
|
||||
};
|
||||
|
||||
private static final Comparator<FeedEntryStatus> STATUS_COMPARATOR_ASC = Ordering.from(STATUS_COMPARATOR_DESC).reverse();
|
||||
|
||||
@Inject
|
||||
ApplicationSettingsService applicationSettingsService;
|
||||
|
||||
public FeedEntryStatus getStatus(User user, FeedSubscription sub, FeedEntry entry) {
|
||||
|
||||
CriteriaQuery<FeedEntryStatus> query = builder.createQuery(getType());
|
||||
Root<FeedEntryStatus> root = query.from(getType());
|
||||
|
||||
Predicate p1 = builder.equal(root.get(FeedEntryStatus_.entry), entry);
|
||||
Predicate p2 = builder.equal(root.get(FeedEntryStatus_.subscription), sub);
|
||||
|
||||
query.where(p1, p2);
|
||||
|
||||
List<FeedEntryStatus> statuses = em.createQuery(query).getResultList();
|
||||
List<FeedEntryStatus> statuses = newQuery().from(status).where(status.entry.eq(entry), status.subscription.eq(sub)).list(status);
|
||||
FeedEntryStatus status = Iterables.getFirst(statuses, null);
|
||||
|
||||
return handleStatus(user, status, sub, entry);
|
||||
}
|
||||
|
||||
private FeedEntryStatus handleStatus(User user, FeedEntryStatus status, FeedSubscription sub, FeedEntry entry) {
|
||||
if (status == null) {
|
||||
Date unreadThreshold = applicationSettingsService.getUnreadThreshold();
|
||||
Date unreadThreshold = config.getApplicationSettings().getUnreadThreshold();
|
||||
boolean read = unreadThreshold == null ? false : entry.getUpdated().before(unreadThreshold);
|
||||
status = new FeedEntryStatus(user, sub, entry);
|
||||
status.setRead(read);
|
||||
@@ -106,27 +96,20 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
||||
}
|
||||
|
||||
public List<FeedEntryStatus> findStarred(User user, Date newerThan, int offset, int limit, ReadingOrder order, boolean includeContent) {
|
||||
|
||||
CriteriaQuery<FeedEntryStatus> query = builder.createQuery(getType());
|
||||
Root<FeedEntryStatus> root = query.from(getType());
|
||||
|
||||
List<Predicate> predicates = Lists.newArrayList();
|
||||
|
||||
predicates.add(builder.equal(root.get(FeedEntryStatus_.user), user));
|
||||
predicates.add(builder.equal(root.get(FeedEntryStatus_.starred), true));
|
||||
|
||||
HibernateQuery query = newQuery().from(status).where(status.user.eq(user), status.starred.isTrue());
|
||||
if (newerThan != null) {
|
||||
predicates.add(builder.greaterThanOrEqualTo(root.get(FeedEntryStatus_.entryInserted), newerThan));
|
||||
query.where(status.entryInserted.gt(newerThan));
|
||||
}
|
||||
|
||||
query.where(predicates.toArray(new Predicate[0]));
|
||||
|
||||
orderStatusesBy(query, root, order);
|
||||
if (order == ReadingOrder.asc) {
|
||||
query.orderBy(status.entryUpdated.asc(), status.id.asc());
|
||||
} else {
|
||||
query.orderBy(status.entryUpdated.desc(), status.id.desc());
|
||||
}
|
||||
|
||||
TypedQuery<FeedEntryStatus> q = em.createQuery(query);
|
||||
limit(q, offset, limit);
|
||||
setTimeout(q);
|
||||
List<FeedEntryStatus> statuses = q.getResultList();
|
||||
query.offset(offset).limit(limit).setTimeout(config.getApplicationSettings().getQueryTimeout());
|
||||
|
||||
List<FeedEntryStatus> statuses = query.list(status);
|
||||
for (FeedEntryStatus status : statuses) {
|
||||
status = handleStatus(user, status, status.getSubscription(), status.getEntry());
|
||||
status = fetchTags(user, status);
|
||||
@@ -134,62 +117,66 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
||||
return lazyLoadContent(includeContent, statuses);
|
||||
}
|
||||
|
||||
private Criteria buildSearchCriteria(User user, FeedSubscription sub, boolean unreadOnly, String keywords, Date newerThan, int offset, int limit,
|
||||
ReadingOrder order, Date last, String tag) {
|
||||
Criteria criteria = getSession().createCriteria(FeedEntry.class, ALIAS_ENTRY);
|
||||
private Criteria buildSearchCriteria(User user, FeedSubscription sub, boolean unreadOnly, String keywords, Date newerThan, int offset,
|
||||
int limit, ReadingOrder order, Date last, String tag) {
|
||||
QFeedEntry entry = QFeedEntry.feedEntry;
|
||||
QFeedEntryContent content = QFeedEntryContent.feedEntryContent;
|
||||
QFeedEntryStatus status = QFeedEntryStatus.feedEntryStatus;
|
||||
QFeedEntryTag entryTag = QFeedEntryTag.feedEntryTag;
|
||||
|
||||
criteria.add(Restrictions.eq(FeedEntry_.feed.getName(), sub.getFeed()));
|
||||
Criteria criteria = currentSession().createCriteria(FeedEntry.class, ALIAS_ENTRY);
|
||||
criteria.add(Restrictions.eq(entry.feed.getMetadata().getName(), sub.getFeed()));
|
||||
|
||||
if (keywords != null) {
|
||||
Criteria contentJoin = criteria.createCriteria(FeedEntry_.content.getName(), "content", JoinType.INNER_JOIN);
|
||||
Criteria contentJoin = criteria.createCriteria(entry.content.getMetadata().getName(), "content", JoinType.INNER_JOIN);
|
||||
|
||||
for (String keyword : StringUtils.split(keywords)) {
|
||||
Disjunction or = Restrictions.disjunction();
|
||||
or.add(Restrictions.ilike(FeedEntryContent_.content.getName(), keyword, MatchMode.ANYWHERE));
|
||||
or.add(Restrictions.ilike(FeedEntryContent_.title.getName(), keyword, MatchMode.ANYWHERE));
|
||||
or.add(Restrictions.ilike(content.content.getMetadata().getName(), keyword, MatchMode.ANYWHERE));
|
||||
or.add(Restrictions.ilike(content.title.getMetadata().getName(), keyword, MatchMode.ANYWHERE));
|
||||
contentJoin.add(or);
|
||||
}
|
||||
}
|
||||
Criteria statusJoin = criteria.createCriteria(FeedEntry_.statuses.getName(), ALIAS_STATUS, JoinType.LEFT_OUTER_JOIN,
|
||||
Restrictions.eq(FeedEntryStatus_.subscription.getName(), sub));
|
||||
Criteria statusJoin = criteria.createCriteria(entry.statuses.getMetadata().getName(), ALIAS_STATUS, JoinType.LEFT_OUTER_JOIN,
|
||||
Restrictions.eq(status.subscription.getMetadata().getName(), sub));
|
||||
|
||||
if (unreadOnly && tag == null) {
|
||||
|
||||
Disjunction or = Restrictions.disjunction();
|
||||
or.add(Restrictions.isNull(FeedEntryStatus_.read.getName()));
|
||||
or.add(Restrictions.eq(FeedEntryStatus_.read.getName(), false));
|
||||
or.add(Restrictions.isNull(status.read.getMetadata().getName()));
|
||||
or.add(Restrictions.eq(status.read.getMetadata().getName(), false));
|
||||
statusJoin.add(or);
|
||||
|
||||
Date unreadThreshold = applicationSettingsService.getUnreadThreshold();
|
||||
Date unreadThreshold = config.getApplicationSettings().getUnreadThreshold();
|
||||
if (unreadThreshold != null) {
|
||||
criteria.add(Restrictions.ge(FeedEntry_.updated.getName(), unreadThreshold));
|
||||
criteria.add(Restrictions.ge(entry.updated.getMetadata().getName(), unreadThreshold));
|
||||
}
|
||||
}
|
||||
|
||||
if (tag != null) {
|
||||
Conjunction and = Restrictions.conjunction();
|
||||
and.add(Restrictions.eq(FeedEntryTag_.user.getName(), user));
|
||||
and.add(Restrictions.eq(FeedEntryTag_.name.getName(), tag));
|
||||
criteria.createCriteria(FeedEntry_.tags.getName(), ALIAS_TAG, JoinType.INNER_JOIN, and);
|
||||
and.add(Restrictions.eq(entryTag.user.getMetadata().getName(), user));
|
||||
and.add(Restrictions.eq(entryTag.name.getMetadata().getName(), tag));
|
||||
criteria.createCriteria(entry.tags.getMetadata().getName(), ALIAS_TAG, JoinType.INNER_JOIN, and);
|
||||
}
|
||||
|
||||
if (newerThan != null) {
|
||||
criteria.add(Restrictions.ge(FeedEntry_.inserted.getName(), newerThan));
|
||||
criteria.add(Restrictions.ge(entry.inserted.getMetadata().getName(), newerThan));
|
||||
}
|
||||
|
||||
if (last != null) {
|
||||
if (order == ReadingOrder.desc) {
|
||||
criteria.add(Restrictions.gt(FeedEntry_.updated.getName(), last));
|
||||
criteria.add(Restrictions.gt(entry.updated.getMetadata().getName(), last));
|
||||
} else {
|
||||
criteria.add(Restrictions.lt(FeedEntry_.updated.getName(), last));
|
||||
criteria.add(Restrictions.lt(entry.updated.getMetadata().getName(), last));
|
||||
}
|
||||
}
|
||||
|
||||
if (order != null) {
|
||||
if (order == ReadingOrder.asc) {
|
||||
criteria.addOrder(Order.asc(FeedEntry_.updated.getName())).addOrder(Order.asc(FeedEntry_.id.getName()));
|
||||
criteria.addOrder(Order.asc(entry.updated.getMetadata().getName())).addOrder(Order.asc(entry.id.getMetadata().getName()));
|
||||
} else {
|
||||
criteria.addOrder(Order.desc(FeedEntry_.updated.getName())).addOrder(Order.desc(FeedEntry_.id.getName()));
|
||||
criteria.addOrder(Order.desc(entry.updated.getMetadata().getName())).addOrder(Order.desc(entry.id.getMetadata().getName()));
|
||||
}
|
||||
}
|
||||
if (offset > -1) {
|
||||
@@ -198,7 +185,7 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
||||
if (limit > -1) {
|
||||
criteria.setMaxResults(limit);
|
||||
}
|
||||
int timeout = applicationSettingsService.get().getQueryTimeout();
|
||||
int timeout = config.getApplicationSettings().getQueryTimeout();
|
||||
if (timeout > 0) {
|
||||
// hibernate timeout is in seconds, jpa timeout is in millis
|
||||
criteria.setTimeout(timeout / 1000);
|
||||
@@ -255,7 +242,7 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
||||
statuses = Lists.newArrayList();
|
||||
for (FeedEntryStatus placeholder : placeholders) {
|
||||
Long statusId = placeholder.getId();
|
||||
FeedEntry entry = em.find(FeedEntry.class, placeholder.getEntry().getId());
|
||||
FeedEntry entry = feedEntryDAO.findById(placeholder.getEntry().getId());
|
||||
FeedEntryStatus status = handleStatus(user, statusId == null ? null : findById(statusId), placeholder.getSubscription(),
|
||||
entry);
|
||||
status = fetchTags(user, status);
|
||||
@@ -272,7 +259,7 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
||||
Criteria criteria = buildSearchCriteria(user, subscription, true, null, null, -1, -1, null, null, null);
|
||||
ProjectionList projection = Projections.projectionList();
|
||||
projection.add(Projections.rowCount(), "count");
|
||||
projection.add(Projections.max(FeedEntry_.updated.getName()), "updated");
|
||||
projection.add(Projections.max(QFeedEntry.feedEntry.updated.getMetadata().getName()), "updated");
|
||||
criteria.setProjection(projection);
|
||||
criteria.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
|
||||
List<Map<String, Object>> list = criteria.list();
|
||||
@@ -294,35 +281,8 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
||||
return results;
|
||||
}
|
||||
|
||||
private void orderStatusesBy(CriteriaQuery<?> query, Path<FeedEntryStatus> statusJoin, ReadingOrder order) {
|
||||
orderBy(query, statusJoin.get(FeedEntryStatus_.entryUpdated), statusJoin.get(FeedEntryStatus_.id), order);
|
||||
}
|
||||
|
||||
private void orderBy(CriteriaQuery<?> query, Path<Date> date, Path<Long> id, ReadingOrder order) {
|
||||
if (order != null) {
|
||||
if (order == ReadingOrder.asc) {
|
||||
query.orderBy(builder.asc(date), builder.asc(id));
|
||||
} else {
|
||||
query.orderBy(builder.desc(date), builder.desc(id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void setTimeout(Query query) {
|
||||
setTimeout(query, applicationSettingsService.get().getQueryTimeout());
|
||||
}
|
||||
|
||||
public List<FeedEntryStatus> getOldStatuses(Date olderThan, int limit) {
|
||||
CriteriaQuery<FeedEntryStatus> query = builder.createQuery(getType());
|
||||
Root<FeedEntryStatus> root = query.from(getType());
|
||||
|
||||
Predicate p1 = builder.lessThan(root.get(FeedEntryStatus_.entryInserted), olderThan);
|
||||
Predicate p2 = builder.isFalse(root.get(FeedEntryStatus_.starred));
|
||||
|
||||
query.where(p1, p2);
|
||||
TypedQuery<FeedEntryStatus> q = em.createQuery(query);
|
||||
q.setMaxResults(limit);
|
||||
return q.getResultList();
|
||||
return newQuery().from(status).where(status.entryInserted.lt(olderThan), status.starred.isFalse()).limit(limit).list(status);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,42 +2,27 @@ package com.commafeed.backend.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.ejb.Stateless;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.commafeed.backend.model.FeedEntry;
|
||||
import com.commafeed.backend.model.FeedEntryTag;
|
||||
import com.commafeed.backend.model.FeedEntryTag_;
|
||||
import com.commafeed.backend.model.FeedEntry_;
|
||||
import com.commafeed.backend.model.QFeedEntryTag;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.model.User_;
|
||||
import com.mysema.query.types.ConstructorExpression;
|
||||
|
||||
@Stateless
|
||||
public class FeedEntryTagDAO extends GenericDAO<FeedEntryTag> {
|
||||
|
||||
private QFeedEntryTag tag = QFeedEntryTag.feedEntryTag;
|
||||
|
||||
public FeedEntryTagDAO(SessionFactory sessionFactory) {
|
||||
super(sessionFactory);
|
||||
}
|
||||
|
||||
public List<String> findByUser(User user) {
|
||||
CriteriaQuery<String> query = builder.createQuery(String.class);
|
||||
Root<FeedEntryTag> root = query.from(getType());
|
||||
query.select(root.get(FeedEntryTag_.name));
|
||||
query.distinct(true);
|
||||
|
||||
Predicate p1 = builder.equal(root.get(FeedEntryTag_.user).get(User_.id), user.getId());
|
||||
query.where(p1);
|
||||
|
||||
return cache(em.createQuery(query)).getResultList();
|
||||
return newQuery().from(tag).where(tag.user.eq(user)).distinct().list(ConstructorExpression.create(String.class, tag.name));
|
||||
}
|
||||
|
||||
public List<FeedEntryTag> findByEntry(User user, FeedEntry entry) {
|
||||
CriteriaQuery<FeedEntryTag> query = builder.createQuery(getType());
|
||||
Root<FeedEntryTag> root = query.from(getType());
|
||||
|
||||
Predicate p1 = builder.equal(root.get(FeedEntryTag_.user).get(User_.id), user.getId());
|
||||
Predicate p2 = builder.equal(root.get(FeedEntryTag_.entry).get(FeedEntry_.id), entry.getId());
|
||||
|
||||
query.where(p1, p2);
|
||||
|
||||
return cache(em.createQuery(query)).getResultList();
|
||||
return newQuery().from(tag).where(tag.user.eq(user), tag.entry.eq(entry)).list(tag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,110 +2,59 @@ package com.commafeed.backend.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.ejb.Stateless;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.JoinType;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.commafeed.backend.model.Feed;
|
||||
import com.commafeed.backend.model.FeedCategory;
|
||||
import com.commafeed.backend.model.FeedCategory_;
|
||||
import com.commafeed.backend.model.FeedSubscription;
|
||||
import com.commafeed.backend.model.FeedSubscription_;
|
||||
import com.commafeed.backend.model.Feed_;
|
||||
import com.commafeed.backend.model.Models;
|
||||
import com.commafeed.backend.model.QFeedSubscription;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.model.User_;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mysema.query.jpa.hibernate.HibernateQuery;
|
||||
|
||||
@Stateless
|
||||
public class FeedSubscriptionDAO extends GenericDAO<FeedSubscription> {
|
||||
|
||||
private QFeedSubscription sub = QFeedSubscription.feedSubscription;
|
||||
|
||||
public FeedSubscriptionDAO(SessionFactory sessionFactory) {
|
||||
super(sessionFactory);
|
||||
}
|
||||
|
||||
public FeedSubscription findById(User user, Long id) {
|
||||
CriteriaQuery<FeedSubscription> query = builder.createQuery(getType());
|
||||
Root<FeedSubscription> root = query.from(getType());
|
||||
|
||||
Predicate p1 = builder.equal(root.get(FeedSubscription_.user).get(User_.id), user.getId());
|
||||
Predicate p2 = builder.equal(root.get(FeedSubscription_.id), id);
|
||||
|
||||
root.fetch(FeedSubscription_.feed, JoinType.LEFT);
|
||||
root.fetch(FeedSubscription_.category, JoinType.LEFT);
|
||||
|
||||
query.where(p1, p2);
|
||||
|
||||
FeedSubscription sub = Iterables.getFirst(cache(em.createQuery(query)).getResultList(), null);
|
||||
initRelations(sub);
|
||||
return sub;
|
||||
List<FeedSubscription> subs = newQuery().from(sub).where(sub.user.eq(user), sub.id.eq(id)).leftJoin(sub.feed).fetch()
|
||||
.leftJoin(sub.category).fetch().list(sub);
|
||||
return initRelations(Iterables.getFirst(subs, null));
|
||||
}
|
||||
|
||||
public List<FeedSubscription> findByFeed(Feed feed) {
|
||||
CriteriaQuery<FeedSubscription> query = builder.createQuery(getType());
|
||||
Root<FeedSubscription> root = query.from(getType());
|
||||
|
||||
query.where(builder.equal(root.get(FeedSubscription_.feed), feed));
|
||||
List<FeedSubscription> list = cache(em.createQuery(query)).getResultList();
|
||||
return list;
|
||||
return newQuery().from(sub).where(sub.feed.eq(feed)).list(sub);
|
||||
}
|
||||
|
||||
public FeedSubscription findByFeed(User user, Feed feed) {
|
||||
|
||||
CriteriaQuery<FeedSubscription> query = builder.createQuery(getType());
|
||||
Root<FeedSubscription> root = query.from(getType());
|
||||
|
||||
Predicate p1 = builder.equal(root.get(FeedSubscription_.user).get(User_.id), user.getId());
|
||||
Predicate p2 = builder.equal(root.get(FeedSubscription_.feed).get(Feed_.id), feed.getId());
|
||||
|
||||
root.fetch(FeedSubscription_.feed, JoinType.LEFT);
|
||||
root.fetch(FeedSubscription_.category, JoinType.LEFT);
|
||||
|
||||
query.where(p1, p2);
|
||||
|
||||
FeedSubscription sub = Iterables.getFirst(cache(em.createQuery(query)).getResultList(), null);
|
||||
initRelations(sub);
|
||||
return sub;
|
||||
List<FeedSubscription> subs = newQuery().from(sub).where(sub.user.eq(user), sub.feed.eq(feed)).list(sub);
|
||||
return initRelations(Iterables.getFirst(subs, null));
|
||||
}
|
||||
|
||||
public List<FeedSubscription> findAll(User user) {
|
||||
|
||||
CriteriaQuery<FeedSubscription> query = builder.createQuery(getType());
|
||||
Root<FeedSubscription> root = query.from(getType());
|
||||
|
||||
root.fetch(FeedSubscription_.feed, JoinType.LEFT);
|
||||
root.fetch(FeedSubscription_.category, JoinType.LEFT);
|
||||
|
||||
query.where(builder.equal(root.get(FeedSubscription_.user).get(User_.id), user.getId()));
|
||||
|
||||
List<FeedSubscription> list = cache(em.createQuery(query)).getResultList();
|
||||
initRelations(list);
|
||||
return list;
|
||||
List<FeedSubscription> subs = newQuery().from(sub).where(sub.user.eq(user)).leftJoin(sub.feed).fetch().leftJoin(sub.category)
|
||||
.fetch().list(sub);
|
||||
return initRelations(subs);
|
||||
}
|
||||
|
||||
public List<FeedSubscription> findByCategory(User user, FeedCategory category) {
|
||||
|
||||
CriteriaQuery<FeedSubscription> query = builder.createQuery(getType());
|
||||
Root<FeedSubscription> root = query.from(getType());
|
||||
|
||||
Predicate p1 = builder.equal(root.get(FeedSubscription_.user).get(User_.id), user.getId());
|
||||
Predicate p2 = null;
|
||||
HibernateQuery query = newQuery().from(sub).where(sub.user.eq(user));
|
||||
if (category == null) {
|
||||
p2 = builder.isNull(root.get(FeedSubscription_.category));
|
||||
query.where(sub.category.isNull());
|
||||
} else {
|
||||
p2 = builder.equal(root.get(FeedSubscription_.category).get(FeedCategory_.id), category.getId());
|
||||
|
||||
query.where(sub.category.eq(category));
|
||||
}
|
||||
|
||||
query.where(p1, p2);
|
||||
|
||||
List<FeedSubscription> list = cache(em.createQuery(query)).getResultList();
|
||||
initRelations(list);
|
||||
return list;
|
||||
return initRelations(query.list(sub));
|
||||
}
|
||||
|
||||
public List<FeedSubscription> findByCategories(User user, List<FeedCategory> categories) {
|
||||
|
||||
List<Long> categoryIds = Lists.transform(categories, new Function<FeedCategory, Long>() {
|
||||
@Override
|
||||
public Long apply(FeedCategory input) {
|
||||
@@ -122,16 +71,18 @@ public class FeedSubscriptionDAO extends GenericDAO<FeedSubscription> {
|
||||
return subscriptions;
|
||||
}
|
||||
|
||||
private void initRelations(List<FeedSubscription> list) {
|
||||
private List<FeedSubscription> initRelations(List<FeedSubscription> list) {
|
||||
for (FeedSubscription sub : list) {
|
||||
initRelations(sub);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private void initRelations(FeedSubscription sub) {
|
||||
private FeedSubscription initRelations(FeedSubscription sub) {
|
||||
if (sub != null) {
|
||||
Models.initialize(sub.getFeed());
|
||||
Models.initialize(sub.getCategory());
|
||||
}
|
||||
return sub;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,160 +1,59 @@
|
||||
package com.commafeed.backend.dao;
|
||||
|
||||
import java.util.Arrays;
|
||||
import io.dropwizard.hibernate.AbstractDAO;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.persistence.metamodel.Attribute;
|
||||
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.commafeed.backend.model.AbstractModel;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.mysema.query.jpa.hibernate.HibernateQuery;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class GenericDAO<T extends AbstractModel> {
|
||||
public abstract class GenericDAO<T extends AbstractModel> extends AbstractDAO<T> {
|
||||
|
||||
private TypeToken<T> type = new TypeToken<T>(getClass()) {
|
||||
};
|
||||
|
||||
@PersistenceContext
|
||||
protected EntityManager em;
|
||||
|
||||
protected CriteriaBuilder builder;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
builder = em.getCriteriaBuilder();
|
||||
public GenericDAO(SessionFactory sessionFactory) {
|
||||
super(sessionFactory);
|
||||
}
|
||||
|
||||
public Session getSession() {
|
||||
Session session = em.unwrap(Session.class);
|
||||
return session;
|
||||
protected HibernateQuery newQuery() {
|
||||
return new HibernateQuery(currentSession());
|
||||
}
|
||||
|
||||
public void saveOrUpdate(Collection<? extends AbstractModel> models) {
|
||||
Session session = getSession();
|
||||
int i = 1;
|
||||
for (AbstractModel model : models) {
|
||||
session.saveOrUpdate(model);
|
||||
if (i % 50 == 0) {
|
||||
session.flush();
|
||||
session.clear();
|
||||
}
|
||||
public void saveOrUpdate(T model) {
|
||||
persist(model);
|
||||
}
|
||||
|
||||
public void saveOrUpdate(Collection<T> models) {
|
||||
for (T model : models) {
|
||||
persist(model);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveOrUpdate(AbstractModel... models) {
|
||||
saveOrUpdate(Arrays.asList(models));
|
||||
public void merge(T model) {
|
||||
currentSession().merge(model);
|
||||
}
|
||||
|
||||
public void delete(AbstractModel object) {
|
||||
if (object != null) {
|
||||
object = em.merge(object);
|
||||
em.remove(object);
|
||||
}
|
||||
}
|
||||
|
||||
public int delete(Collection<? extends AbstractModel> objects) {
|
||||
for (AbstractModel object : objects) {
|
||||
delete(object);
|
||||
}
|
||||
return objects.size();
|
||||
}
|
||||
|
||||
public void deleteById(Long id) {
|
||||
Object ref = em.getReference(getType(), id);
|
||||
if (ref != null) {
|
||||
em.remove(ref);
|
||||
public void merge(Collection<T> models) {
|
||||
for (T model : models) {
|
||||
merge(model);
|
||||
}
|
||||
}
|
||||
|
||||
public T findById(Long id) {
|
||||
T t = em.find(getType(), id);
|
||||
return t;
|
||||
return get(id);
|
||||
}
|
||||
|
||||
public List<T> findAll() {
|
||||
CriteriaQuery<T> query = builder.createQuery(getType());
|
||||
query.from(getType());
|
||||
return em.createQuery(query).getResultList();
|
||||
}
|
||||
|
||||
public List<T> findAll(int startIndex, int count) {
|
||||
CriteriaQuery<T> query = builder.createQuery(getType());
|
||||
query.from(getType());
|
||||
TypedQuery<T> q = em.createQuery(query);
|
||||
q.setMaxResults(count);
|
||||
q.setFirstResult(startIndex);
|
||||
return q.getResultList();
|
||||
}
|
||||
|
||||
public List<T> findAll(int startIndex, int count, String orderBy, boolean asc) {
|
||||
|
||||
CriteriaQuery<T> query = builder.createQuery(getType());
|
||||
Root<T> root = query.from(getType());
|
||||
|
||||
if (asc) {
|
||||
query.orderBy(builder.asc(root.get(orderBy)));
|
||||
} else {
|
||||
query.orderBy(builder.desc(root.get(orderBy)));
|
||||
}
|
||||
|
||||
TypedQuery<T> q = em.createQuery(query);
|
||||
q.setMaxResults(count);
|
||||
q.setFirstResult(startIndex);
|
||||
return q.getResultList();
|
||||
}
|
||||
|
||||
public long getCount() {
|
||||
CriteriaBuilder builder = em.getCriteriaBuilder();
|
||||
CriteriaQuery<Long> query = builder.createQuery(Long.class);
|
||||
Root<T> root = query.from(getType());
|
||||
query.select(builder.count(root));
|
||||
return em.createQuery(query).getSingleResult();
|
||||
}
|
||||
|
||||
protected <V> List<T> findByField(Attribute<T, V> field, V value) {
|
||||
return findByField(field, value, false);
|
||||
}
|
||||
|
||||
protected <V> List<T> findByField(Attribute<T, V> field, V value, boolean cache) {
|
||||
CriteriaQuery<T> query = builder.createQuery(getType());
|
||||
Root<T> root = query.from(getType());
|
||||
|
||||
query.where(builder.equal(root.get(field.getName()), value));
|
||||
TypedQuery<T> q = em.createQuery(query);
|
||||
if (cache) {
|
||||
cache(q);
|
||||
}
|
||||
return em.createQuery(query).getResultList();
|
||||
}
|
||||
|
||||
protected <Q> void limit(TypedQuery<Q> query, int offset, int limit) {
|
||||
if (offset > -1) {
|
||||
query.setFirstResult(offset);
|
||||
}
|
||||
if (limit > -1) {
|
||||
query.setMaxResults(limit);
|
||||
public void delete(T object) {
|
||||
if (object != null) {
|
||||
currentSession().delete(object);
|
||||
}
|
||||
}
|
||||
|
||||
protected <Q> TypedQuery<Q> readOnly(TypedQuery<Q> query) {
|
||||
query.unwrap(Query.class).setReadOnly(true);
|
||||
return query;
|
||||
}
|
||||
|
||||
protected <Q> TypedQuery<Q> cache(TypedQuery<Q> query) {
|
||||
query.unwrap(Query.class).setCacheable(true);
|
||||
return query;
|
||||
public int delete(Collection<T> objects) {
|
||||
for (T object : objects) {
|
||||
delete(object);
|
||||
}
|
||||
return objects.size();
|
||||
}
|
||||
|
||||
protected void setTimeout(javax.persistence.Query query, int queryTimeout) {
|
||||
@@ -162,9 +61,4 @@ public abstract class GenericDAO<T extends AbstractModel> {
|
||||
query.setHint("javax.persistence.query.timeout", queryTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Class<T> getType() {
|
||||
return (Class<T>) type.getRawType();
|
||||
}
|
||||
}
|
||||
|
||||
60
src/main/java/com/commafeed/backend/dao/UnitOfWork.java
Normal file
60
src/main/java/com/commafeed/backend/dao/UnitOfWork.java
Normal file
@@ -0,0 +1,60 @@
|
||||
package com.commafeed.backend.dao;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.context.internal.ManagedSessionContext;
|
||||
|
||||
public abstract class UnitOfWork<T> {
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
public UnitOfWork(SessionFactory sessionFactory) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
protected abstract T runInSession() throws Exception;
|
||||
|
||||
public T run() {
|
||||
final Session session = sessionFactory.openSession();
|
||||
if (ManagedSessionContext.hasBind(sessionFactory)) {
|
||||
throw new IllegalStateException("Already in a unit of work!");
|
||||
}
|
||||
T t = null;
|
||||
try {
|
||||
ManagedSessionContext.bind(session);
|
||||
session.beginTransaction();
|
||||
try {
|
||||
t = runInSession();
|
||||
commitTransaction(session);
|
||||
} catch (Exception e) {
|
||||
rollbackTransaction(session);
|
||||
this.<RuntimeException> rethrow(e);
|
||||
}
|
||||
} finally {
|
||||
session.close();
|
||||
ManagedSessionContext.unbind(sessionFactory);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
private void rollbackTransaction(Session session) {
|
||||
final Transaction txn = session.getTransaction();
|
||||
if (txn != null && txn.isActive()) {
|
||||
txn.rollback();
|
||||
}
|
||||
}
|
||||
|
||||
private void commitTransaction(Session session) {
|
||||
final Transaction txn = session.getTransaction();
|
||||
if (txn != null && txn.isActive()) {
|
||||
txn.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <E extends Exception> void rethrow(Exception e) throws E {
|
||||
throw (E) e;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,68 +1,27 @@
|
||||
package com.commafeed.backend.dao;
|
||||
|
||||
import javax.ejb.Stateless;
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.commafeed.backend.model.QUser;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.model.User_;
|
||||
|
||||
@Stateless
|
||||
public class UserDAO extends GenericDAO<User> {
|
||||
|
||||
private QUser user = QUser.user;
|
||||
|
||||
public UserDAO(SessionFactory sessionFactory) {
|
||||
super(sessionFactory);
|
||||
}
|
||||
|
||||
public User findByName(String name) {
|
||||
|
||||
CriteriaQuery<User> query = builder.createQuery(getType());
|
||||
Root<User> root = query.from(getType());
|
||||
query.where(builder.equal(builder.lower(root.get(User_.name)), name.toLowerCase()));
|
||||
TypedQuery<User> q = em.createQuery(query);
|
||||
cache(q);
|
||||
|
||||
User user = null;
|
||||
try {
|
||||
user = q.getSingleResult();
|
||||
} catch (NoResultException e) {
|
||||
user = null;
|
||||
}
|
||||
return user;
|
||||
return newQuery().from(user).where(user.name.equalsIgnoreCase(name)).uniqueResult(user);
|
||||
}
|
||||
|
||||
public User findByApiKey(String key) {
|
||||
CriteriaQuery<User> query = builder.createQuery(getType());
|
||||
Root<User> root = query.from(getType());
|
||||
query.where(builder.equal(root.get(User_.apiKey), key));
|
||||
TypedQuery<User> q = em.createQuery(query);
|
||||
cache(q);
|
||||
|
||||
User user = null;
|
||||
try {
|
||||
user = q.getSingleResult();
|
||||
} catch (NoResultException e) {
|
||||
user = null;
|
||||
}
|
||||
return user;
|
||||
return newQuery().from(user).where(user.apiKey.equalsIgnoreCase(key)).uniqueResult(user);
|
||||
}
|
||||
|
||||
public User findByEmail(String email) {
|
||||
if (StringUtils.isBlank(email)) {
|
||||
return null;
|
||||
}
|
||||
CriteriaQuery<User> query = builder.createQuery(getType());
|
||||
Root<User> root = query.from(getType());
|
||||
query.where(builder.equal(root.get(User_.email), email));
|
||||
TypedQuery<User> q = em.createQuery(query);
|
||||
|
||||
User user = null;
|
||||
try {
|
||||
user = q.getSingleResult();
|
||||
} catch (NoResultException e) {
|
||||
user = null;
|
||||
}
|
||||
return user;
|
||||
return newQuery().from(user).where(user.email.equalsIgnoreCase(email)).uniqueResult(user);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,38 +3,28 @@ package com.commafeed.backend.dao;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ejb.Stateless;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.JoinType;
|
||||
import javax.persistence.criteria.Root;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.commafeed.backend.model.QUserRole;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.model.UserRole;
|
||||
import com.commafeed.backend.model.UserRole.Role;
|
||||
import com.commafeed.backend.model.UserRole_;
|
||||
import com.commafeed.backend.model.User_;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
@Stateless
|
||||
public class UserRoleDAO extends GenericDAO<UserRole> {
|
||||
|
||||
@Override
|
||||
private QUserRole role = QUserRole.userRole;
|
||||
|
||||
public UserRoleDAO(SessionFactory sessionFactory) {
|
||||
super(sessionFactory);
|
||||
}
|
||||
|
||||
public List<UserRole> findAll() {
|
||||
CriteriaQuery<UserRole> query = builder.createQuery(getType());
|
||||
Root<UserRole> root = query.from(getType());
|
||||
query.distinct(true);
|
||||
|
||||
root.fetch(UserRole_.user, JoinType.LEFT);
|
||||
|
||||
return em.createQuery(query).getResultList();
|
||||
return newQuery().from(role).leftJoin(role.user).fetch().distinct().list(role);
|
||||
}
|
||||
|
||||
public List<UserRole> findAll(User user) {
|
||||
CriteriaQuery<UserRole> query = builder.createQuery(getType());
|
||||
Root<UserRole> root = query.from(getType());
|
||||
|
||||
query.where(builder.equal(root.get(UserRole_.user).get(User_.id), user.getId()));
|
||||
return cache(em.createQuery(query)).getResultList();
|
||||
return newQuery().from(role).where(role.user.eq(user)).distinct().list(role);
|
||||
}
|
||||
|
||||
public Set<Role> findRoles(User user) {
|
||||
|
||||
@@ -1,31 +1,18 @@
|
||||
package com.commafeed.backend.dao;
|
||||
|
||||
import javax.ejb.Stateless;
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Root;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.model.UserSettings;
|
||||
import com.commafeed.backend.model.UserSettings_;
|
||||
import com.commafeed.backend.model.User_;
|
||||
|
||||
@Stateless
|
||||
public class UserSettingsDAO extends GenericDAO<UserSettings> {
|
||||
|
||||
public UserSettingsDAO(SessionFactory sessionFactory) {
|
||||
super(sessionFactory);
|
||||
}
|
||||
|
||||
public UserSettings findByUser(User user) {
|
||||
|
||||
CriteriaQuery<UserSettings> query = builder.createQuery(getType());
|
||||
Root<UserSettings> root = query.from(getType());
|
||||
|
||||
query.where(builder.equal(root.get(UserSettings_.user).get(User_.id), user.getId()));
|
||||
|
||||
UserSettings settings = null;
|
||||
try {
|
||||
settings = cache(em.createQuery(query)).getSingleResult();
|
||||
} catch (NoResultException e) {
|
||||
settings = null;
|
||||
}
|
||||
return settings;
|
||||
return uniqueResult(criteria().add(Restrictions.eq("user", user)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package com.commafeed.backend.feeds;
|
||||
package com.commafeed.backend.feed;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.select.Elements;
|
||||
@@ -20,6 +19,7 @@ import com.commafeed.backend.HttpGetter.HttpResult;
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
public class FaviconFetcher {
|
||||
|
||||
private static long MIN_ICON_LENGTH = 100;
|
||||
@@ -30,8 +30,7 @@ public class FaviconFetcher {
|
||||
"text/ico", "application/ico", "image/x-ms-bmp", "image/x-bmp", "image/gif", "image/png", "image/jpeg");
|
||||
private static List<String> ICON_MIMETYPE_BLACKLIST = Arrays.asList("application/xml", "text/html");
|
||||
|
||||
@Inject
|
||||
HttpGetter getter;
|
||||
private final HttpGetter getter;
|
||||
|
||||
public byte[] fetch(String url) {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package com.commafeed.backend.feeds;
|
||||
package com.commafeed.backend.feed;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.codec.binary.StringUtils;
|
||||
@@ -21,13 +20,11 @@ import com.commafeed.backend.model.Feed;
|
||||
import com.sun.syndication.io.FeedException;
|
||||
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
public class FeedFetcher {
|
||||
|
||||
@Inject
|
||||
FeedParser parser;
|
||||
|
||||
@Inject
|
||||
HttpGetter getter;
|
||||
private final FeedParser parser;
|
||||
private final HttpGetter getter;
|
||||
|
||||
public FetchedFeed fetch(String feedUrl, boolean extractFeedUrlFromHtml, String lastModified, String eTag, Date lastPublishedDate,
|
||||
String lastContentHash) throws FeedException, ClientProtocolException, IOException, NotModifiedException {
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.commafeed.backend.feeds;
|
||||
package com.commafeed.backend.feed;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.text.DateFormat;
|
||||
@@ -1,71 +1,41 @@
|
||||
package com.commafeed.backend.feeds;
|
||||
package com.commafeed.backend.feed;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
|
||||
import com.codahale.metrics.Gauge;
|
||||
import com.codahale.metrics.Meter;
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.commafeed.CommaFeedConfiguration;
|
||||
import com.commafeed.backend.dao.FeedDAO;
|
||||
import com.commafeed.backend.model.Feed;
|
||||
import com.commafeed.backend.services.ApplicationSettingsService;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Queues;
|
||||
|
||||
/**
|
||||
* Infinite loop fetching feeds from the database and queuing them to the {@link FeedRefreshWorker} pool. Also handles feed database updates
|
||||
* at the end of the cycle through {@link #giveBack(Feed)}.
|
||||
*
|
||||
*/
|
||||
@ApplicationScoped
|
||||
@Slf4j
|
||||
public class FeedRefreshTaskGiver {
|
||||
public class FeedQueues {
|
||||
|
||||
@Inject
|
||||
FeedDAO feedDAO;
|
||||
|
||||
@Inject
|
||||
ApplicationSettingsService applicationSettingsService;
|
||||
|
||||
@Inject
|
||||
MetricRegistry metrics;
|
||||
|
||||
@Inject
|
||||
FeedRefreshWorker worker;
|
||||
|
||||
private int backgroundThreads;
|
||||
private final FeedDAO feedDAO;
|
||||
private final CommaFeedConfiguration config;
|
||||
|
||||
private Queue<FeedRefreshContext> addQueue = Queues.newConcurrentLinkedQueue();
|
||||
private Queue<FeedRefreshContext> takeQueue = Queues.newConcurrentLinkedQueue();
|
||||
private Queue<Feed> giveBackQueue = Queues.newConcurrentLinkedQueue();
|
||||
|
||||
private ExecutorService executor;
|
||||
|
||||
private Meter feedRefreshed;
|
||||
private Meter threadWaited;
|
||||
private Meter refill;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
backgroundThreads = applicationSettingsService.get().getBackgroundThreads();
|
||||
executor = Executors.newFixedThreadPool(1);
|
||||
feedRefreshed = metrics.meter(MetricRegistry.name(getClass(), "feedRefreshed"));
|
||||
threadWaited = metrics.meter(MetricRegistry.name(getClass(), "threadWaited"));
|
||||
@Inject
|
||||
public FeedQueues(FeedDAO feedDAO, CommaFeedConfiguration config, MetricRegistry metrics) {
|
||||
this.config = config;
|
||||
this.feedDAO = feedDAO;
|
||||
|
||||
refill = metrics.meter(MetricRegistry.name(getClass(), "refill"));
|
||||
metrics.register(MetricRegistry.name(getClass(), "addQueue"), new Gauge<Integer>() {
|
||||
@Override
|
||||
@@ -87,56 +57,10 @@ public class FeedRefreshTaskGiver {
|
||||
});
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void shutdown() {
|
||||
executor.shutdownNow();
|
||||
while (!executor.isTerminated()) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
log.error("interrupted while waiting for threads to finish.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void start() {
|
||||
log.info("starting feed refresh task giver");
|
||||
executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// sleeping for a little while, let everything settle
|
||||
Thread.sleep(60000);
|
||||
} catch (InterruptedException e) {
|
||||
log.error("interrupted while sleeping");
|
||||
}
|
||||
while (!executor.isShutdown()) {
|
||||
try {
|
||||
FeedRefreshContext context = take();
|
||||
if (context != null) {
|
||||
feedRefreshed.mark();
|
||||
worker.updateFeed(context);
|
||||
} else {
|
||||
log.debug("nothing to do, sleeping for 15s");
|
||||
threadWaited.mark();
|
||||
try {
|
||||
Thread.sleep(15000);
|
||||
} catch (InterruptedException e) {
|
||||
log.error("interrupted while sleeping");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* take a feed from the refresh queue
|
||||
*/
|
||||
private FeedRefreshContext take() {
|
||||
public synchronized FeedRefreshContext take() {
|
||||
FeedRefreshContext context = takeQueue.poll();
|
||||
|
||||
if (context == null) {
|
||||
@@ -146,15 +70,11 @@ public class FeedRefreshTaskGiver {
|
||||
return context;
|
||||
}
|
||||
|
||||
public Long getUpdatableCount() {
|
||||
return feedDAO.getUpdatableCount(getLastLoginThreshold());
|
||||
}
|
||||
|
||||
/**
|
||||
* add a feed to the refresh queue
|
||||
*/
|
||||
public void add(Feed feed, boolean urgent) {
|
||||
int refreshInterval = applicationSettingsService.get().getRefreshIntervalMinutes();
|
||||
int refreshInterval = config.getApplicationSettings().getRefreshIntervalMinutes();
|
||||
if (feed.getLastUpdated() == null || feed.getLastUpdated().before(DateUtils.addMinutes(new Date(), -1 * refreshInterval))) {
|
||||
addQueue.add(new FeedRefreshContext(feed, urgent));
|
||||
}
|
||||
@@ -167,7 +87,7 @@ public class FeedRefreshTaskGiver {
|
||||
refill.mark();
|
||||
|
||||
List<FeedRefreshContext> contexts = Lists.newArrayList();
|
||||
int batchSize = Math.min(100, 3 * backgroundThreads);
|
||||
int batchSize = Math.min(100, 3 * config.getApplicationSettings().getBackgroundThreads());
|
||||
|
||||
// add feeds we got from the add() method
|
||||
int addQueueSize = addQueue.size();
|
||||
@@ -176,7 +96,7 @@ public class FeedRefreshTaskGiver {
|
||||
}
|
||||
|
||||
// add feeds that are up to refresh from the database
|
||||
if (!applicationSettingsService.get().isCrawlingPaused()) {
|
||||
if (!config.getApplicationSettings().isCrawlingPaused()) {
|
||||
int count = batchSize - contexts.size();
|
||||
if (count > 0) {
|
||||
List<Feed> feeds = feedDAO.findNextUpdatable(count, getLastLoginThreshold());
|
||||
@@ -186,12 +106,12 @@ public class FeedRefreshTaskGiver {
|
||||
}
|
||||
}
|
||||
|
||||
// set the disabledDate to now as we use the disabledDate in feedDAO to decide what to refresh next. We also use a map to remove
|
||||
// set the disabledDate as we use it in feedDAO to decide what to refresh next. We also use a map to remove
|
||||
// duplicates.
|
||||
Map<Long, FeedRefreshContext> map = Maps.newLinkedHashMap();
|
||||
for (FeedRefreshContext context : contexts) {
|
||||
Feed feed = context.getFeed();
|
||||
feed.setDisabledUntil(new Date());
|
||||
feed.setDisabledUntil(DateUtils.addMinutes(new Date(), config.getApplicationSettings().getRefreshIntervalMinutes()));
|
||||
map.put(feed.getId(), context);
|
||||
}
|
||||
|
||||
@@ -210,7 +130,7 @@ public class FeedRefreshTaskGiver {
|
||||
for (FeedRefreshContext context : map.values()) {
|
||||
feeds.add(context.getFeed());
|
||||
}
|
||||
feedDAO.saveOrUpdate(feeds);
|
||||
feedDAO.merge(feeds);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -225,7 +145,7 @@ public class FeedRefreshTaskGiver {
|
||||
}
|
||||
|
||||
private Date getLastLoginThreshold() {
|
||||
if (applicationSettingsService.get().isHeavyLoad()) {
|
||||
if (config.getApplicationSettings().isHeavyLoad()) {
|
||||
return DateUtils.addDays(new Date(), -30);
|
||||
} else {
|
||||
return null;
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.commafeed.backend.feeds;
|
||||
package com.commafeed.backend.feed;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.commafeed.backend.feeds;
|
||||
package com.commafeed.backend.feed;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.RejectedExecutionHandler;
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.commafeed.backend.feed;
|
||||
|
||||
import io.dropwizard.lifecycle.Managed;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.codahale.metrics.Meter;
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.commafeed.CommaFeedConfiguration;
|
||||
import com.commafeed.backend.dao.FeedDAO;
|
||||
import com.commafeed.backend.dao.UnitOfWork;
|
||||
|
||||
/**
|
||||
* Infinite loop fetching feeds from @FeedQueues and queuing them to the {@link FeedRefreshWorker} pool.
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
public class FeedRefreshTaskGiver implements Managed {
|
||||
|
||||
private final SessionFactory sessionFactory;
|
||||
private final FeedQueues queues;
|
||||
private final FeedRefreshWorker worker;
|
||||
|
||||
private ExecutorService executor;
|
||||
|
||||
private Meter feedRefreshed;
|
||||
private Meter threadWaited;
|
||||
|
||||
@Inject
|
||||
public FeedRefreshTaskGiver(SessionFactory sessionFactory, FeedQueues queues, FeedDAO feedDAO, FeedRefreshWorker worker,
|
||||
CommaFeedConfiguration config, MetricRegistry metrics) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
this.queues = queues;
|
||||
this.worker = worker;
|
||||
|
||||
executor = Executors.newFixedThreadPool(1);
|
||||
feedRefreshed = metrics.meter(MetricRegistry.name(getClass(), "feedRefreshed"));
|
||||
threadWaited = metrics.meter(MetricRegistry.name(getClass(), "threadWaited"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
executor.shutdownNow();
|
||||
while (!executor.isTerminated()) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
log.error("interrupted while waiting for threads to finish.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
log.info("starting feed refresh task giver");
|
||||
executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (!executor.isShutdown()) {
|
||||
try {
|
||||
FeedRefreshContext context = new UnitOfWork<FeedRefreshContext>(sessionFactory) {
|
||||
@Override
|
||||
protected FeedRefreshContext runInSession() throws Exception {
|
||||
FeedRefreshContext context = queues.take();
|
||||
if (context != null) {
|
||||
feedRefreshed.mark();
|
||||
worker.updateFeed(context);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
}.run();
|
||||
if (context == null) {
|
||||
log.debug("nothing to do, sleeping for 15s");
|
||||
threadWaited.mark();
|
||||
try {
|
||||
Thread.sleep(15000);
|
||||
} catch (InterruptedException e) {
|
||||
log.error("interrupted while sleeping");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
package com.commafeed.backend.feeds;
|
||||
package com.commafeed.backend.feed;
|
||||
|
||||
import io.dropwizard.lifecycle.Managed;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
@@ -7,67 +9,42 @@ import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.codahale.metrics.Meter;
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.commafeed.CommaFeedConfiguration;
|
||||
import com.commafeed.CommaFeedConfiguration.ApplicationSettings;
|
||||
import com.commafeed.backend.cache.CacheService;
|
||||
import com.commafeed.backend.dao.FeedDAO;
|
||||
import com.commafeed.backend.dao.FeedEntryDAO;
|
||||
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
||||
import com.commafeed.backend.feeds.FeedRefreshExecutor.Task;
|
||||
import com.commafeed.backend.model.ApplicationSettings;
|
||||
import com.commafeed.backend.dao.UnitOfWork;
|
||||
import com.commafeed.backend.feed.FeedRefreshExecutor.Task;
|
||||
import com.commafeed.backend.model.Feed;
|
||||
import com.commafeed.backend.model.FeedEntry;
|
||||
import com.commafeed.backend.model.FeedEntryContent;
|
||||
import com.commafeed.backend.model.FeedSubscription;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.pubsubhubbub.SubscriptionHandler;
|
||||
import com.commafeed.backend.services.ApplicationSettingsService;
|
||||
import com.commafeed.backend.services.FeedUpdateService;
|
||||
import com.commafeed.backend.service.FeedUpdateService;
|
||||
import com.commafeed.backend.service.PubSubService;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.util.concurrent.Striped;
|
||||
|
||||
@ApplicationScoped
|
||||
@Slf4j
|
||||
public class FeedRefreshUpdater {
|
||||
public class FeedRefreshUpdater implements Managed {
|
||||
|
||||
@Inject
|
||||
FeedUpdateService feedUpdateService;
|
||||
|
||||
@Inject
|
||||
SubscriptionHandler handler;
|
||||
|
||||
@Inject
|
||||
FeedRefreshTaskGiver taskGiver;
|
||||
|
||||
@Inject
|
||||
FeedDAO feedDAO;
|
||||
|
||||
@Inject
|
||||
ApplicationSettingsService applicationSettingsService;
|
||||
|
||||
@Inject
|
||||
MetricRegistry metrics;
|
||||
|
||||
@Inject
|
||||
FeedSubscriptionDAO feedSubscriptionDAO;
|
||||
|
||||
@Inject
|
||||
FeedEntryDAO feedEntryDAO;
|
||||
|
||||
@Inject
|
||||
CacheService cache;
|
||||
private final SessionFactory sessionFactory;
|
||||
private final FeedUpdateService feedUpdateService;
|
||||
private final PubSubService pubSubService;
|
||||
private final FeedQueues queues;
|
||||
private final CommaFeedConfiguration config;
|
||||
private final FeedSubscriptionDAO feedSubscriptionDAO;
|
||||
private final CacheService cache;
|
||||
|
||||
private FeedRefreshExecutor pool;
|
||||
private Striped<Lock> locks;
|
||||
@@ -77,9 +54,18 @@ public class FeedRefreshUpdater {
|
||||
private Meter feedUpdated;
|
||||
private Meter entryInserted;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
ApplicationSettings settings = applicationSettingsService.get();
|
||||
public FeedRefreshUpdater(SessionFactory sessionFactory, FeedUpdateService feedUpdateService, PubSubService pubSubService,
|
||||
FeedQueues queues, CommaFeedConfiguration config, MetricRegistry metrics, FeedSubscriptionDAO feedSubscriptionDAO,
|
||||
CacheService cache) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
this.feedUpdateService = feedUpdateService;
|
||||
this.pubSubService = pubSubService;
|
||||
this.queues = queues;
|
||||
this.config = config;
|
||||
this.feedSubscriptionDAO = feedSubscriptionDAO;
|
||||
this.cache = cache;
|
||||
|
||||
ApplicationSettings settings = config.getApplicationSettings();
|
||||
int threads = Math.max(settings.getDatabaseUpdateThreads(), 1);
|
||||
pool = new FeedRefreshExecutor("feed-refresh-updater", threads, Math.min(50 * threads, 1000), metrics);
|
||||
locks = Striped.lazyWeakLock(threads * 100000);
|
||||
@@ -90,8 +76,12 @@ public class FeedRefreshUpdater {
|
||||
entryInserted = metrics.meter(MetricRegistry.name(getClass(), "entryInserted"));
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void shutdown() {
|
||||
@Override
|
||||
public void start() throws Exception {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
pool.shutdown();
|
||||
}
|
||||
|
||||
@@ -109,6 +99,16 @@ public class FeedRefreshUpdater {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
new UnitOfWork<Void>(sessionFactory) {
|
||||
@Override
|
||||
protected Void runInSession() throws Exception {
|
||||
internalRun();
|
||||
return null;
|
||||
}
|
||||
}.run();
|
||||
}
|
||||
|
||||
public void internalRun() {
|
||||
boolean ok = true;
|
||||
Feed feed = context.getFeed();
|
||||
List<FeedEntry> entries = context.getEntries();
|
||||
@@ -151,7 +151,7 @@ public class FeedRefreshUpdater {
|
||||
}
|
||||
}
|
||||
|
||||
if (applicationSettingsService.get().isPubsubhubbub()) {
|
||||
if (config.getApplicationSettings().isPubsubhubbub()) {
|
||||
handlePubSub(feed);
|
||||
}
|
||||
if (!ok) {
|
||||
@@ -159,7 +159,7 @@ public class FeedRefreshUpdater {
|
||||
feed.setDisabledUntil(new Date(0));
|
||||
}
|
||||
feedUpdated.mark();
|
||||
taskGiver.giveBack(feed);
|
||||
queues.giveBack(feed);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -218,10 +218,11 @@ public class FeedRefreshUpdater {
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
handler.subscribe(feed);
|
||||
pubSubService.subscribe(feed);
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,62 +1,53 @@
|
||||
package com.commafeed.backend.feeds;
|
||||
package com.commafeed.backend.feed;
|
||||
|
||||
import io.dropwizard.lifecycle.Managed;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.commafeed.CommaFeedConfiguration;
|
||||
import com.commafeed.backend.HttpGetter.NotModifiedException;
|
||||
import com.commafeed.backend.feeds.FeedRefreshExecutor.Task;
|
||||
import com.commafeed.backend.model.ApplicationSettings;
|
||||
import com.commafeed.backend.feed.FeedRefreshExecutor.Task;
|
||||
import com.commafeed.backend.model.Feed;
|
||||
import com.commafeed.backend.model.FeedEntry;
|
||||
import com.commafeed.backend.services.ApplicationSettingsService;
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
/**
|
||||
* Calls {@link FeedFetcher} and handles its outcome
|
||||
*
|
||||
*/
|
||||
@ApplicationScoped
|
||||
@Slf4j
|
||||
public class FeedRefreshWorker {
|
||||
public class FeedRefreshWorker implements Managed {
|
||||
|
||||
@Inject
|
||||
FeedRefreshUpdater feedRefreshUpdater;
|
||||
private final FeedRefreshUpdater feedRefreshUpdater;
|
||||
private final FeedFetcher fetcher;
|
||||
private final FeedQueues queues;
|
||||
private final CommaFeedConfiguration config;
|
||||
private final FeedRefreshExecutor pool;
|
||||
|
||||
@Inject
|
||||
FeedFetcher fetcher;
|
||||
|
||||
@Inject
|
||||
FeedRefreshTaskGiver taskGiver;
|
||||
|
||||
@Inject
|
||||
MetricRegistry metrics;
|
||||
|
||||
@Inject
|
||||
ApplicationSettingsService applicationSettingsService;
|
||||
|
||||
private FeedRefreshExecutor pool;
|
||||
|
||||
@PostConstruct
|
||||
private void init() {
|
||||
ApplicationSettings settings = applicationSettingsService.get();
|
||||
int threads = settings.getBackgroundThreads();
|
||||
public FeedRefreshWorker(FeedRefreshUpdater feedRefreshUpdater, FeedFetcher fetcher, FeedQueues queues, CommaFeedConfiguration config,
|
||||
MetricRegistry metrics) {
|
||||
this.feedRefreshUpdater = feedRefreshUpdater;
|
||||
this.fetcher = fetcher;
|
||||
this.config = config;
|
||||
this.queues = queues;
|
||||
int threads = config.getApplicationSettings().getBackgroundThreads();
|
||||
pool = new FeedRefreshExecutor("feed-refresh-worker", threads, Math.min(20 * threads, 1000), metrics);
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void shutdown() {
|
||||
@Override
|
||||
public void start() throws Exception {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
pool.shutdown();
|
||||
}
|
||||
|
||||
@@ -85,16 +76,16 @@ public class FeedRefreshWorker {
|
||||
|
||||
private void update(FeedRefreshContext context) {
|
||||
Feed feed = context.getFeed();
|
||||
int refreshInterval = applicationSettingsService.get().getRefreshIntervalMinutes();
|
||||
int refreshInterval = config.getApplicationSettings().getRefreshIntervalMinutes();
|
||||
Date disabledUntil = DateUtils.addMinutes(new Date(), refreshInterval);
|
||||
try {
|
||||
String url = ObjectUtils.firstNonNull(feed.getUrlAfterRedirect(), feed.getUrl());
|
||||
String url = Optional.fromNullable(feed.getUrlAfterRedirect()).or(feed.getUrl());
|
||||
FetchedFeed fetchedFeed = fetcher.fetch(url, false, feed.getLastModifiedHeader(), feed.getEtagHeader(),
|
||||
feed.getLastPublishedDate(), feed.getLastContentHash());
|
||||
// stops here if NotModifiedException or any other exception is thrown
|
||||
List<FeedEntry> entries = fetchedFeed.getEntries();
|
||||
|
||||
if (applicationSettingsService.get().isHeavyLoad()) {
|
||||
if (config.getApplicationSettings().isHeavyLoad()) {
|
||||
disabledUntil = FeedUtils.buildDisabledUntil(fetchedFeed.getFeed().getLastEntryDate(), fetchedFeed.getFeed()
|
||||
.getAverageEntryInterval(), disabledUntil);
|
||||
}
|
||||
@@ -122,14 +113,14 @@ public class FeedRefreshWorker {
|
||||
} catch (NotModifiedException e) {
|
||||
log.debug("Feed not modified : {} - {}", feed.getUrl(), e.getMessage());
|
||||
|
||||
if (applicationSettingsService.get().isHeavyLoad()) {
|
||||
if (config.getApplicationSettings().isHeavyLoad()) {
|
||||
disabledUntil = FeedUtils.buildDisabledUntil(feed.getLastEntryDate(), feed.getAverageEntryInterval(), disabledUntil);
|
||||
}
|
||||
feed.setErrorCount(0);
|
||||
feed.setMessage(e.getMessage());
|
||||
feed.setDisabledUntil(disabledUntil);
|
||||
|
||||
taskGiver.giveBack(feed);
|
||||
queues.giveBack(feed);
|
||||
} catch (Exception e) {
|
||||
String message = "Unable to refresh feed " + feed.getUrl() + " : " + e.getMessage();
|
||||
log.debug(e.getClass().getName() + " " + message, e);
|
||||
@@ -138,7 +129,7 @@ public class FeedRefreshWorker {
|
||||
feed.setMessage(message);
|
||||
feed.setDisabledUntil(FeedUtils.buildDisabledUntil(feed.getErrorCount()));
|
||||
|
||||
taskGiver.giveBack(feed);
|
||||
queues.giveBack(feed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.commafeed.backend.feeds;
|
||||
package com.commafeed.backend.feed;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.net.MalformedURLException;
|
||||
@@ -15,9 +15,8 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
import org.apache.commons.math.stat.descriptive.SummaryStatistics;
|
||||
import org.apache.wicket.request.UrlUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Document.OutputSettings;
|
||||
@@ -129,10 +128,10 @@ public class FeedUtils {
|
||||
}
|
||||
return encoding;
|
||||
}
|
||||
|
||||
public static String replaceHtmlEntitiesWithNumericEntities(String source){
|
||||
|
||||
public static String replaceHtmlEntitiesWithNumericEntities(String source) {
|
||||
String result = source;
|
||||
for(String entity : HtmlEntities.NUMERIC_MAPPING.keySet()){
|
||||
for (String entity : HtmlEntities.NUMERIC_MAPPING.keySet()) {
|
||||
result = result.replace(entity, HtmlEntities.NUMERIC_MAPPING.get(entity));
|
||||
}
|
||||
return result;
|
||||
@@ -422,7 +421,7 @@ public class FeedUtils {
|
||||
return url;
|
||||
}
|
||||
|
||||
String baseUrl = (feedLink == null || UrlUtils.isRelative(feedLink)) ? feedUrl : feedLink;
|
||||
String baseUrl = (feedLink == null || isRelative(feedLink)) ? feedUrl : feedLink;
|
||||
|
||||
if (baseUrl == null) {
|
||||
return url;
|
||||
@@ -439,6 +438,15 @@ public class FeedUtils {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean isRelative(final String url) {
|
||||
// the regex means "doesn't start with 'scheme://'"
|
||||
if ((url != null) && (url.startsWith("/") == false) && (!url.matches("^\\w+\\:\\/\\/.*")) && !(url.startsWith("#"))) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getFaviconUrl(FeedSubscription subscription, String publicUrl) {
|
||||
return removeTrailingSlash(publicUrl) + "/rest/feed/favicon/" + subscription.getId();
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.commafeed.backend.feeds;
|
||||
package com.commafeed.backend.feed;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.commafeed.backend.feeds;
|
||||
package com.commafeed.backend.feed;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.commafeed.backend.metrics;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
import javax.enterprise.inject.Produces;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import com.codahale.metrics.JmxReporter;
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
|
||||
@ApplicationScoped
|
||||
@Slf4j
|
||||
public class MetricRegistryProducer {
|
||||
|
||||
private MetricRegistry registry;
|
||||
|
||||
@PostConstruct
|
||||
private void init() {
|
||||
log.info("initializing metrics registry");
|
||||
registry = new MetricRegistry();
|
||||
JmxReporter.forRegistry(registry).build().start();
|
||||
log.info("metrics registry initialized");
|
||||
}
|
||||
|
||||
@Produces
|
||||
public MetricRegistry produceMetricsRegistry() {
|
||||
return registry;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package com.commafeed.backend.model;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import org.apache.log4j.Level;
|
||||
|
||||
@Entity
|
||||
@Table(name = "APPLICATIONSETTINGS")
|
||||
@SuppressWarnings("serial")
|
||||
@Getter
|
||||
@Setter
|
||||
public class ApplicationSettings extends AbstractModel {
|
||||
|
||||
private String publicUrl;
|
||||
private boolean allowRegistrations = false;
|
||||
private String googleAnalyticsTrackingCode;
|
||||
private String googleClientId;
|
||||
private String googleClientSecret;
|
||||
private int backgroundThreads = 3;
|
||||
private int databaseUpdateThreads = 1;
|
||||
private String smtpHost;
|
||||
private int smtpPort;
|
||||
private boolean smtpTls;
|
||||
private String smtpUserName;
|
||||
private String smtpPassword;
|
||||
private boolean heavyLoad;
|
||||
private boolean pubsubhubbub;
|
||||
private boolean feedbackButton = true;
|
||||
private String logLevel = Level.INFO.toString();
|
||||
private boolean imageProxyEnabled;
|
||||
private int queryTimeout;
|
||||
private boolean crawlingPaused;
|
||||
private int keepStatusDays = 0;
|
||||
private int refreshIntervalMinutes = 5;
|
||||
@Column(length = 255)
|
||||
private String announcement;
|
||||
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package com.commafeed.backend.model;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
@@ -15,14 +14,9 @@ import javax.persistence.TemporalType;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
@Entity
|
||||
@Table(name = "FEEDS")
|
||||
@SuppressWarnings("serial")
|
||||
@Cacheable
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
|
||||
@Getter
|
||||
@Setter
|
||||
public class Feed extends AbstractModel {
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.commafeed.backend.model;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
@@ -14,14 +13,9 @@ import javax.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
@Entity
|
||||
@Table(name = "FEEDCATEGORIES")
|
||||
@SuppressWarnings("serial")
|
||||
@Cacheable
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
|
||||
@Getter
|
||||
@Setter
|
||||
public class FeedCategory extends AbstractModel {
|
||||
@@ -31,11 +25,9 @@ public class FeedCategory extends AbstractModel {
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(nullable = false)
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
|
||||
private User user;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
|
||||
private FeedCategory parent;
|
||||
|
||||
@OneToMany(mappedBy = "parent")
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.commafeed.backend.model;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
@@ -19,14 +18,9 @@ import javax.persistence.TemporalType;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
@Entity
|
||||
@Table(name = "FEEDENTRIES")
|
||||
@SuppressWarnings("serial")
|
||||
@Cacheable
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
|
||||
@Getter
|
||||
@Setter
|
||||
public class FeedEntry extends AbstractModel {
|
||||
@@ -55,7 +49,7 @@ public class FeedEntry extends AbstractModel {
|
||||
|
||||
@OneToMany(mappedBy = "entry", cascade = CascadeType.REMOVE)
|
||||
private Set<FeedEntryStatus> statuses;
|
||||
|
||||
|
||||
@OneToMany(mappedBy = "entry", cascade = CascadeType.REMOVE)
|
||||
private Set<FeedEntryTag> tags;
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.commafeed.backend.model;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Lob;
|
||||
@@ -12,14 +11,9 @@ import javax.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
@Entity
|
||||
@Table(name = "FEEDENTRYCONTENTS")
|
||||
@SuppressWarnings("serial")
|
||||
@Cacheable
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
|
||||
@Getter
|
||||
@Setter
|
||||
public class FeedEntryContent extends AbstractModel {
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.commafeed.backend.model;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
@@ -19,19 +18,16 @@ import javax.persistence.Transient;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
@Entity
|
||||
@Table(name = "FEEDENTRYSTATUSES")
|
||||
@SuppressWarnings("serial")
|
||||
@Cacheable
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
|
||||
@Getter
|
||||
@Setter
|
||||
@NamedQueries(@NamedQuery(name="Statuses.deleteOld", query="delete from FeedEntryStatus s where s.entryInserted < :date and s.starred = false"))
|
||||
@NamedQueries(@NamedQuery(
|
||||
name = "Statuses.deleteOld",
|
||||
query = "delete from FeedEntryStatus s where s.entryInserted < :date and s.starred = false"))
|
||||
public class FeedEntryStatus extends AbstractModel {
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@@ -48,7 +44,7 @@ public class FeedEntryStatus extends AbstractModel {
|
||||
|
||||
@Transient
|
||||
private boolean markable;
|
||||
|
||||
|
||||
@Transient
|
||||
private List<FeedEntryTag> tags = Lists.newArrayList();
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.commafeed.backend.model;
|
||||
|
||||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
@@ -11,14 +10,9 @@ import javax.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
@Entity
|
||||
@Table(name = "FEEDENTRYTAGS")
|
||||
@SuppressWarnings("serial")
|
||||
@Cacheable
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
|
||||
@Getter
|
||||
@Setter
|
||||
public class FeedEntryTag extends AbstractModel {
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.commafeed.backend.model;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
@@ -15,33 +14,25 @@ import javax.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
@Entity
|
||||
@Table(name = "FEEDSUBSCRIPTIONS")
|
||||
@SuppressWarnings("serial")
|
||||
@Cacheable
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
|
||||
@Getter
|
||||
@Setter
|
||||
public class FeedSubscription extends AbstractModel {
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(nullable = false)
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
|
||||
private User user;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(nullable = false)
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
|
||||
private Feed feed;
|
||||
|
||||
@Column(length = 128, nullable = false)
|
||||
private String title;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
|
||||
private FeedCategory category;
|
||||
|
||||
@OneToMany(mappedBy = "subscription", cascade = CascadeType.REMOVE)
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.commafeed.backend.model;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
@@ -16,23 +15,20 @@ import javax.persistence.TemporalType;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.annotations.Cascade;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
@Entity
|
||||
@Table(name = "USERS")
|
||||
@SuppressWarnings("serial")
|
||||
@Cacheable
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
|
||||
@Getter
|
||||
@Setter
|
||||
public class User extends AbstractModel {
|
||||
|
||||
@Column(length = 32, nullable = false, unique = true)
|
||||
private String name;
|
||||
|
||||
|
||||
@Column(length = 255, unique = true)
|
||||
private String email;
|
||||
|
||||
@@ -61,6 +57,8 @@ public class User extends AbstractModel {
|
||||
private Date recoverPasswordTokenDate;
|
||||
|
||||
@OneToMany(mappedBy = "user", cascade = { CascadeType.PERSIST, CascadeType.REMOVE })
|
||||
@Cascade({ org.hibernate.annotations.CascadeType.PERSIST, org.hibernate.annotations.CascadeType.SAVE_UPDATE,
|
||||
org.hibernate.annotations.CascadeType.REMOVE })
|
||||
private Set<UserRole> roles = Sets.newHashSet();
|
||||
|
||||
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.commafeed.backend.model;
|
||||
|
||||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
@@ -13,14 +12,9 @@ import javax.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
@Entity
|
||||
@Table(name = "USERROLES")
|
||||
@SuppressWarnings("serial")
|
||||
@Cacheable
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
|
||||
@Getter
|
||||
@Setter
|
||||
public class UserRole extends AbstractModel {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.commafeed.backend.model;
|
||||
|
||||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
@@ -14,14 +13,9 @@ import javax.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
@Entity
|
||||
@Table(name = "USERSETTINGS")
|
||||
@SuppressWarnings("serial")
|
||||
@Cacheable
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
|
||||
@Getter
|
||||
@Setter
|
||||
public class UserSettings extends AbstractModel {
|
||||
@@ -69,7 +63,7 @@ public class UserSettings extends AbstractModel {
|
||||
|
||||
@Column(name = "scroll_speed")
|
||||
private int scrollSpeed;
|
||||
|
||||
|
||||
private boolean email;
|
||||
private boolean gmail;
|
||||
private boolean facebook;
|
||||
|
||||
@@ -3,8 +3,7 @@ package com.commafeed.backend.opml;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.ejb.Stateless;
|
||||
import javax.inject.Inject;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import com.commafeed.backend.dao.FeedCategoryDAO;
|
||||
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
||||
@@ -15,14 +14,11 @@ import com.sun.syndication.feed.opml.Attribute;
|
||||
import com.sun.syndication.feed.opml.Opml;
|
||||
import com.sun.syndication.feed.opml.Outline;
|
||||
|
||||
@Stateless
|
||||
@AllArgsConstructor
|
||||
public class OPMLExporter {
|
||||
|
||||
@Inject
|
||||
FeedCategoryDAO feedCategoryDAO;
|
||||
|
||||
@Inject
|
||||
FeedSubscriptionDAO feedSubscriptionDAO;
|
||||
private final FeedCategoryDAO feedCategoryDAO;
|
||||
private final FeedSubscriptionDAO feedSubscriptionDAO;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Opml export(User user) {
|
||||
|
||||
@@ -3,12 +3,6 @@ package com.commafeed.backend.opml;
|
||||
import java.io.StringReader;
|
||||
import java.util.List;
|
||||
|
||||
import javax.ejb.Asynchronous;
|
||||
import javax.ejb.Stateless;
|
||||
import javax.ejb.TransactionAttribute;
|
||||
import javax.ejb.TransactionAttributeType;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
@@ -16,37 +10,36 @@ import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import com.commafeed.backend.cache.CacheService;
|
||||
import com.commafeed.backend.dao.FeedCategoryDAO;
|
||||
import com.commafeed.backend.feeds.FeedUtils;
|
||||
import com.commafeed.backend.feed.FeedUtils;
|
||||
import com.commafeed.backend.model.FeedCategory;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.services.FeedSubscriptionService;
|
||||
import com.commafeed.backend.services.FeedSubscriptionService.FeedSubscriptionException;
|
||||
import com.commafeed.backend.service.FeedSubscriptionService;
|
||||
import com.commafeed.backend.service.FeedSubscriptionService.FeedSubscriptionException;
|
||||
import com.sun.syndication.feed.opml.Opml;
|
||||
import com.sun.syndication.feed.opml.Outline;
|
||||
import com.sun.syndication.io.WireFeedInput;
|
||||
|
||||
@Stateless
|
||||
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
|
||||
@Slf4j
|
||||
public class OPMLImporter {
|
||||
|
||||
@Inject
|
||||
FeedSubscriptionService feedSubscriptionService;
|
||||
private FeedCategoryDAO feedCategoryDAO;
|
||||
private FeedSubscriptionService feedSubscriptionService;
|
||||
private CacheService cache;
|
||||
|
||||
@Inject
|
||||
FeedCategoryDAO feedCategoryDAO;
|
||||
|
||||
@Inject
|
||||
CacheService cache;
|
||||
public OPMLImporter(FeedCategoryDAO feedCategoryDAO, FeedSubscriptionService feedSubscriptionService, CacheService cache) {
|
||||
super();
|
||||
this.feedCategoryDAO = feedCategoryDAO;
|
||||
this.feedSubscriptionService = feedSubscriptionService;
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Asynchronous
|
||||
public void importOpml(User user, String xml) {
|
||||
xml = xml.substring(xml.indexOf('<'));
|
||||
WireFeedInput input = new WireFeedInput();
|
||||
try {
|
||||
Opml feed = (Opml) input.build(new StringReader(xml));
|
||||
List<Outline> outlines = (List<Outline>) feed.getOutlines();
|
||||
List<Outline> outlines = feed.getOutlines();
|
||||
for (Outline outline : outlines) {
|
||||
handleOutline(user, outline, null);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.commafeed.backend.services;
|
||||
package com.commafeed.backend.service;
|
||||
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
@@ -6,13 +6,7 @@ public class ApplicationPropertiesService {
|
||||
|
||||
private ResourceBundle bundle;
|
||||
|
||||
private static ApplicationPropertiesService INSTANCE = new ApplicationPropertiesService();
|
||||
|
||||
public static ApplicationPropertiesService get() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private ApplicationPropertiesService() {
|
||||
public ApplicationPropertiesService() {
|
||||
bundle = ResourceBundle.getBundle("application");
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.commafeed.backend.services;
|
||||
package com.commafeed.backend.service;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
@@ -6,8 +6,7 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import com.commafeed.backend.dao.FeedDAO;
|
||||
@@ -25,28 +24,17 @@ import com.commafeed.backend.model.FeedSubscription;
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class DatabaseCleaningService {
|
||||
|
||||
private static final int BATCH_SIZE = 100;
|
||||
|
||||
@Inject
|
||||
FeedDAO feedDAO;
|
||||
private final FeedDAO feedDAO;
|
||||
private final FeedEntryDAO feedEntryDAO;
|
||||
private final FeedEntryContentDAO feedEntryContentDAO;
|
||||
private final FeedEntryStatusDAO feedEntryStatusDAO;
|
||||
private final FeedSubscriptionDAO feedSubscriptionDAO;
|
||||
|
||||
@Inject
|
||||
FeedEntryDAO feedEntryDAO;
|
||||
|
||||
@Inject
|
||||
FeedSubscriptionDAO feedSubscriptionDAO;
|
||||
|
||||
@Inject
|
||||
FeedEntryContentDAO feedEntryContentDAO;
|
||||
|
||||
@Inject
|
||||
FeedEntryStatusDAO feedEntryStatusDAO;
|
||||
|
||||
@Inject
|
||||
ApplicationSettingsService applicationSettingsService;
|
||||
|
||||
public long cleanEntriesWithoutSubscriptions() {
|
||||
log.info("cleaning entries without subscriptions");
|
||||
long total = 0;
|
||||
@@ -1,18 +1,18 @@
|
||||
package com.commafeed.backend.services;
|
||||
package com.commafeed.backend.service;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import com.commafeed.backend.dao.FeedEntryContentDAO;
|
||||
import com.commafeed.backend.feeds.FeedUtils;
|
||||
import com.commafeed.backend.feed.FeedUtils;
|
||||
import com.commafeed.backend.model.FeedEntryContent;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class FeedEntryContentService {
|
||||
|
||||
@Inject
|
||||
FeedEntryContentDAO feedEntryContentDAO;
|
||||
private final FeedEntryContentDAO feedEntryContentDAO;
|
||||
|
||||
/**
|
||||
* this is NOT thread-safe
|
||||
@@ -1,10 +1,9 @@
|
||||
package com.commafeed.backend.services;
|
||||
package com.commafeed.backend.service;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.ejb.Stateless;
|
||||
import javax.inject.Inject;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import com.commafeed.backend.cache.CacheService;
|
||||
import com.commafeed.backend.dao.FeedEntryDAO;
|
||||
@@ -16,20 +15,13 @@ import com.commafeed.backend.model.FeedSubscription;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
@Stateless
|
||||
@RequiredArgsConstructor
|
||||
public class FeedEntryService {
|
||||
|
||||
@Inject
|
||||
FeedEntryStatusDAO feedEntryStatusDAO;
|
||||
|
||||
@Inject
|
||||
FeedSubscriptionDAO feedSubscriptionDAO;
|
||||
|
||||
@Inject
|
||||
FeedEntryDAO feedEntryDAO;
|
||||
|
||||
@Inject
|
||||
CacheService cache;
|
||||
private final FeedSubscriptionDAO feedSubscriptionDAO;
|
||||
private final FeedEntryDAO feedEntryDAO;
|
||||
private final FeedEntryStatusDAO feedEntryStatusDAO;
|
||||
private final CacheService cache;
|
||||
|
||||
public void markEntry(User user, Long entryId, boolean read) {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package com.commafeed.backend.services;
|
||||
package com.commafeed.backend.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.ejb.Stateless;
|
||||
import javax.inject.Inject;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import com.commafeed.backend.dao.FeedEntryDAO;
|
||||
import com.commafeed.backend.dao.FeedEntryTagDAO;
|
||||
@@ -15,14 +14,11 @@ import com.google.common.base.Function;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
@Stateless
|
||||
@RequiredArgsConstructor
|
||||
public class FeedEntryTagService {
|
||||
|
||||
@Inject
|
||||
FeedEntryDAO feedEntryDAO;
|
||||
|
||||
@Inject
|
||||
FeedEntryTagDAO feedEntryTagDAO;
|
||||
private final FeedEntryDAO feedEntryDAO;
|
||||
private final FeedEntryTagDAO feedEntryTagDAO;
|
||||
|
||||
public void updateTags(User user, Long entryId, List<String> tagNames) {
|
||||
FeedEntry entry = feedEntryDAO.findById(entryId);
|
||||
32
src/main/java/com/commafeed/backend/service/FeedService.java
Normal file
32
src/main/java/com/commafeed/backend/service/FeedService.java
Normal file
@@ -0,0 +1,32 @@
|
||||
package com.commafeed.backend.service;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
|
||||
import com.commafeed.backend.dao.FeedDAO;
|
||||
import com.commafeed.backend.feed.FeedUtils;
|
||||
import com.commafeed.backend.model.Feed;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class FeedService {
|
||||
|
||||
private final FeedDAO feedDAO;
|
||||
|
||||
public synchronized Feed findOrCreate(String url) {
|
||||
String normalized = FeedUtils.normalizeURL(url);
|
||||
Feed feed = feedDAO.findByUrl(normalized);
|
||||
if (feed == null) {
|
||||
feed = new Feed();
|
||||
feed.setUrl(url);
|
||||
feed.setNormalizedUrl(normalized);
|
||||
feed.setNormalizedUrlHash(DigestUtils.sha1Hex(normalized));
|
||||
feed.setDisabledUntil(new Date(0));
|
||||
feedDAO.saveOrUpdate(feed);
|
||||
}
|
||||
return feed;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +1,19 @@
|
||||
package com.commafeed.backend.services;
|
||||
package com.commafeed.backend.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.ejb.ApplicationException;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import com.commafeed.CommaFeedConfiguration;
|
||||
import com.commafeed.backend.cache.CacheService;
|
||||
import com.commafeed.backend.dao.FeedEntryDAO;
|
||||
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
||||
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
||||
import com.commafeed.backend.feeds.FeedRefreshTaskGiver;
|
||||
import com.commafeed.backend.feeds.FeedUtils;
|
||||
import com.commafeed.backend.feed.FeedQueues;
|
||||
import com.commafeed.backend.feed.FeedUtils;
|
||||
import com.commafeed.backend.model.Feed;
|
||||
import com.commafeed.backend.model.FeedCategory;
|
||||
import com.commafeed.backend.model.FeedSubscription;
|
||||
@@ -25,40 +23,26 @@ import com.commafeed.frontend.model.UnreadCount;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class FeedSubscriptionService {
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApplicationException
|
||||
public static class FeedSubscriptionException extends RuntimeException {
|
||||
public FeedSubscriptionException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
FeedService feedService;
|
||||
|
||||
@Inject
|
||||
FeedEntryDAO feedEntryDAO;
|
||||
|
||||
@Inject
|
||||
FeedEntryStatusDAO feedEntryStatusDAO;
|
||||
|
||||
@Inject
|
||||
FeedSubscriptionDAO feedSubscriptionDAO;
|
||||
|
||||
@Inject
|
||||
ApplicationSettingsService applicationSettingsService;
|
||||
|
||||
@Inject
|
||||
FeedRefreshTaskGiver taskGiver;
|
||||
|
||||
@Inject
|
||||
CacheService cache;
|
||||
private final FeedEntryStatusDAO feedEntryStatusDAO;
|
||||
private final FeedSubscriptionDAO feedSubscriptionDAO;
|
||||
private final FeedService feedService;
|
||||
private final FeedQueues queues;
|
||||
private final CacheService cache;
|
||||
private final CommaFeedConfiguration config;
|
||||
|
||||
public Feed subscribe(User user, String url, String title, FeedCategory category) {
|
||||
|
||||
final String pubUrl = applicationSettingsService.get().getPublicUrl();
|
||||
final String pubUrl = config.getApplicationSettings().getPublicUrl();
|
||||
if (StringUtils.isBlank(pubUrl)) {
|
||||
throw new FeedSubscriptionException("Public URL of this CommaFeed instance is not set");
|
||||
}
|
||||
@@ -79,7 +63,7 @@ public class FeedSubscriptionService {
|
||||
sub.setTitle(FeedUtils.truncate(title, 128));
|
||||
feedSubscriptionDAO.saveOrUpdate(sub);
|
||||
|
||||
taskGiver.add(feed, false);
|
||||
queues.add(feed, false);
|
||||
cache.invalidateUserRootCategory(user);
|
||||
return feed;
|
||||
}
|
||||
@@ -99,7 +83,7 @@ public class FeedSubscriptionService {
|
||||
List<FeedSubscription> subs = feedSubscriptionDAO.findAll(user);
|
||||
for (FeedSubscription sub : subs) {
|
||||
Feed feed = sub.getFeed();
|
||||
taskGiver.add(feed, true);
|
||||
queues.add(feed, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package com.commafeed.backend.services;
|
||||
package com.commafeed.backend.service;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.ejb.Stateless;
|
||||
import javax.inject.Inject;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
|
||||
@@ -12,21 +11,18 @@ import com.commafeed.backend.model.Feed;
|
||||
import com.commafeed.backend.model.FeedEntry;
|
||||
import com.commafeed.backend.model.FeedEntryContent;
|
||||
|
||||
@Stateless
|
||||
@AllArgsConstructor
|
||||
public class FeedUpdateService {
|
||||
|
||||
@Inject
|
||||
FeedEntryDAO feedEntryDAO;
|
||||
|
||||
@Inject
|
||||
FeedEntryContentService feedEntryContentService;
|
||||
private final FeedEntryDAO feedEntryDAO;
|
||||
private final FeedEntryContentService feedEntryContentService;
|
||||
|
||||
/**
|
||||
* this is NOT thread-safe
|
||||
*/
|
||||
public boolean addEntry(Feed feed, FeedEntry entry) {
|
||||
|
||||
Long existing = feedEntryDAO.findExisting(entry.getGuid(), feed.getId());
|
||||
Long existing = feedEntryDAO.findExisting(entry.getGuid(), feed);
|
||||
if (existing != null) {
|
||||
return false;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.commafeed.backend.services;
|
||||
package com.commafeed.backend.service;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Properties;
|
||||
@@ -12,7 +12,8 @@ import javax.mail.Transport;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
|
||||
import com.commafeed.backend.model.ApplicationSettings;
|
||||
import com.commafeed.CommaFeedConfiguration;
|
||||
import com.commafeed.CommaFeedConfiguration.ApplicationSettings;
|
||||
import com.commafeed.backend.model.User;
|
||||
|
||||
/**
|
||||
@@ -23,11 +24,11 @@ import com.commafeed.backend.model.User;
|
||||
public class MailService implements Serializable {
|
||||
|
||||
@Inject
|
||||
ApplicationSettingsService applicationSettingsService;
|
||||
CommaFeedConfiguration config;
|
||||
|
||||
public void sendMail(User user, String subject, String content) throws Exception {
|
||||
|
||||
ApplicationSettings settings = applicationSettingsService.get();
|
||||
ApplicationSettings settings = config.getApplicationSettings();
|
||||
|
||||
final String username = settings.getSmtpUserName();
|
||||
final String password = settings.getSmtpPassword();
|
||||
@@ -41,6 +42,7 @@ public class MailService implements Serializable {
|
||||
props.put("mail.smtp.port", "" + settings.getSmtpPort());
|
||||
|
||||
Session session = Session.getInstance(props, new Authenticator() {
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(username, password);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.commafeed.backend.services;
|
||||
package com.commafeed.backend.service;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
@@ -1,12 +1,13 @@
|
||||
package com.commafeed.backend.pubsubhubbub;
|
||||
package com.commafeed.backend.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.NameValuePair;
|
||||
@@ -16,14 +17,13 @@ import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.apache.wicket.util.io.IOUtils;
|
||||
|
||||
import com.commafeed.CommaFeedConfiguration;
|
||||
import com.commafeed.backend.HttpGetter;
|
||||
import com.commafeed.backend.feeds.FeedRefreshTaskGiver;
|
||||
import com.commafeed.backend.feeds.FeedUtils;
|
||||
import com.commafeed.backend.feed.FeedQueues;
|
||||
import com.commafeed.backend.feed.FeedUtils;
|
||||
import com.commafeed.backend.model.Feed;
|
||||
import com.commafeed.backend.services.ApplicationSettingsService;
|
||||
import com.commafeed.frontend.rest.resources.PubSubHubbubCallbackREST;
|
||||
import com.commafeed.frontend.resource.PubSubHubbubCallbackREST;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
/**
|
||||
@@ -31,13 +31,11 @@ import com.google.common.collect.Lists;
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
public class SubscriptionHandler {
|
||||
@RequiredArgsConstructor
|
||||
public class PubSubService {
|
||||
|
||||
@Inject
|
||||
ApplicationSettingsService applicationSettingsService;
|
||||
|
||||
@Inject
|
||||
FeedRefreshTaskGiver taskGiver;
|
||||
private final CommaFeedConfiguration config;
|
||||
private final FeedQueues queues;
|
||||
|
||||
public void subscribe(Feed feed) {
|
||||
|
||||
@@ -51,7 +49,7 @@ public class SubscriptionHandler {
|
||||
|
||||
String hub = feed.getPushHub();
|
||||
String topic = feed.getPushTopic();
|
||||
String publicUrl = FeedUtils.removeTrailingSlash(applicationSettingsService.get().getPublicUrl());
|
||||
String publicUrl = FeedUtils.removeTrailingSlash(config.getApplicationSettings().getPublicUrl());
|
||||
|
||||
log.debug("sending new pubsub subscription to {} for {}", hub, topic);
|
||||
|
||||
@@ -81,7 +79,7 @@ public class SubscriptionHandler {
|
||||
if (code == 400 && StringUtils.contains(message, pushpressError)) {
|
||||
String[] tokens = message.split(" ");
|
||||
feed.setPushTopic(tokens[tokens.length - 1]);
|
||||
taskGiver.giveBack(feed);
|
||||
queues.giveBack(feed);
|
||||
log.debug("handled pushpress subfeed {} : {}", topic, feed.getPushTopic());
|
||||
} else {
|
||||
throw new Exception("Unexpected response code: " + code + " " + response.getStatusLine().getReasonPhrase() + " - "
|
||||
127
src/main/java/com/commafeed/backend/service/StartupService.java
Normal file
127
src/main/java/com/commafeed/backend/service/StartupService.java
Normal file
@@ -0,0 +1,127 @@
|
||||
package com.commafeed.backend.service;
|
||||
|
||||
import io.dropwizard.lifecycle.Managed;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.InitialContext;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import liquibase.Liquibase;
|
||||
import liquibase.database.Database;
|
||||
import liquibase.database.DatabaseFactory;
|
||||
import liquibase.database.core.PostgresDatabase;
|
||||
import liquibase.database.jvm.JdbcConnection;
|
||||
import liquibase.resource.ClassLoaderResourceAccessor;
|
||||
import liquibase.resource.ResourceAccessor;
|
||||
import liquibase.structure.DatabaseObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl;
|
||||
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
|
||||
import org.hibernate.internal.SessionFactoryImpl;
|
||||
|
||||
import com.commafeed.CommaFeedApplication;
|
||||
import com.commafeed.backend.dao.UnitOfWork;
|
||||
import com.commafeed.backend.dao.UserDAO;
|
||||
import com.commafeed.backend.model.UserRole.Role;
|
||||
|
||||
@Slf4j
|
||||
public class StartupService implements Managed {
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
private UserDAO userDAO;
|
||||
private UserService userService;
|
||||
|
||||
public StartupService(SessionFactory sessionFactory, UserDAO userDAO, UserService userService) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
this.userDAO = userDAO;
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() throws Exception {
|
||||
updateSchema();
|
||||
new UnitOfWork<Void>(sessionFactory) {
|
||||
@Override
|
||||
protected Void runInSession() throws Exception {
|
||||
if (userDAO.findByName(CommaFeedApplication.USERNAME_ADMIN) == null) {
|
||||
initialData();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}.run();
|
||||
}
|
||||
|
||||
private void updateSchema() {
|
||||
try {
|
||||
Context context = null;
|
||||
Connection connection = null;
|
||||
try {
|
||||
Thread currentThread = Thread.currentThread();
|
||||
ClassLoader classLoader = currentThread.getContextClassLoader();
|
||||
ResourceAccessor accessor = new ClassLoaderResourceAccessor(classLoader);
|
||||
|
||||
context = new InitialContext();
|
||||
DataSource dataSource = getDataSource(sessionFactory);
|
||||
connection = dataSource.getConnection();
|
||||
JdbcConnection jdbcConnection = new JdbcConnection(connection);
|
||||
|
||||
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(jdbcConnection);
|
||||
|
||||
if (database instanceof PostgresDatabase) {
|
||||
database = new PostgresDatabase() {
|
||||
@Override
|
||||
public String escapeObjectName(String objectName, Class<? extends DatabaseObject> objectType) {
|
||||
return objectName;
|
||||
}
|
||||
};
|
||||
database.setConnection(jdbcConnection);
|
||||
}
|
||||
|
||||
Liquibase liq = new Liquibase("migrations.xml", accessor, database);
|
||||
liq.update("prod");
|
||||
} finally {
|
||||
if (context != null) {
|
||||
context.close();
|
||||
}
|
||||
if (connection != null) {
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void initialData() {
|
||||
log.info("Populating database with default values");
|
||||
try {
|
||||
userService.register(CommaFeedApplication.USERNAME_ADMIN, "admin", "admin@commafeed.com", Arrays.asList(Role.ADMIN, Role.USER),
|
||||
true);
|
||||
userService.register(CommaFeedApplication.USERNAME_DEMO, "demo", "demo@commafeed.com", Arrays.asList(Role.USER), true);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
|
||||
}
|
||||
|
||||
private static DataSource getDataSource(SessionFactory sessionFactory) {
|
||||
if (sessionFactory instanceof SessionFactoryImpl) {
|
||||
ConnectionProvider cp = ((SessionFactoryImpl) sessionFactory).getConnectionProvider();
|
||||
if (cp instanceof DatasourceConnectionProviderImpl) {
|
||||
return ((DatasourceConnectionProviderImpl) cp).getDataSource();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,18 +1,17 @@
|
||||
package com.commafeed.backend.services;
|
||||
package com.commafeed.backend.service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.ejb.Stateless;
|
||||
import javax.inject.Inject;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
|
||||
import com.commafeed.CommaFeedConfiguration;
|
||||
import com.commafeed.backend.dao.FeedCategoryDAO;
|
||||
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
||||
import com.commafeed.backend.dao.UserDAO;
|
||||
import com.commafeed.backend.dao.UserSettingsDAO;
|
||||
import com.commafeed.backend.model.User;
|
||||
@@ -20,29 +19,16 @@ import com.commafeed.backend.model.UserRole;
|
||||
import com.commafeed.backend.model.UserRole.Role;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
@Stateless
|
||||
@RequiredArgsConstructor
|
||||
public class UserService {
|
||||
|
||||
@Inject
|
||||
UserDAO userDAO;
|
||||
private final FeedCategoryDAO feedCategoryDAO;
|
||||
private final UserDAO userDAO;
|
||||
private final UserSettingsDAO userSettingsDAO;
|
||||
|
||||
@Inject
|
||||
FeedEntryStatusDAO feedEntryStatusDAO;
|
||||
|
||||
@Inject
|
||||
FeedCategoryDAO feedCategoryDAO;
|
||||
|
||||
@Inject
|
||||
UserSettingsDAO userSettingsDAO;
|
||||
|
||||
@Inject
|
||||
PasswordEncryptionService encryptionService;
|
||||
|
||||
@Inject
|
||||
ApplicationSettingsService applicationSettingsService;
|
||||
|
||||
@Inject
|
||||
FeedSubscriptionService feedSubscriptionService;
|
||||
private final FeedSubscriptionService feedSubscriptionService;
|
||||
private final PasswordEncryptionService encryptionService;
|
||||
private final CommaFeedConfiguration config;
|
||||
|
||||
public User login(String name, String password) {
|
||||
if (name == null || password == null) {
|
||||
@@ -63,7 +49,7 @@ public class UserService {
|
||||
user.setLastLogin(now);
|
||||
saveUser = true;
|
||||
}
|
||||
if (applicationSettingsService.get().isHeavyLoad()
|
||||
if (config.getApplicationSettings().isHeavyLoad()
|
||||
&& (user.getLastFullRefresh() == null || user.getLastFullRefresh().before(DateUtils.addMinutes(now, -30)))) {
|
||||
user.setLastFullRefresh(now);
|
||||
saveUser = true;
|
||||
@@ -89,7 +75,7 @@ public class UserService {
|
||||
Preconditions.checkNotNull(password);
|
||||
|
||||
if (!forceRegistration) {
|
||||
Preconditions.checkState(applicationSettingsService.get().isAllowRegistrations(),
|
||||
Preconditions.checkState(config.getApplicationSettings().isAllowRegistrations(),
|
||||
"Registrations are closed on this CommaFeed instance");
|
||||
|
||||
Preconditions.checkNotNull(email);
|
||||
@@ -1,60 +0,0 @@
|
||||
package com.commafeed.backend.services;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.LogManager;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.commafeed.backend.dao.ApplicationSettingsDAO;
|
||||
import com.commafeed.backend.model.ApplicationSettings;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
@ApplicationScoped
|
||||
public class ApplicationSettingsService {
|
||||
|
||||
@Inject
|
||||
ApplicationSettingsDAO applicationSettingsDAO;
|
||||
|
||||
private ApplicationSettings settings;
|
||||
|
||||
@PostConstruct
|
||||
private void init() {
|
||||
settings = Iterables.getFirst(applicationSettingsDAO.findAll(), null);
|
||||
}
|
||||
|
||||
public ApplicationSettings get() {
|
||||
return settings;
|
||||
}
|
||||
|
||||
public void save(ApplicationSettings settings) {
|
||||
applicationSettingsDAO.saveOrUpdate(settings);
|
||||
this.settings = settings;
|
||||
applyLogLevel();
|
||||
}
|
||||
|
||||
public Date getUnreadThreshold() {
|
||||
int keepStatusDays = get().getKeepStatusDays();
|
||||
return keepStatusDays > 0 ? DateUtils.addDays(new Date(), -1 * keepStatusDays) : null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void applyLogLevel() {
|
||||
String logLevel = get().getLogLevel();
|
||||
Level level = Level.toLevel(logLevel);
|
||||
|
||||
Enumeration<Logger> loggers = LogManager.getCurrentLoggers();
|
||||
while (loggers.hasMoreElements()) {
|
||||
Logger logger = loggers.nextElement();
|
||||
if (logger.getName().startsWith("com.commafeed")) {
|
||||
logger.setLevel(level);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package com.commafeed.backend.services;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.ejb.Lock;
|
||||
import javax.ejb.LockType;
|
||||
import javax.ejb.Singleton;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
|
||||
import com.commafeed.backend.dao.FeedDAO;
|
||||
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
||||
import com.commafeed.backend.feeds.FeedUtils;
|
||||
import com.commafeed.backend.model.Feed;
|
||||
|
||||
@Singleton
|
||||
public class FeedService {
|
||||
|
||||
@Inject
|
||||
FeedDAO feedDAO;
|
||||
|
||||
@Inject
|
||||
FeedSubscriptionDAO feedSubscriptionDAO;
|
||||
|
||||
@Lock(LockType.WRITE)
|
||||
public Feed findOrCreate(String url) {
|
||||
Feed feed = feedDAO.findByUrl(url);
|
||||
if (feed == null) {
|
||||
String normalized = FeedUtils.normalizeURL(url);
|
||||
feed = new Feed();
|
||||
feed.setUrl(url);
|
||||
feed.setNormalizedUrl(normalized);
|
||||
feed.setNormalizedUrlHash(DigestUtils.sha1Hex(normalized));
|
||||
feed.setDisabledUntil(new Date(0));
|
||||
feedDAO.saveOrUpdate(feed);
|
||||
}
|
||||
return feed;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
package com.commafeed.backend.startup;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
import javax.ejb.Stateless;
|
||||
import javax.ejb.TransactionManagement;
|
||||
import javax.ejb.TransactionManagementType;
|
||||
import javax.naming.Context;
|
||||
import javax.naming.InitialContext;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import liquibase.Liquibase;
|
||||
import liquibase.database.Database;
|
||||
import liquibase.database.DatabaseFactory;
|
||||
import liquibase.database.core.PostgresDatabase;
|
||||
import liquibase.database.jvm.JdbcConnection;
|
||||
import liquibase.resource.ClassLoaderResourceAccessor;
|
||||
import liquibase.resource.ResourceAccessor;
|
||||
import liquibase.structure.DatabaseObject;
|
||||
|
||||
import com.commafeed.backend.services.ApplicationPropertiesService;
|
||||
|
||||
/**
|
||||
* Executes needed liquibase database schema upgrades
|
||||
*
|
||||
*/
|
||||
@Stateless
|
||||
@TransactionManagement(TransactionManagementType.BEAN)
|
||||
public class DatabaseUpdater {
|
||||
|
||||
public void update() {
|
||||
ApplicationPropertiesService properties = ApplicationPropertiesService.get();
|
||||
String datasourceName = properties.getDatasource();
|
||||
try {
|
||||
Context context = null;
|
||||
Connection connection = null;
|
||||
try {
|
||||
Thread currentThread = Thread.currentThread();
|
||||
ClassLoader classLoader = currentThread.getContextClassLoader();
|
||||
ResourceAccessor accessor = new ClassLoaderResourceAccessor(classLoader);
|
||||
|
||||
context = new InitialContext();
|
||||
DataSource dataSource = (DataSource) context.lookup(datasourceName);
|
||||
connection = dataSource.getConnection();
|
||||
JdbcConnection jdbcConnection = new JdbcConnection(connection);
|
||||
|
||||
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(jdbcConnection);
|
||||
|
||||
if (database instanceof PostgresDatabase) {
|
||||
database = new PostgresDatabase() {
|
||||
@Override
|
||||
public String escapeObjectName(String objectName, Class<? extends DatabaseObject> objectType) {
|
||||
return objectName;
|
||||
}
|
||||
};
|
||||
database.setConnection(jdbcConnection);
|
||||
}
|
||||
|
||||
Liquibase liq = new Liquibase("changelogs/db.changelog-master.xml", accessor, database);
|
||||
liq.update("prod");
|
||||
} finally {
|
||||
if (context != null) {
|
||||
context.close();
|
||||
}
|
||||
if (connection != null) {
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
package com.commafeed.backend.startup;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.ejb.ConcurrencyManagement;
|
||||
import javax.ejb.ConcurrencyManagementType;
|
||||
import javax.ejb.Singleton;
|
||||
import javax.ejb.Startup;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import com.commafeed.backend.dao.ApplicationSettingsDAO;
|
||||
import com.commafeed.backend.feeds.FeedRefreshTaskGiver;
|
||||
import com.commafeed.backend.model.ApplicationSettings;
|
||||
import com.commafeed.backend.model.UserRole.Role;
|
||||
import com.commafeed.backend.services.ApplicationSettingsService;
|
||||
import com.commafeed.backend.services.UserService;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
/**
|
||||
* Starting point of the application
|
||||
*
|
||||
*/
|
||||
@Startup
|
||||
@Singleton
|
||||
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
|
||||
@Slf4j
|
||||
public class StartupBean {
|
||||
|
||||
public static final String USERNAME_ADMIN = "admin";
|
||||
public static final String USERNAME_DEMO = "demo";
|
||||
|
||||
@Inject
|
||||
DatabaseUpdater databaseUpdater;
|
||||
|
||||
@Inject
|
||||
ApplicationSettingsDAO applicationSettingsDAO;
|
||||
|
||||
@Inject
|
||||
UserService userService;
|
||||
|
||||
@Inject
|
||||
FeedRefreshTaskGiver taskGiver;
|
||||
|
||||
@Inject
|
||||
ApplicationSettingsService applicationSettingsService;
|
||||
|
||||
private long startupTime;
|
||||
private Map<String, String> supportedLanguages = Maps.newHashMap();
|
||||
|
||||
@PostConstruct
|
||||
private void init() {
|
||||
|
||||
startupTime = System.currentTimeMillis();
|
||||
|
||||
// update database schema
|
||||
databaseUpdater.update();
|
||||
|
||||
if (applicationSettingsDAO.getCount() == 0) {
|
||||
// import initial data
|
||||
initialData();
|
||||
}
|
||||
applicationSettingsService.applyLogLevel();
|
||||
|
||||
initSupportedLanguages();
|
||||
|
||||
// start fetching feeds
|
||||
taskGiver.start();
|
||||
}
|
||||
|
||||
private void initSupportedLanguages() {
|
||||
Properties props = new Properties();
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = getClass().getResourceAsStream("/i18n/languages.properties");
|
||||
props.load(new InputStreamReader(is, "UTF-8"));
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(is);
|
||||
}
|
||||
for (Object key : props.keySet()) {
|
||||
supportedLanguages.put(key.toString(), props.getProperty(key.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* create default users
|
||||
*/
|
||||
private void initialData() {
|
||||
log.info("Populating database with default values");
|
||||
|
||||
ApplicationSettings settings = new ApplicationSettings();
|
||||
settings.setAnnouncement("Set the Public URL in the admin section!");
|
||||
applicationSettingsService.save(settings);
|
||||
|
||||
try {
|
||||
userService.register(USERNAME_ADMIN, "admin", "admin@commafeed.com", Arrays.asList(Role.ADMIN, Role.USER), true);
|
||||
userService.register(USERNAME_DEMO, "demo", "demo@commafeed.com", Arrays.asList(Role.USER), true);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public long getStartupTime() {
|
||||
return startupTime;
|
||||
}
|
||||
|
||||
public Map<String, String> getSupportedLanguages() {
|
||||
return supportedLanguages;
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
package com.commafeed.frontend;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
import javax.annotation.processing.SupportedAnnotationTypes;
|
||||
import javax.annotation.processing.SupportedOptions;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.tools.Diagnostic.Kind;
|
||||
import javax.tools.FileObject;
|
||||
import javax.tools.StandardLocation;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.wicket.util.io.IOUtils;
|
||||
|
||||
import com.commafeed.frontend.model.Entries;
|
||||
import com.commafeed.frontend.model.request.MarkRequest;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.wordnik.swagger.annotations.Api;
|
||||
import com.wordnik.swagger.core.Documentation;
|
||||
import com.wordnik.swagger.core.DocumentationEndPoint;
|
||||
import com.wordnik.swagger.core.SwaggerSpec;
|
||||
import com.wordnik.swagger.core.util.TypeUtil;
|
||||
import com.wordnik.swagger.jaxrs.HelpApi;
|
||||
import com.wordnik.swagger.jaxrs.JaxrsApiReader;
|
||||
|
||||
@SupportedAnnotationTypes("com.wordnik.swagger.annotations.Api")
|
||||
@SupportedOptions("outputDirectory")
|
||||
public class APIGenerator extends AbstractProcessor {
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
try {
|
||||
return processInternal(annotations, roundEnv);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean processInternal(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) throws Exception {
|
||||
JaxrsApiReader.setFormatString("");
|
||||
TypeUtil.addAllowablePackage(Entries.class.getPackage().getName());
|
||||
TypeUtil.addAllowablePackage(MarkRequest.class.getPackage().getName());
|
||||
|
||||
String apiVersion = "1.0";
|
||||
String swaggerVersion = SwaggerSpec.version();
|
||||
String basePath = "../rest";
|
||||
|
||||
Documentation doc = new Documentation();
|
||||
for (Element element : roundEnv.getElementsAnnotatedWith(Api.class)) {
|
||||
TypeElement type = (TypeElement) element;
|
||||
String fqn = type.getQualifiedName().toString();
|
||||
Class<?> resource = Class.forName(fqn);
|
||||
|
||||
Api api = resource.getAnnotation(Api.class);
|
||||
String apiPath = api.value();
|
||||
|
||||
Documentation apiDoc = JaxrsApiReader.read(resource, apiVersion, swaggerVersion, basePath, apiPath);
|
||||
apiDoc = new HelpApi(null).filterDocs(apiDoc, null, null, null, null);
|
||||
|
||||
apiDoc.setSwaggerVersion(swaggerVersion);
|
||||
apiDoc.setApiVersion(apiVersion);
|
||||
write(apiDoc.getResourcePath(), apiDoc, element);
|
||||
|
||||
doc.addApi(new DocumentationEndPoint(api.value(), api.description()));
|
||||
|
||||
}
|
||||
doc.setSwaggerVersion(swaggerVersion);
|
||||
doc.setApiVersion(apiVersion);
|
||||
|
||||
write(doc.getResourcePath(), doc, null);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void write(String resourcePath, Object doc, Element element) throws Exception {
|
||||
String fileName = StringUtils.defaultString(resourcePath, "resources");
|
||||
fileName = StringUtils.removeStart(fileName, "/");
|
||||
|
||||
FileObject resource = null;
|
||||
try {
|
||||
resource = processingEnv.getFiler().createResource(StandardLocation.SOURCE_OUTPUT, "", fileName, element);
|
||||
} catch (Exception e) {
|
||||
// already processed
|
||||
}
|
||||
if (resource != null) {
|
||||
OutputStream os = resource.openOutputStream();
|
||||
try {
|
||||
IOUtils.write(new ObjectMapper().writeValueAsString(doc), os, "UTF-8");
|
||||
} finally {
|
||||
IOUtils.closeQuietly(os);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,216 +0,0 @@
|
||||
package com.commafeed.frontend;
|
||||
|
||||
import javax.enterprise.inject.spi.BeanManager;
|
||||
import javax.inject.Inject;
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.NamingException;
|
||||
import javax.servlet.http.Cookie;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.wicket.Application;
|
||||
import org.apache.wicket.Component;
|
||||
import org.apache.wicket.IRequestCycleProvider;
|
||||
import org.apache.wicket.Page;
|
||||
import org.apache.wicket.RuntimeConfigurationType;
|
||||
import org.apache.wicket.Session;
|
||||
import org.apache.wicket.ajax.AjaxRequestTarget;
|
||||
import org.apache.wicket.authentication.strategy.DefaultAuthenticationStrategy;
|
||||
import org.apache.wicket.authorization.Action;
|
||||
import org.apache.wicket.authorization.IAuthorizationStrategy;
|
||||
import org.apache.wicket.authroles.authentication.AbstractAuthenticatedWebSession;
|
||||
import org.apache.wicket.authroles.authentication.AuthenticatedWebApplication;
|
||||
import org.apache.wicket.authroles.authorization.strategies.role.Roles;
|
||||
import org.apache.wicket.cdi.CdiConfiguration;
|
||||
import org.apache.wicket.cdi.CdiContainer;
|
||||
import org.apache.wicket.cdi.ConversationPropagation;
|
||||
import org.apache.wicket.core.request.handler.PageProvider;
|
||||
import org.apache.wicket.core.request.handler.RenderPageRequestHandler;
|
||||
import org.apache.wicket.core.request.handler.RenderPageRequestHandler.RedirectPolicy;
|
||||
import org.apache.wicket.markup.head.IHeaderResponse;
|
||||
import org.apache.wicket.markup.head.filter.JavaScriptFilteredIntoFooterHeaderResponse;
|
||||
import org.apache.wicket.markup.html.IHeaderResponseDecorator;
|
||||
import org.apache.wicket.markup.html.WebPage;
|
||||
import org.apache.wicket.request.IRequestHandler;
|
||||
import org.apache.wicket.request.Request;
|
||||
import org.apache.wicket.request.Response;
|
||||
import org.apache.wicket.request.Url;
|
||||
import org.apache.wicket.request.UrlRenderer;
|
||||
import org.apache.wicket.request.component.IRequestableComponent;
|
||||
import org.apache.wicket.request.cycle.AbstractRequestCycleListener;
|
||||
import org.apache.wicket.request.cycle.RequestCycle;
|
||||
import org.apache.wicket.request.cycle.RequestCycleContext;
|
||||
import org.apache.wicket.util.cookies.CookieUtils;
|
||||
|
||||
import com.commafeed.backend.services.ApplicationPropertiesService;
|
||||
import com.commafeed.backend.services.ApplicationSettingsService;
|
||||
import com.commafeed.frontend.pages.DemoLoginPage;
|
||||
import com.commafeed.frontend.pages.HomePage;
|
||||
import com.commafeed.frontend.pages.LogoutPage;
|
||||
import com.commafeed.frontend.pages.NextUnreadRedirectPage;
|
||||
import com.commafeed.frontend.pages.PasswordRecoveryCallbackPage;
|
||||
import com.commafeed.frontend.pages.PasswordRecoveryPage;
|
||||
import com.commafeed.frontend.pages.WelcomePage;
|
||||
import com.commafeed.frontend.utils.WicketUtils;
|
||||
import com.commafeed.frontend.utils.exception.DisplayExceptionPage;
|
||||
|
||||
@Slf4j
|
||||
public class CommaFeedApplication extends AuthenticatedWebApplication {
|
||||
|
||||
@Inject
|
||||
ApplicationSettingsService applicationSettingsService;
|
||||
|
||||
public CommaFeedApplication() {
|
||||
super();
|
||||
boolean prod = ApplicationPropertiesService.get().isProduction();
|
||||
setConfigurationType(prod ? RuntimeConfigurationType.DEPLOYMENT : RuntimeConfigurationType.DEVELOPMENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
setupInjection();
|
||||
setupSecurity();
|
||||
|
||||
mountPage("welcome", WelcomePage.class);
|
||||
mountPage("demo", DemoLoginPage.class);
|
||||
|
||||
mountPage("recover", PasswordRecoveryPage.class);
|
||||
mountPage("recover2", PasswordRecoveryCallbackPage.class);
|
||||
|
||||
mountPage("logout", LogoutPage.class);
|
||||
mountPage("error", DisplayExceptionPage.class);
|
||||
|
||||
mountPage("next", NextUnreadRedirectPage.class);
|
||||
|
||||
getMarkupSettings().setStripWicketTags(true);
|
||||
getMarkupSettings().setCompressWhitespace(true);
|
||||
getMarkupSettings().setDefaultMarkupEncoding("UTF-8");
|
||||
|
||||
setHeaderResponseDecorator(new IHeaderResponseDecorator() {
|
||||
@Override
|
||||
public IHeaderResponse decorate(IHeaderResponse response) {
|
||||
return new JavaScriptFilteredIntoFooterHeaderResponse(response, "footer-container");
|
||||
}
|
||||
});
|
||||
|
||||
getRequestCycleListeners().add(new AbstractRequestCycleListener() {
|
||||
@Override
|
||||
public IRequestHandler onException(RequestCycle cycle, Exception ex) {
|
||||
AjaxRequestTarget target = cycle.find(AjaxRequestTarget.class);
|
||||
// redirect to the error page if ajax request, render error on current page otherwise
|
||||
RedirectPolicy policy = target == null ? RedirectPolicy.NEVER_REDIRECT : RedirectPolicy.AUTO_REDIRECT;
|
||||
return new RenderPageRequestHandler(new PageProvider(new DisplayExceptionPage(ex)), policy);
|
||||
}
|
||||
});
|
||||
|
||||
setRequestCycleProvider(new IRequestCycleProvider() {
|
||||
@Override
|
||||
public RequestCycle get(RequestCycleContext context) {
|
||||
return new RequestCycle(context) {
|
||||
@Override
|
||||
protected UrlRenderer newUrlRenderer() {
|
||||
return new UrlRenderer(getRequest()) {
|
||||
@Override
|
||||
public String renderUrl(Url url) {
|
||||
// override wicket's relative-to-absolute url conversion with what we know is the correct protocol
|
||||
String publicUrl = applicationSettingsService.get().getPublicUrl();
|
||||
if (StringUtils.isNotBlank(publicUrl)) {
|
||||
Url parsed = Url.parse(publicUrl);
|
||||
url.setProtocol(parsed.getProtocol());
|
||||
url.setPort(parsed.getPort());
|
||||
}
|
||||
return super.renderUrl(url);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setupSecurity() {
|
||||
getSecuritySettings().setAuthenticationStrategy(new DefaultAuthenticationStrategy("LoggedIn") {
|
||||
|
||||
private CookieUtils cookieUtils = null;
|
||||
|
||||
@Override
|
||||
protected CookieUtils getCookieUtils() {
|
||||
|
||||
if (cookieUtils == null) {
|
||||
cookieUtils = new CookieUtils() {
|
||||
@Override
|
||||
protected void initializeCookie(Cookie cookie) {
|
||||
super.initializeCookie(cookie);
|
||||
cookie.setHttpOnly(true);
|
||||
}
|
||||
};
|
||||
}
|
||||
return cookieUtils;
|
||||
}
|
||||
});
|
||||
getSecuritySettings().setAuthorizationStrategy(new IAuthorizationStrategy() {
|
||||
|
||||
@Override
|
||||
public <T extends IRequestableComponent> boolean isInstantiationAuthorized(Class<T> componentClass) {
|
||||
boolean authorized = true;
|
||||
|
||||
boolean restricted = componentClass.isAnnotationPresent(SecurityCheck.class);
|
||||
if (restricted) {
|
||||
SecurityCheck annotation = componentClass.getAnnotation(SecurityCheck.class);
|
||||
Roles roles = CommaFeedSession.get().getRoles();
|
||||
authorized = roles.hasAnyRole(new Roles(annotation.value().name()));
|
||||
}
|
||||
return authorized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActionAuthorized(Component component, Action action) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Page> getHomePage() {
|
||||
return HomePage.class;
|
||||
}
|
||||
|
||||
protected void setupInjection() {
|
||||
try {
|
||||
BeanManager beanManager = (BeanManager) new InitialContext().lookup("java:comp/BeanManager");
|
||||
CdiContainer container = new CdiConfiguration(beanManager).setPropagation(ConversationPropagation.NONE).configure(this);
|
||||
container.getNonContextualManager().inject(this);
|
||||
} catch (NamingException e) {
|
||||
log.warn("Could not locate bean manager. CDI is disabled.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restartResponseAtSignInPage() {
|
||||
// preserve https if it was set
|
||||
RequestCycle.get().getUrlRenderer().setBaseUrl(Url.parse(WicketUtils.getClientFullUrl()));
|
||||
super.restartResponseAtSignInPage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Session newSession(Request request, Response response) {
|
||||
return new CommaFeedSession(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends WebPage> getSignInPageClass() {
|
||||
return WelcomePage.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends AbstractAuthenticatedWebSession> getWebSessionClass() {
|
||||
return CommaFeedSession.class;
|
||||
}
|
||||
|
||||
public static CommaFeedApplication get() {
|
||||
|
||||
return (CommaFeedApplication) Application.get();
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package com.commafeed.frontend;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import org.apache.wicket.Session;
|
||||
import org.apache.wicket.authroles.authentication.AuthenticatedWebSession;
|
||||
import org.apache.wicket.authroles.authorization.strategies.role.Roles;
|
||||
import org.apache.wicket.request.Request;
|
||||
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.model.UserRole.Role;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
public class CommaFeedSession extends AuthenticatedWebSession {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private User user;
|
||||
private Roles roles = new Roles();
|
||||
|
||||
@Getter(lazy = true)
|
||||
private final CommaFeedSessionServices services = newServices();
|
||||
|
||||
public CommaFeedSession(Request request) {
|
||||
super(request);
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public static CommaFeedSession get() {
|
||||
return (CommaFeedSession) Session.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Roles getRoles() {
|
||||
return roles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean authenticate(String userName, String password) {
|
||||
User user = getServices().getUserService().login(userName, password);
|
||||
setUser(user);
|
||||
return user != null;
|
||||
}
|
||||
|
||||
public void setUser(User user) {
|
||||
if (user == null) {
|
||||
this.user = null;
|
||||
this.roles = new Roles();
|
||||
} else {
|
||||
|
||||
Set<String> roleSet = Sets.newHashSet();
|
||||
for (Role role : getServices().getUserRoleDAO().findRoles(user)) {
|
||||
roleSet.add(role.name());
|
||||
}
|
||||
this.user = user;
|
||||
this.roles = new Roles(roleSet.toArray(new String[0]));
|
||||
}
|
||||
}
|
||||
|
||||
private CommaFeedSessionServices newServices() {
|
||||
return new CommaFeedSessionServices();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package com.commafeed.frontend;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import com.commafeed.backend.dao.UserRoleDAO;
|
||||
import com.commafeed.backend.services.UserService;
|
||||
|
||||
// extend Component in order to benefit from injection
|
||||
public class CommaFeedSessionServices extends Component {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Inject
|
||||
UserService userService;
|
||||
|
||||
@Inject
|
||||
UserRoleDAO userRoleDAO;
|
||||
|
||||
public CommaFeedSessionServices() {
|
||||
super("services");
|
||||
}
|
||||
|
||||
public UserService getUserService() {
|
||||
return userService;
|
||||
}
|
||||
|
||||
public UserRoleDAO getUserRoleDAO() {
|
||||
return userRoleDAO;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRender() {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package com.commafeed.frontend;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.annotation.WebFilter;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@WebFilter(urlPatterns = "/*")
|
||||
public class InterceptingFilter implements Filter {
|
||||
|
||||
private static final String HEADER_CORS = "Access-Control-Allow-Origin";
|
||||
private static final String HEADER_CORS_VALUE = "*";
|
||||
private static final String HEADER_CORS_METHODS = "Access-Control-Allow-Methods";
|
||||
private static final String HEADER_CORS_METHODS_VALUE = "POST, GET, OPTIONS";
|
||||
private static final String HEADER_CORS_MAXAGE = "Access-Control-Max-Age";
|
||||
private static final String HEADER_CORS_MAXAGE_VALUE = "2592000";
|
||||
private static final String HEADER_CORS_ALLOW_HEADERS = "Access-Control-Allow-Headers";
|
||||
private static final String HEADER_CORS_ALLOW_HEADERS_VALUE = "Authorization";
|
||||
private static final String HEADER_CORS_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
|
||||
private static final String HEADER_CORS_ALLOW_CREDENTIALS_VALUE = "true";
|
||||
|
||||
private static final String HEADER_X_UA_COMPATIBLE = "X-UA-Compatible";
|
||||
private static final String HEADER_X_UA_COMPATIBLE_VALUE = "IE=Edge,chrome=1";
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
HttpServletResponse resp = (HttpServletResponse) response;
|
||||
resp.addHeader(HEADER_CORS, HEADER_CORS_VALUE);
|
||||
resp.addHeader(HEADER_CORS_METHODS, HEADER_CORS_METHODS_VALUE);
|
||||
resp.addHeader(HEADER_CORS_MAXAGE, HEADER_CORS_MAXAGE_VALUE);
|
||||
resp.addHeader(HEADER_CORS_ALLOW_HEADERS, HEADER_CORS_ALLOW_HEADERS_VALUE);
|
||||
resp.addHeader(HEADER_CORS_ALLOW_CREDENTIALS, HEADER_CORS_ALLOW_CREDENTIALS_VALUE);
|
||||
|
||||
resp.addHeader(HEADER_X_UA_COMPATIBLE, HEADER_X_UA_COMPATIBLE_VALUE);
|
||||
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.commafeed.frontend;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import javax.enterprise.util.Nonbinding;
|
||||
import javax.interceptor.InterceptorBinding;
|
||||
|
||||
import com.commafeed.backend.model.UserRole.Role;
|
||||
|
||||
@Inherited
|
||||
@InterceptorBinding
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface SecurityCheck {
|
||||
|
||||
/**
|
||||
* Roles needed.
|
||||
*/
|
||||
@Nonbinding
|
||||
Role value() default Role.USER;
|
||||
|
||||
@Nonbinding
|
||||
boolean apiKeyAllowed() default false;
|
||||
}
|
||||
@@ -6,32 +6,32 @@ import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiProperty;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiClass("Entry details")
|
||||
@ApiModel("Entry details")
|
||||
@Data
|
||||
public class Category implements Serializable {
|
||||
|
||||
@ApiProperty("category id")
|
||||
@ApiModelProperty("category id")
|
||||
private String id;
|
||||
|
||||
@ApiProperty("parent category id")
|
||||
@ApiModelProperty("parent category id")
|
||||
private String parentId;
|
||||
|
||||
@ApiProperty("category id")
|
||||
@ApiModelProperty("category id")
|
||||
private String name;
|
||||
|
||||
@ApiProperty("category children categories")
|
||||
@ApiModelProperty("category children categories")
|
||||
private List<Category> children = Lists.newArrayList();
|
||||
|
||||
@ApiProperty("category feeds")
|
||||
@ApiModelProperty("category feeds")
|
||||
private List<Subscription> feeds = Lists.newArrayList();
|
||||
|
||||
@ApiProperty("wether the category is expanded or collapsed")
|
||||
@ApiModelProperty("wether the category is expanded or collapsed")
|
||||
private boolean expanded;
|
||||
|
||||
@ApiProperty("position of the category in the list")
|
||||
@ApiModelProperty("position of the category in the list")
|
||||
private Integer position;
|
||||
}
|
||||
@@ -6,42 +6,42 @@ import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiProperty;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiClass("List of entries with some metadata")
|
||||
@ApiModel("List of entries with some metadata")
|
||||
@Data
|
||||
public class Entries implements Serializable {
|
||||
|
||||
@ApiProperty("name of the feed or the category requested")
|
||||
@ApiModelProperty("name of the feed or the category requested")
|
||||
private String name;
|
||||
|
||||
@ApiProperty("error or warning message")
|
||||
@ApiModelProperty("error or warning message")
|
||||
private String message;
|
||||
|
||||
@ApiProperty("times the server tried to refresh the feed and failed")
|
||||
@ApiModelProperty("times the server tried to refresh the feed and failed")
|
||||
private int errorCount;
|
||||
|
||||
@ApiProperty("URL of the website, extracted from the feed")
|
||||
@ApiModelProperty("URL of the website, extracted from the feed")
|
||||
private String feedLink;
|
||||
|
||||
@ApiProperty("list generation timestamp")
|
||||
@ApiModelProperty("list generation timestamp")
|
||||
private long timestamp;
|
||||
|
||||
@ApiProperty("if the query has more elements")
|
||||
@ApiModelProperty("if the query has more elements")
|
||||
private boolean hasMore;
|
||||
|
||||
@ApiProperty("the requested offset")
|
||||
@ApiModelProperty("the requested offset")
|
||||
private int offset;
|
||||
|
||||
@ApiProperty("the requested limit")
|
||||
@ApiModelProperty("the requested limit")
|
||||
private int limit;
|
||||
|
||||
@ApiProperty("list of entries")
|
||||
@ApiModelProperty("list of entries")
|
||||
private List<Entry> entries = Lists.newArrayList();
|
||||
|
||||
@ApiProperty("if true, the unread flag was ignored in the request, all entries are returned regardless of their read status")
|
||||
@ApiModelProperty("if true, the unread flag was ignored in the request, all entries are returned regardless of their read status")
|
||||
private boolean ignoredReadStatus;
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.commafeed.backend.feeds.FeedUtils;
|
||||
import com.commafeed.backend.feed.FeedUtils;
|
||||
import com.commafeed.backend.model.FeedEntry;
|
||||
import com.commafeed.backend.model.FeedEntryContent;
|
||||
import com.commafeed.backend.model.FeedEntryStatus;
|
||||
@@ -17,11 +17,11 @@ import com.google.common.collect.Lists;
|
||||
import com.sun.syndication.feed.synd.SyndContentImpl;
|
||||
import com.sun.syndication.feed.synd.SyndEntry;
|
||||
import com.sun.syndication.feed.synd.SyndEntryImpl;
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiProperty;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiClass("Entry details")
|
||||
@ApiModel("Entry details")
|
||||
@Data
|
||||
public class Entry implements Serializable {
|
||||
|
||||
@@ -78,63 +78,63 @@ public class Entry implements Serializable {
|
||||
return entry;
|
||||
}
|
||||
|
||||
@ApiProperty("entry id")
|
||||
@ApiModelProperty("entry id")
|
||||
private String id;
|
||||
|
||||
@ApiProperty("entry guid")
|
||||
@ApiModelProperty("entry guid")
|
||||
private String guid;
|
||||
|
||||
@ApiProperty("entry title")
|
||||
@ApiModelProperty("entry title")
|
||||
private String title;
|
||||
|
||||
@ApiProperty("entry content")
|
||||
@ApiModelProperty("entry content")
|
||||
private String content;
|
||||
|
||||
@ApiProperty("wether entry content and title are rtl")
|
||||
@ApiModelProperty("wether entry content and title are rtl")
|
||||
private boolean rtl;
|
||||
|
||||
@ApiProperty("entry author")
|
||||
@ApiModelProperty("entry author")
|
||||
private String author;
|
||||
|
||||
@ApiProperty("entry enclosure url, if any")
|
||||
@ApiModelProperty("entry enclosure url, if any")
|
||||
private String enclosureUrl;
|
||||
|
||||
@ApiProperty("entry enclosure mime type, if any")
|
||||
@ApiModelProperty("entry enclosure mime type, if any")
|
||||
private String enclosureType;
|
||||
|
||||
@ApiProperty("entry publication date")
|
||||
@ApiModelProperty("entry publication date")
|
||||
private Date date;
|
||||
|
||||
@ApiProperty("entry insertion date in the database")
|
||||
@ApiModelProperty("entry insertion date in the database")
|
||||
private Date insertedDate;
|
||||
|
||||
@ApiProperty("feed id")
|
||||
@ApiModelProperty("feed id")
|
||||
private String feedId;
|
||||
|
||||
@ApiProperty("feed name")
|
||||
@ApiModelProperty("feed name")
|
||||
private String feedName;
|
||||
|
||||
@ApiProperty("this entry's feed url")
|
||||
@ApiModelProperty("this entry's feed url")
|
||||
private String feedUrl;
|
||||
|
||||
@ApiProperty("this entry's website url")
|
||||
@ApiModelProperty("this entry's website url")
|
||||
private String feedLink;
|
||||
|
||||
@ApiProperty(value = "The favicon url to use for this feed")
|
||||
@ApiModelProperty(value = "The favicon url to use for this feed")
|
||||
private String iconUrl;
|
||||
|
||||
@ApiProperty("entry url")
|
||||
@ApiModelProperty("entry url")
|
||||
private String url;
|
||||
|
||||
@ApiProperty("read sttaus")
|
||||
@ApiModelProperty("read sttaus")
|
||||
private boolean read;
|
||||
|
||||
@ApiProperty("starred status")
|
||||
@ApiModelProperty("starred status")
|
||||
private boolean starred;
|
||||
|
||||
@ApiProperty("wether the entry is still markable (old entry statuses are discarded)")
|
||||
@ApiModelProperty("wether the entry is still markable (old entry statuses are discarded)")
|
||||
private boolean markable;
|
||||
|
||||
@ApiProperty("tags")
|
||||
@ApiModelProperty("tags")
|
||||
private List<String> tags;
|
||||
}
|
||||
|
||||
@@ -7,9 +7,9 @@ import lombok.Data;
|
||||
|
||||
import com.commafeed.backend.model.Feed;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
|
||||
@ApiClass("Feed count")
|
||||
@ApiModel("Feed count")
|
||||
@Data
|
||||
public class FeedCount implements Serializable {
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@ import java.io.Serializable;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiClass("Feed details")
|
||||
@ApiModel("Feed details")
|
||||
@Data
|
||||
public class FeedInfo implements Serializable {
|
||||
|
||||
|
||||
@@ -1,21 +1,18 @@
|
||||
package com.commafeed.frontend.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiClass("Server infos")
|
||||
@ApiModel("Server infos")
|
||||
@Data
|
||||
public class ServerInfo implements Serializable {
|
||||
|
||||
private String announcement;
|
||||
private String version;
|
||||
private String gitCommit;
|
||||
private Map<String, String> supportedLanguages = Maps.newHashMap();
|
||||
|
||||
}
|
||||
|
||||
@@ -4,41 +4,41 @@ import java.io.Serializable;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiProperty;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiClass("User settings")
|
||||
@ApiModel("User settings")
|
||||
@Data
|
||||
public class Settings implements Serializable {
|
||||
|
||||
@ApiProperty(value = "user's preferred language, english if none")
|
||||
@ApiModelProperty(value = "user's preferred language, english if none")
|
||||
private String language;
|
||||
|
||||
@ApiProperty(value = "user reads all entries or unread entries only", allowableValues = "all,unread", required = true)
|
||||
@ApiModelProperty(value = "user reads all entries or unread entries only", allowableValues = "all,unread", required = true)
|
||||
private String readingMode;
|
||||
|
||||
@ApiProperty(value = "user reads entries in ascending or descending order", allowableValues = "asc,desc", required = true)
|
||||
@ApiModelProperty(value = "user reads entries in ascending or descending order", allowableValues = "asc,desc", required = true)
|
||||
private String readingOrder;
|
||||
|
||||
@ApiProperty(value = "user viewing mode, either title-only or expande view", allowableValues = "title,expanded", required = true)
|
||||
@ApiModelProperty(value = "user viewing mode, either title-only or expande view", allowableValues = "title,expanded", required = true)
|
||||
private String viewMode;
|
||||
|
||||
@ApiProperty(value = "user wants category and feeds with no unread entries shown", required = true)
|
||||
@ApiModelProperty(value = "user wants category and feeds with no unread entries shown", required = true)
|
||||
private boolean showRead;
|
||||
|
||||
@ApiProperty(value = "In expanded view, scroll through entries mark them as read", required = true)
|
||||
@ApiModelProperty(value = "In expanded view, scroll through entries mark them as read", required = true)
|
||||
private boolean scrollMarks;
|
||||
|
||||
@ApiProperty(value = "user's selected theme")
|
||||
@ApiModelProperty(value = "user's selected theme")
|
||||
private String theme;
|
||||
|
||||
@ApiProperty(value = "user's custom css for the website")
|
||||
@ApiModelProperty(value = "user's custom css for the website")
|
||||
private String customCss;
|
||||
|
||||
@ApiProperty(value = "user's preferred scroll speed when navigating between entries")
|
||||
|
||||
@ApiModelProperty(value = "user's preferred scroll speed when navigating between entries")
|
||||
private int scrollSpeed;
|
||||
|
||||
|
||||
private boolean email;
|
||||
private boolean gmail;
|
||||
private boolean facebook;
|
||||
|
||||
@@ -5,15 +5,15 @@ import java.util.Date;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.commafeed.backend.feeds.FeedUtils;
|
||||
import com.commafeed.backend.feed.FeedUtils;
|
||||
import com.commafeed.backend.model.Feed;
|
||||
import com.commafeed.backend.model.FeedCategory;
|
||||
import com.commafeed.backend.model.FeedSubscription;
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiProperty;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiClass("User information")
|
||||
@ApiModel("User information")
|
||||
@Data
|
||||
public class Subscription implements Serializable {
|
||||
|
||||
@@ -38,43 +38,43 @@ public class Subscription implements Serializable {
|
||||
return sub;
|
||||
}
|
||||
|
||||
@ApiProperty(value = "subscription id", required = true)
|
||||
@ApiModelProperty(value = "subscription id", required = true)
|
||||
private Long id;
|
||||
|
||||
@ApiProperty(value = "subscription name", required = true)
|
||||
@ApiModelProperty(value = "subscription name", required = true)
|
||||
private String name;
|
||||
|
||||
@ApiProperty(value = "error message while fetching the feed", required = true)
|
||||
@ApiModelProperty(value = "error message while fetching the feed", required = true)
|
||||
private String message;
|
||||
|
||||
@ApiProperty(value = "error count", required = true)
|
||||
@ApiModelProperty(value = "error count", required = true)
|
||||
private int errorCount;
|
||||
|
||||
@ApiProperty(value = "last time the feed was refreshed", required = true)
|
||||
@ApiModelProperty(value = "last time the feed was refreshed", required = true)
|
||||
private Date lastRefresh;
|
||||
|
||||
@ApiProperty(value = "next time the feed refresh is planned, null if refresh is already queued", required = true)
|
||||
@ApiModelProperty(value = "next time the feed refresh is planned, null if refresh is already queued", required = true)
|
||||
private Date nextRefresh;
|
||||
|
||||
@ApiProperty(value = "this subscription's feed url", required = true)
|
||||
@ApiModelProperty(value = "this subscription's feed url", required = true)
|
||||
private String feedUrl;
|
||||
|
||||
@ApiProperty(value = "this subscription's website url", required = true)
|
||||
@ApiModelProperty(value = "this subscription's website url", required = true)
|
||||
private String feedLink;
|
||||
|
||||
@ApiProperty(value = "The favicon url to use for this feed")
|
||||
@ApiModelProperty(value = "The favicon url to use for this feed")
|
||||
private String iconUrl;
|
||||
|
||||
@ApiProperty(value = "unread count", required = true)
|
||||
@ApiModelProperty(value = "unread count", required = true)
|
||||
private long unread;
|
||||
|
||||
@ApiProperty(value = "category id")
|
||||
@ApiModelProperty(value = "category id")
|
||||
private String categoryId;
|
||||
|
||||
@ApiProperty("position of the subscription's in the list")
|
||||
@ApiModelProperty("position of the subscription's in the list")
|
||||
private Integer position;
|
||||
|
||||
@ApiProperty("date of the newest item")
|
||||
@ApiModelProperty("date of the newest item")
|
||||
private Date newestItemTime;
|
||||
|
||||
}
|
||||
@@ -5,10 +5,10 @@ import java.util.Date;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiClass("Unread count")
|
||||
@ApiModel("Unread count")
|
||||
@Data
|
||||
public class UnreadCount implements Serializable {
|
||||
|
||||
@@ -17,7 +17,6 @@ public class UnreadCount implements Serializable {
|
||||
private Date newestItemTime;
|
||||
|
||||
public UnreadCount() {
|
||||
|
||||
}
|
||||
|
||||
public UnreadCount(long feedId, long unreadCount, Date newestItemTime) {
|
||||
|
||||
@@ -5,39 +5,39 @@ import java.util.Date;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiProperty;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiClass("User information")
|
||||
@ApiModel("User information")
|
||||
@Data
|
||||
public class UserModel implements Serializable {
|
||||
|
||||
@ApiProperty(value = "user id", required = true)
|
||||
@ApiModelProperty(value = "user id", required = true)
|
||||
private Long id;
|
||||
|
||||
@ApiProperty(value = "user name", required = true)
|
||||
@ApiModelProperty(value = "user name", required = true)
|
||||
private String name;
|
||||
|
||||
@ApiProperty("user email, if any")
|
||||
@ApiModelProperty("user email, if any")
|
||||
private String email;
|
||||
|
||||
@ApiProperty("api key")
|
||||
@ApiModelProperty("api key")
|
||||
private String apiKey;
|
||||
|
||||
@ApiProperty(value = "user password, never returned by the api")
|
||||
@ApiModelProperty(value = "user password, never returned by the api")
|
||||
private String password;
|
||||
|
||||
@ApiProperty(value = "account status")
|
||||
@ApiModelProperty(value = "account status")
|
||||
private boolean enabled;
|
||||
|
||||
@ApiProperty(value = "account creation date")
|
||||
@ApiModelProperty(value = "account creation date")
|
||||
private Date created;
|
||||
|
||||
@ApiProperty(value = "last login date")
|
||||
@ApiModelProperty(value = "last login date")
|
||||
private Date lastLogin;
|
||||
|
||||
@ApiProperty(value = "user is admin")
|
||||
@ApiModelProperty(value = "user is admin")
|
||||
private boolean admin;
|
||||
|
||||
}
|
||||
|
||||
@@ -4,18 +4,18 @@ import java.io.Serializable;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiProperty;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiClass("Add Category Request")
|
||||
@ApiModel("Add Category Request")
|
||||
@Data
|
||||
public class AddCategoryRequest implements Serializable {
|
||||
|
||||
@ApiProperty(value = "name", required = true)
|
||||
@ApiModelProperty(value = "name", required = true)
|
||||
private String name;
|
||||
|
||||
@ApiProperty(value = "parent category id, if any")
|
||||
@ApiModelProperty(value = "parent category id, if any")
|
||||
private String parentId;
|
||||
|
||||
}
|
||||
|
||||
@@ -4,24 +4,24 @@ import java.io.Serializable;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiProperty;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiClass("Category modification request")
|
||||
@ApiModel("Category modification request")
|
||||
@Data
|
||||
public class CategoryModificationRequest implements Serializable {
|
||||
|
||||
@ApiProperty(value = "id", required = true)
|
||||
@ApiModelProperty(value = "id", required = true)
|
||||
private Long id;
|
||||
|
||||
@ApiProperty(value = "new name, null if not changed")
|
||||
@ApiModelProperty(value = "new name, null if not changed")
|
||||
private String name;
|
||||
|
||||
@ApiProperty(value = "new parent category id")
|
||||
@ApiModelProperty(value = "new parent category id")
|
||||
private String parentId;
|
||||
|
||||
@ApiProperty(value = "new display position, null if not changed")
|
||||
@ApiModelProperty(value = "new display position, null if not changed")
|
||||
private Integer position;
|
||||
|
||||
}
|
||||
|
||||
@@ -4,18 +4,18 @@ import java.io.Serializable;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiProperty;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiClass("Mark Request")
|
||||
@ApiModel("Mark Request")
|
||||
@Data
|
||||
public class CollapseRequest implements Serializable {
|
||||
|
||||
@ApiProperty(value = "category id", required = true)
|
||||
@ApiModelProperty(value = "category id", required = true)
|
||||
private Long id;
|
||||
|
||||
@ApiProperty(value = "collapse", required = true)
|
||||
@ApiModelProperty(value = "collapse", required = true)
|
||||
private boolean collapse;
|
||||
|
||||
}
|
||||
|
||||
@@ -4,15 +4,15 @@ import java.io.Serializable;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiProperty;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiClass("Feed information request")
|
||||
@ApiModel("Feed information request")
|
||||
@Data
|
||||
public class FeedInfoRequest implements Serializable {
|
||||
|
||||
@ApiProperty(value = "feed url", required = true)
|
||||
@ApiModelProperty(value = "feed url", required = true)
|
||||
private String url;
|
||||
|
||||
}
|
||||
|
||||
@@ -5,18 +5,18 @@ import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiProperty;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiClass("Feed merge Request")
|
||||
@ApiModel("Feed merge Request")
|
||||
@Data
|
||||
public class FeedMergeRequest implements Serializable {
|
||||
|
||||
@ApiProperty(value = "merge into this feed", required = true)
|
||||
@ApiModelProperty(value = "merge into this feed", required = true)
|
||||
private Long intoFeedId;
|
||||
|
||||
@ApiProperty(value = "id of the feeds to merge", required = true)
|
||||
@ApiModelProperty(value = "id of the feeds to merge", required = true)
|
||||
private List<Long> feedIds;
|
||||
|
||||
}
|
||||
|
||||
@@ -4,24 +4,24 @@ import java.io.Serializable;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiProperty;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiClass("Feed modification request")
|
||||
@ApiModel("Feed modification request")
|
||||
@Data
|
||||
public class FeedModificationRequest implements Serializable {
|
||||
|
||||
@ApiProperty(value = "id", required = true)
|
||||
@ApiModelProperty(value = "id", required = true)
|
||||
private Long id;
|
||||
|
||||
@ApiProperty(value = "new name, null if not changed")
|
||||
@ApiModelProperty(value = "new name, null if not changed")
|
||||
private String name;
|
||||
|
||||
@ApiProperty(value = "new parent category id")
|
||||
@ApiModelProperty(value = "new parent category id")
|
||||
private String categoryId;
|
||||
|
||||
@ApiProperty(value = "new display position, null if not changed")
|
||||
@ApiModelProperty(value = "new display position, null if not changed")
|
||||
private Integer position;
|
||||
|
||||
}
|
||||
|
||||
@@ -4,15 +4,15 @@ import java.io.Serializable;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiProperty;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiClass
|
||||
@ApiModel
|
||||
@Data
|
||||
public class IDRequest implements Serializable {
|
||||
|
||||
@ApiProperty
|
||||
@ApiModelProperty
|
||||
private Long id;
|
||||
|
||||
}
|
||||
|
||||
@@ -5,26 +5,26 @@ import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiProperty;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiClass("Mark Request")
|
||||
@ApiModel("Mark Request")
|
||||
@Data
|
||||
public class MarkRequest implements Serializable {
|
||||
|
||||
@ApiProperty(value = "entry id, category id, 'all' or 'starred'", required = true)
|
||||
@ApiModelProperty(value = "entry id, category id, 'all' or 'starred'", required = true)
|
||||
private String id;
|
||||
|
||||
@ApiProperty(value = "mark as read or unread")
|
||||
@ApiModelProperty(value = "mark as read or unread")
|
||||
private boolean read;
|
||||
|
||||
@ApiProperty(
|
||||
@ApiModelProperty(
|
||||
value = "only entries older than this, pass the timestamp you got from the entry list to prevent marking an entry that was not retrieved",
|
||||
required = false)
|
||||
private Long olderThan;
|
||||
|
||||
@ApiProperty(value = "if marking a category or 'all', exclude those subscriptions from the marking", required = false)
|
||||
@ApiModelProperty(value = "if marking a category or 'all', exclude those subscriptions from the marking", required = false)
|
||||
private List<Long> excludedSubscriptions;
|
||||
|
||||
}
|
||||
|
||||
@@ -5,15 +5,15 @@ import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiProperty;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiClass("Multiple Mark Request")
|
||||
@ApiModel("Multiple Mark Request")
|
||||
@Data
|
||||
public class MultipleMarkRequest implements Serializable {
|
||||
|
||||
@ApiProperty(value = "list of mark requests", required = true)
|
||||
@ApiModelProperty(value = "list of mark requests", required = true)
|
||||
private List<MarkRequest> requests;
|
||||
|
||||
}
|
||||
|
||||
@@ -4,21 +4,21 @@ import java.io.Serializable;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiProperty;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiClass("Profile modification request")
|
||||
@ApiModel("Profile modification request")
|
||||
@Data
|
||||
public class ProfileModificationRequest implements Serializable {
|
||||
|
||||
@ApiProperty(value = "changes email of the user, if specified")
|
||||
@ApiModelProperty(value = "changes email of the user, if specified")
|
||||
private String email;
|
||||
|
||||
@ApiProperty(value = "changes password of the user, if specified")
|
||||
@ApiModelProperty(value = "changes password of the user, if specified")
|
||||
private String password;
|
||||
|
||||
@ApiProperty(value = "generate a new api key")
|
||||
@ApiModelProperty(value = "generate a new api key")
|
||||
private boolean newApiKey;
|
||||
|
||||
}
|
||||
|
||||
@@ -4,19 +4,21 @@ import java.io.Serializable;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiProperty;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@Data
|
||||
@ApiModel
|
||||
public class RegistrationRequest implements Serializable {
|
||||
|
||||
@ApiProperty(value = "username, between 3 and 32 characters", required = true)
|
||||
@ApiModelProperty(value = "username, between 3 and 32 characters", required = true)
|
||||
private String name;
|
||||
|
||||
@ApiProperty(value = "password, minimum 6 characters", required = true)
|
||||
@ApiModelProperty(value = "password, minimum 6 characters", required = true)
|
||||
private String password;
|
||||
|
||||
@ApiProperty(value = "email address for password recovery", required = true)
|
||||
@ApiModelProperty(value = "email address for password recovery", required = true)
|
||||
private String email;
|
||||
|
||||
}
|
||||
|
||||
@@ -4,21 +4,21 @@ import java.io.Serializable;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiProperty;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiClass("Star Request")
|
||||
@ApiModel("Star Request")
|
||||
@Data
|
||||
public class StarRequest implements Serializable {
|
||||
|
||||
@ApiProperty(value = "id", required = true)
|
||||
@ApiModelProperty(value = "id", required = true)
|
||||
private String id;
|
||||
|
||||
@ApiProperty(value = "feed id", required = true)
|
||||
@ApiModelProperty(value = "feed id", required = true)
|
||||
private Long feedId;
|
||||
|
||||
@ApiProperty(value = "starred or not")
|
||||
@ApiModelProperty(value = "starred or not")
|
||||
private boolean starred;
|
||||
|
||||
}
|
||||
|
||||
@@ -4,21 +4,21 @@ import java.io.Serializable;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiProperty;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiClass("Subscription request")
|
||||
@ApiModel("Subscription request")
|
||||
@Data
|
||||
public class SubscribeRequest implements Serializable {
|
||||
|
||||
@ApiProperty(value = "url of the feed", required = true)
|
||||
@ApiModelProperty(value = "url of the feed", required = true)
|
||||
private String url;
|
||||
|
||||
@ApiProperty(value = "name of the feed for the user", required = true)
|
||||
@ApiModelProperty(value = "name of the feed for the user", required = true)
|
||||
private String title;
|
||||
|
||||
@ApiProperty(value = "id of the user category to place the feed in")
|
||||
@ApiModelProperty(value = "id of the user category to place the feed in")
|
||||
private String categoryId;
|
||||
|
||||
}
|
||||
|
||||
@@ -5,18 +5,18 @@ import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiProperty;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiClass("Tag Request")
|
||||
@ApiModel("Tag Request")
|
||||
@Data
|
||||
public class TagRequest implements Serializable {
|
||||
|
||||
@ApiProperty(value = "entry id", required = true)
|
||||
@ApiModelProperty(value = "entry id", required = true)
|
||||
private Long entryId;
|
||||
|
||||
@ApiProperty(value = "tags")
|
||||
@ApiModelProperty(value = "tags")
|
||||
private List<String> tags;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:wicket="http://wicket.apache.org" wicket:id="html">
|
||||
<head>
|
||||
<title>CommaFeed</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
|
||||
<link rel="apple-touch-icon" href="app-icon-57.png" />
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="app-icon-72.png" />
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="app-icon-114.png" />
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="app-icon-144.png" />
|
||||
<link rel="icon" sizes="32x32" href="app-icon-32.png" />
|
||||
<link rel="icon" sizes="64x64" href="app-icon-64.png" />
|
||||
<link rel="icon" sizes="128x128" href="app-icon-128.png" />
|
||||
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
|
||||
<meta name="application-name" content="CommaFeed" />
|
||||
<meta name="msapplication-navbutton-color" content="#F88A14" />
|
||||
<meta name="msapplication-starturl" content="/" />
|
||||
<meta name="msapplication-square70x70logo" content="metro-icon-70.png" />
|
||||
<meta name="msapplication-square150x150logo" content="metro-icon-150.png" />
|
||||
<link rel="fluid-icon" href="app-icon-512.png" title="CommaFeed" />
|
||||
<link rel="logo" type="image/svg" href="app-icon.svg" />
|
||||
</head>
|
||||
<body>
|
||||
<wicket:child />
|
||||
<wicket:container wicket:id="footer-container" />
|
||||
<wicket:container wicket:id="uservoice">
|
||||
<script>
|
||||
(function() {
|
||||
var uv = document.createElement('script');
|
||||
uv.type = 'text/javascript';
|
||||
uv.async = true;
|
||||
uv.src = '//widget.uservoice.com/XYpTZZteqS4lHvgrTXeA.js';
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(uv, s);
|
||||
})();
|
||||
</script>
|
||||
<script>
|
||||
UserVoice = window.UserVoice || [];
|
||||
UserVoice.push(['showTab', 'classic_widget', {
|
||||
mode : 'full',
|
||||
default_mode : 'feedback',
|
||||
primary_color : '#000',
|
||||
link_color : '#007dbf',
|
||||
forum_id : 204509,
|
||||
support_tab_name : 'Contact',
|
||||
feedback_tab_name : 'Feedback',
|
||||
tab_label : 'Feedback',
|
||||
tab_color : '#7e72db',
|
||||
tab_position : 'bottom-right',
|
||||
tab_inverted : false
|
||||
}]);
|
||||
</script>
|
||||
</wicket:container>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,130 +0,0 @@
|
||||
package com.commafeed.frontend.pages;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.wicket.AttributeModifier;
|
||||
import org.apache.wicket.RuntimeConfigurationType;
|
||||
import org.apache.wicket.markup.head.CssHeaderItem;
|
||||
import org.apache.wicket.markup.head.IHeaderResponse;
|
||||
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
|
||||
import org.apache.wicket.markup.head.filter.HeaderResponseContainer;
|
||||
import org.apache.wicket.markup.html.TransparentWebMarkupContainer;
|
||||
import org.apache.wicket.markup.html.WebMarkupContainer;
|
||||
import org.apache.wicket.markup.html.WebPage;
|
||||
|
||||
import com.commafeed.backend.dao.FeedCategoryDAO;
|
||||
import com.commafeed.backend.dao.FeedDAO;
|
||||
import com.commafeed.backend.dao.FeedEntryDAO;
|
||||
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
||||
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
||||
import com.commafeed.backend.dao.UserDAO;
|
||||
import com.commafeed.backend.dao.UserRoleDAO;
|
||||
import com.commafeed.backend.dao.UserSettingsDAO;
|
||||
import com.commafeed.backend.model.ApplicationSettings;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.model.UserSettings;
|
||||
import com.commafeed.backend.services.ApplicationSettingsService;
|
||||
import com.commafeed.backend.services.MailService;
|
||||
import com.commafeed.backend.startup.StartupBean;
|
||||
import com.commafeed.frontend.CommaFeedSession;
|
||||
import com.commafeed.frontend.utils.WicketUtils;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class BasePage extends WebPage {
|
||||
|
||||
@Inject
|
||||
protected FeedDAO feedDAO;
|
||||
|
||||
@Inject
|
||||
StartupBean startupBean;
|
||||
|
||||
@Inject
|
||||
protected FeedSubscriptionDAO feedSubscriptionDAO;
|
||||
|
||||
@Inject
|
||||
protected FeedCategoryDAO feedCategoryDAO;
|
||||
|
||||
@Inject
|
||||
protected FeedEntryDAO feedEntryDAO;
|
||||
|
||||
@Inject
|
||||
protected FeedEntryStatusDAO feedEntryStatusDAO;
|
||||
|
||||
@Inject
|
||||
protected UserDAO userDAO;
|
||||
|
||||
@Inject
|
||||
protected UserSettingsDAO userSettingsDAO;
|
||||
|
||||
@Inject
|
||||
protected UserRoleDAO userRoleDAO;
|
||||
|
||||
@Inject
|
||||
MailService mailService;
|
||||
|
||||
@Inject
|
||||
ApplicationSettingsService applicationSettingsService;
|
||||
|
||||
private ApplicationSettings settings;
|
||||
|
||||
public BasePage() {
|
||||
|
||||
String lang = "en";
|
||||
String theme = "default";
|
||||
User user = CommaFeedSession.get().getUser();
|
||||
if (user != null) {
|
||||
UserSettings settings = userSettingsDAO.findByUser(user);
|
||||
if (settings != null) {
|
||||
lang = settings.getLanguage() == null ? "en" : settings.getLanguage();
|
||||
theme = settings.getTheme() == null ? "default" : settings.getTheme();
|
||||
}
|
||||
}
|
||||
|
||||
add(new TransparentWebMarkupContainer("html").setMarkupId("theme-" + theme).add(new AttributeModifier("lang", lang)));
|
||||
|
||||
settings = applicationSettingsService.get();
|
||||
add(new HeaderResponseContainer("footer-container", "footer-container"));
|
||||
add(new WebMarkupContainer("uservoice") {
|
||||
@Override
|
||||
protected void onConfigure() {
|
||||
super.onConfigure();
|
||||
setVisibilityAllowed(settings.isFeedbackButton());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderHead(IHeaderResponse response) {
|
||||
super.renderHead(response);
|
||||
|
||||
if (getApplication().getConfigurationType() == RuntimeConfigurationType.DEPLOYMENT) {
|
||||
long startupTime = startupBean.getStartupTime();
|
||||
String suffix = "?" + startupTime;
|
||||
response.render(JavaScriptHeaderItem.forUrl("static/all.js" + suffix));
|
||||
response.render(CssHeaderItem.forUrl("static/all.css" + suffix));
|
||||
} else {
|
||||
response.render(JavaScriptHeaderItem.forUrl("wro/lib.js"));
|
||||
response.render(CssHeaderItem.forUrl("wro/lib.css"));
|
||||
response.render(CssHeaderItem.forUrl("wro/app.css"));
|
||||
|
||||
response.render(JavaScriptHeaderItem.forUrl("js/welcome.js"));
|
||||
response.render(JavaScriptHeaderItem.forUrl("js/main.js"));
|
||||
response.render(JavaScriptHeaderItem.forUrl("js/controllers.js"));
|
||||
response.render(JavaScriptHeaderItem.forUrl("js/directives.js"));
|
||||
response.render(JavaScriptHeaderItem.forUrl("js/filters.js"));
|
||||
response.render(JavaScriptHeaderItem.forUrl("js/services.js"));
|
||||
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(settings.getGoogleAnalyticsTrackingCode())) {
|
||||
Map<String, Object> vars = Maps.newHashMap();
|
||||
vars.put("trackingCode", settings.getGoogleAnalyticsTrackingCode());
|
||||
WicketUtils.loadJS(response, BasePage.class, "analytics", vars);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.commafeed.frontend.pages;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.apache.wicket.markup.html.WebPage;
|
||||
|
||||
import com.commafeed.backend.services.UserService;
|
||||
import com.commafeed.backend.startup.StartupBean;
|
||||
import com.commafeed.frontend.CommaFeedSession;
|
||||
|
||||
public class DemoLoginPage extends WebPage {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Inject
|
||||
UserService userService;
|
||||
|
||||
public DemoLoginPage() {
|
||||
CommaFeedSession.get().authenticate(StartupBean.USERNAME_DEMO, StartupBean.USERNAME_DEMO);
|
||||
setResponsePage(getApplication().getHomePage());
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:wicket="http://wicket.apache.org">
|
||||
<body>
|
||||
<wicket:extend>
|
||||
<div ng-app="commafeed" id="main" class="main">
|
||||
<div ui-view>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</wicket:extend>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.commafeed.frontend.pages;
|
||||
|
||||
import org.apache.wicket.markup.head.CssHeaderItem;
|
||||
import org.apache.wicket.markup.head.IHeaderResponse;
|
||||
import org.apache.wicket.request.mapper.parameter.PageParameters;
|
||||
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.model.UserRole.Role;
|
||||
import com.commafeed.backend.model.UserSettings;
|
||||
import com.commafeed.frontend.CommaFeedSession;
|
||||
import com.commafeed.frontend.SecurityCheck;
|
||||
import com.commafeed.frontend.resources.UserCustomCssReference;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@SecurityCheck(Role.USER)
|
||||
public class HomePage extends BasePage {
|
||||
|
||||
@Override
|
||||
public void renderHead(IHeaderResponse response) {
|
||||
super.renderHead(response);
|
||||
|
||||
response.render(CssHeaderItem.forReference(new UserCustomCssReference() {
|
||||
@Override
|
||||
protected String getCss() {
|
||||
User user = CommaFeedSession.get().getUser();
|
||||
if (user == null) {
|
||||
return null;
|
||||
}
|
||||
UserSettings settings = userSettingsDAO.findByUser(user);
|
||||
return settings == null ? null : settings.getCustomCss();
|
||||
}
|
||||
}, new PageParameters().add("_t", System.currentTimeMillis()), null));
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package com.commafeed.frontend.pages;
|
||||
|
||||
import org.apache.wicket.markup.html.WebPage;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class LogoutPage extends WebPage {
|
||||
public LogoutPage() {
|
||||
getSession().invalidate();
|
||||
setResponsePage(getApplication().getHomePage());
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package com.commafeed.frontend.pages;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.wicket.markup.html.WebPage;
|
||||
import org.apache.wicket.request.flow.RedirectToUrlException;
|
||||
import org.apache.wicket.request.mapper.parameter.PageParameters;
|
||||
|
||||
import com.commafeed.backend.dao.FeedCategoryDAO;
|
||||
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
||||
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
||||
import com.commafeed.backend.model.FeedCategory;
|
||||
import com.commafeed.backend.model.FeedEntryStatus;
|
||||
import com.commafeed.backend.model.FeedSubscription;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.model.UserRole.Role;
|
||||
import com.commafeed.backend.model.UserSettings.ReadingOrder;
|
||||
import com.commafeed.frontend.CommaFeedSession;
|
||||
import com.commafeed.frontend.SecurityCheck;
|
||||
import com.commafeed.frontend.rest.resources.CategoryREST;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@SecurityCheck(Role.USER)
|
||||
public class NextUnreadRedirectPage extends WebPage {
|
||||
|
||||
public static final String PARAM_CATEGORYID = "category";
|
||||
public static final String PARAM_READINGORDER = "order";
|
||||
|
||||
@Inject
|
||||
FeedCategoryDAO feedCategoryDAO;
|
||||
|
||||
@Inject
|
||||
FeedEntryStatusDAO feedEntryStatusDAO;
|
||||
|
||||
@Inject
|
||||
FeedSubscriptionDAO feedSubscriptionDAO;
|
||||
|
||||
public NextUnreadRedirectPage(PageParameters params) {
|
||||
String categoryId = params.get(PARAM_CATEGORYID).toString();
|
||||
String orderParam = params.get(PARAM_READINGORDER).toString();
|
||||
|
||||
User user = CommaFeedSession.get().getUser();
|
||||
ReadingOrder order = ReadingOrder.desc;
|
||||
|
||||
if (StringUtils.equals(orderParam, "asc")) {
|
||||
order = ReadingOrder.asc;
|
||||
}
|
||||
|
||||
List<FeedEntryStatus> statuses = null;
|
||||
if (StringUtils.isBlank(categoryId) || CategoryREST.ALL.equals(categoryId)) {
|
||||
List<FeedSubscription> subs = feedSubscriptionDAO.findAll(user);
|
||||
statuses = feedEntryStatusDAO.findBySubscriptions(user, subs, true, null, null, 0, 1, order, true, false, null);
|
||||
} else {
|
||||
FeedCategory category = feedCategoryDAO.findById(user, Long.valueOf(categoryId));
|
||||
if (category != null) {
|
||||
List<FeedCategory> children = feedCategoryDAO.findAllChildrenCategories(user, category);
|
||||
List<FeedSubscription> subscriptions = feedSubscriptionDAO.findByCategories(user, children);
|
||||
statuses = feedEntryStatusDAO.findBySubscriptions(user, subscriptions, true, null, null, 0, 1, order, true, false, null);
|
||||
}
|
||||
}
|
||||
|
||||
if (CollectionUtils.isEmpty(statuses)) {
|
||||
setResponsePage(HomePage.class);
|
||||
} else {
|
||||
FeedEntryStatus status = Iterables.getFirst(statuses, null);
|
||||
String url = status.getEntry().getUrl();
|
||||
status.setRead(true);
|
||||
feedEntryStatusDAO.saveOrUpdate(status);
|
||||
throw new RedirectToUrlException(url);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user