diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java index 54238266b28389ad1146758590d6c441607c4046..7ae01fe47a056d4d1b7cf361ab3596032e52b25a 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java @@ -68,8 +68,8 @@ import static org.briarproject.bramble.db.ExponentialBackoff.calculateExpiry; @NotNullByDefault abstract class JdbcDatabase implements Database<Connection> { - private static final int SCHEMA_VERSION = 29; - private static final int MIN_SCHEMA_VERSION = 29; + private static final int SCHEMA_VERSION = 30; + private static final int MIN_SCHEMA_VERSION = 30; private static final String CREATE_SETTINGS = "CREATE TABLE settings" diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/Blog.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/Blog.java index b7e1d240fea96c14eed901a1fff18c2c9424dac9..a0e4fff021f700be77017977701959a79d2eca8a 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/blog/Blog.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/Blog.java @@ -13,16 +13,22 @@ import javax.annotation.concurrent.Immutable; public class Blog extends BaseGroup implements Shareable { private final Author author; + private final boolean rssFeed; - public Blog(Group group, Author author) { + public Blog(Group group, Author author, boolean rssFeed) { super(group); this.author = author; + this.rssFeed = rssFeed; } public Author getAuthor() { return author; } + public boolean isRssFeed() { + return rssFeed; + } + @Override public boolean equals(Object o) { return o instanceof Blog && super.equals(o); diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogFactory.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogFactory.java index 4b0a89cf377b3f8c036cd206e1f15a8c78e9be4b..a9d057501da211b41d383b1cad7bf47f110e748f 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogFactory.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogFactory.java @@ -13,6 +13,11 @@ public interface BlogFactory { */ Blog createBlog(Author author); + /** + * Creates a RSS feed blog for a given author. + */ + Blog createFeedBlog(Author author); + /** * Parses a blog with the given Group */ diff --git a/briar-api/src/main/java/org/briarproject/briar/api/feed/Feed.java b/briar-api/src/main/java/org/briarproject/briar/api/feed/Feed.java index 51f53f10cde72093129db6cf37bbd1a8b61eb4fe..4932ecab75a390cd1757bac874dbab7bacad8e75 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/feed/Feed.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/feed/Feed.java @@ -93,21 +93,9 @@ public class Feed { if (this == o) return true; if (o instanceof Feed) { Feed f = (Feed) o; - return url.equals(f.url) && blog.equals(f.blog) && - equalsWithNull(title, f.title) && - equalsWithNull(description, f.description) && - equalsWithNull(author, f.author) && - added == f.added && - updated == f.updated && - lastEntryTime == f.lastEntryTime; + return blog.equals(f.blog); } return false; } - private boolean equalsWithNull(@Nullable Object a, @Nullable Object b) { - if (a == b) return true; - if (a == null || b == null) return false; - return a.equals(b); - } - } diff --git a/briar-core/src/main/java/org/briarproject/briar/blog/BlogFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/blog/BlogFactoryImpl.java index 26c1eb108c0f9e75301e3e2a8f854adb6bc91660..deaae2cfe643919c1d2fc1e7a9d422f898190eb4 100644 --- a/briar-core/src/main/java/org/briarproject/briar/blog/BlogFactoryImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/blog/BlogFactoryImpl.java @@ -33,15 +33,25 @@ class BlogFactoryImpl implements BlogFactory { @Override public Blog createBlog(Author a) { + return createBlog(a, false); + } + + @Override + public Blog createFeedBlog(Author a) { + return createBlog(a, true); + } + + private Blog createBlog(Author a, boolean rssFeed) { try { BdfList blog = BdfList.of( a.getName(), - a.getPublicKey() + a.getPublicKey(), + rssFeed ); byte[] descriptor = clientHelper.toByteArray(blog); Group g = groupFactory .createGroup(BlogManagerImpl.CLIENT_ID, descriptor); - return new Blog(g, a); + return new Blog(g, a, rssFeed); } catch (FormatException e) { throw new RuntimeException(e); } @@ -54,7 +64,7 @@ class BlogFactoryImpl implements BlogFactory { BdfList blog = clientHelper.toList(descriptor); Author a = authorFactory.createAuthor(blog.getString(0), blog.getRaw(1)); - return new Blog(g, a); + return new Blog(g, a, blog.getBoolean(2)); } } diff --git a/briar-core/src/main/java/org/briarproject/briar/feed/FeedFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/feed/FeedFactoryImpl.java index 531f169ef57691c00312ea0e1d6e19b4f14df59c..14aca1559836f7d32625b22665626a015e81bd09 100644 --- a/briar-core/src/main/java/org/briarproject/briar/feed/FeedFactoryImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/feed/FeedFactoryImpl.java @@ -52,7 +52,7 @@ class FeedFactoryImpl implements FeedFactory { .createLocalAuthor(syndFeed.getTitle(), keyPair.getPublic().getEncoded(), keyPair.getPrivate().getEncoded()); - Blog blog = blogFactory.createBlog(localAuthor); + Blog blog = blogFactory.createFeedBlog(localAuthor); long added = clock.currentTimeMillis(); return new Feed(url, blog, localAuthor, added); @@ -75,7 +75,7 @@ class FeedFactoryImpl implements FeedFactory { byte[] privateKey = d.getRaw(KEY_PRIVATE_KEY); LocalAuthor localAuthor = authorFactory .createLocalAuthor(blogTitle, publicKey, privateKey); - Blog blog = blogFactory.createBlog(localAuthor); + Blog blog = blogFactory.createFeedBlog(localAuthor); String title = d.getOptionalString(KEY_FEED_TITLE); String desc = d.getOptionalString(KEY_FEED_DESC); diff --git a/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java index 8db542e8b9a1034d2320990f7a526c3da80eefe4..969de52a3c5eb259c715fd418f100d6a59404824 100644 --- a/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java @@ -30,6 +30,7 @@ import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Scheduler; import org.briarproject.bramble.util.StringUtils; +import org.briarproject.briar.api.blog.Blog; import org.briarproject.briar.api.blog.BlogManager; import org.briarproject.briar.api.blog.BlogPost; import org.briarproject.briar.api.blog.BlogPostFactory; @@ -74,7 +75,8 @@ import static org.briarproject.briar.util.HtmlUtils.clean; @ThreadSafe @NotNullByDefault -class FeedManagerImpl implements FeedManager, Client, EventListener { +class FeedManagerImpl implements FeedManager, Client, EventListener, + BlogManager.RemoveBlogHook { private static final Logger LOG = Logger.getLogger(FeedManagerImpl.class.getName()); @@ -158,7 +160,6 @@ class FeedManagerImpl implements FeedManager, Client, EventListener { @Override public void addFeed(String url) throws DbException, IOException { - // TODO check for existing feed? // fetch syndication feed to get its metadata SyndFeed f; try { @@ -207,15 +208,7 @@ class FeedManagerImpl implements FeedManager, Client, EventListener { LOG.info("Removing RSS feed..."); Transaction txn = db.startTransaction(false); try { - List<Feed> feeds = getFeeds(txn); - for (Feed f : feeds) { - if (f.getBlogId().equals(feed.getBlogId())) { - feed = f; - feeds.remove(f); - break; - } - } - storeFeeds(txn, feeds); + // this will call removingBlog() where the feed itself gets removed blogManager.removeBlog(txn, feed.getBlog()); db.commitTransaction(txn); } finally { @@ -223,6 +216,23 @@ class FeedManagerImpl implements FeedManager, Client, EventListener { } } + @Override + public void removingBlog(Transaction txn, Blog b) throws DbException { + if (!b.isRssFeed()) return; + + // delete blog's RSS feed if we have it + boolean found = false; + List<Feed> feeds = getFeeds(txn); + for (Feed f : feeds) { + if (f.getBlogId().equals(b.getId())) { + found = true; + feeds.remove(f); + break; + } + } + if (found) storeFeeds(txn, feeds); + } + @Override public List<Feed> getFeeds() throws DbException { List<Feed> feeds; diff --git a/briar-core/src/main/java/org/briarproject/briar/feed/FeedModule.java b/briar-core/src/main/java/org/briarproject/briar/feed/FeedModule.java index ab8dfbc29322ba6090ec4bcf6f9530e43c2d6980..c4b567c189977888c2e2927fc956e9cb2c40f079 100644 --- a/briar-core/src/main/java/org/briarproject/briar/feed/FeedModule.java +++ b/briar-core/src/main/java/org/briarproject/briar/feed/FeedModule.java @@ -2,6 +2,7 @@ package org.briarproject.briar.feed; import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.lifecycle.LifecycleManager; +import org.briarproject.briar.api.blog.BlogManager; import org.briarproject.briar.api.feed.FeedManager; import javax.inject.Inject; @@ -21,10 +22,12 @@ public class FeedModule { @Provides @Singleton FeedManager provideFeedManager(FeedManagerImpl feedManager, - LifecycleManager lifecycleManager, EventBus eventBus) { + LifecycleManager lifecycleManager, EventBus eventBus, + BlogManager blogManager) { lifecycleManager.registerClient(feedManager); eventBus.addListener(feedManager); + blogManager.registerRemoveBlogHook(feedManager); return feedManager; } diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingValidator.java b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingValidator.java index 6f0df8e473b3db7b1e1361850adb2cff997523a8..f9b378ef7878628b4c29f323b54437e393d47f8d 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingValidator.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingValidator.java @@ -39,14 +39,20 @@ class BlogSharingValidator extends SharingValidator { @Override protected GroupId validateDescriptor(BdfList descriptor) throws FormatException { - checkSize(descriptor, 2); + checkSize(descriptor, 3); String name = descriptor.getString(0); checkLength(name, 1, MAX_AUTHOR_NAME_LENGTH); byte[] publicKey = descriptor.getRaw(1); checkLength(publicKey, 1, MAX_PUBLIC_KEY_LENGTH); + boolean rssFeed = descriptor.getBoolean(2); Author author = authorFactory.createAuthor(name, publicKey); - Blog blog = blogFactory.createBlog(author); + Blog blog; + if (rssFeed) { + blog = blogFactory.createFeedBlog(author); + } else { + blog = blogFactory.createBlog(author); + } return blog.getId(); } diff --git a/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerImplTest.java index e2b5e8ef5206d162cc029c3cd945362f894eaa96..4ff1bb75c4826d35c093fc7a8815f9acaa32975f 100644 --- a/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerImplTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerImplTest.java @@ -297,7 +297,7 @@ public class BlogManagerImplTest extends BriarTestCase { final LocalAuthor localAuthor = new LocalAuthor(authorId, "Author", publicKey, privateKey, created); - return new Blog(group, localAuthor); + return new Blog(group, localAuthor, false); } private BdfDictionary authorToBdfDictionary(Author a) { diff --git a/briar-core/src/test/java/org/briarproject/briar/blog/BlogPostValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/blog/BlogPostValidatorTest.java index 1ac77a550e8d3737eadd84e447e9981abb0d443f..d3731d19de9c9fcea112144ab37589e782081793 100644 --- a/briar-core/src/test/java/org/briarproject/briar/blog/BlogPostValidatorTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/blog/BlogPostValidatorTest.java @@ -79,7 +79,7 @@ public class BlogPostValidatorTest extends BriarTestCase { new BdfEntry(KEY_AUTHOR_NAME, author.getName()), new BdfEntry(KEY_PUBLIC_KEY, author.getPublicKey()) ); - blog = new Blog(group, author); + blog = new Blog(group, author, false); MessageId messageId = new MessageId(TestUtils.getRandomId()); long timestamp = System.currentTimeMillis(); diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingValidatorTest.java index c67360d648b933c8a543e45ea640893f8621a9db..7c4c96ab267cb9f52f769abc2771221b911b75f1 100644 --- a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingValidatorTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingValidatorTest.java @@ -23,8 +23,8 @@ public class BlogSharingValidatorTest extends SharingValidatorTest { private final byte[] publicKey = TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH); private final Author author = new Author(authorId, authorName, publicKey); - private final Blog blog = new Blog(group, author); - private final BdfList descriptor = BdfList.of(authorName, publicKey); + private final Blog blog = new Blog(group, author, false); + private final BdfList descriptor = BdfList.of(authorName, publicKey, false); private final String content = TestUtils.getRandomString(MAX_INVITATION_MESSAGE_LENGTH); @@ -64,7 +64,7 @@ public class BlogSharingValidatorTest extends SharingValidatorTest { @Test(expected = FormatException.class) public void testRejectsNullBlogName() throws Exception { - BdfList invalidDescriptor = BdfList.of(null, publicKey); + BdfList invalidDescriptor = BdfList.of(null, publicKey, false); v.validateMessage(message, group, BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor, null)); @@ -72,7 +72,7 @@ public class BlogSharingValidatorTest extends SharingValidatorTest { @Test(expected = FormatException.class) public void testRejectsNonStringBlogName() throws Exception { - BdfList invalidDescriptor = BdfList.of(123, publicKey); + BdfList invalidDescriptor = BdfList.of(123, publicKey, false); v.validateMessage(message, group, BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor, null)); @@ -80,7 +80,7 @@ public class BlogSharingValidatorTest extends SharingValidatorTest { @Test(expected = FormatException.class) public void testRejectsTooShortBlogName() throws Exception { - BdfList invalidDescriptor = BdfList.of("", publicKey); + BdfList invalidDescriptor = BdfList.of("", publicKey, false); v.validateMessage(message, group, BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor, null)); @@ -89,7 +89,7 @@ public class BlogSharingValidatorTest extends SharingValidatorTest { @Test public void testAcceptsMinLengthBlogName() throws Exception { String shortBlogName = TestUtils.getRandomString(1); - BdfList validDescriptor = BdfList.of(shortBlogName, publicKey); + BdfList validDescriptor = BdfList.of(shortBlogName, publicKey, false); expectCreateBlog(shortBlogName, publicKey); expectEncodeMetadata(INVITE); BdfMessageContext messageContext = v.validateMessage(message, group, @@ -102,7 +102,8 @@ public class BlogSharingValidatorTest extends SharingValidatorTest { public void testRejectsTooLongBlogName() throws Exception { String invalidBlogName = TestUtils.getRandomString(MAX_BLOG_NAME_LENGTH + 1); - BdfList invalidDescriptor = BdfList.of(invalidBlogName, publicKey); + BdfList invalidDescriptor = + BdfList.of(invalidBlogName, publicKey, false); v.validateMessage(message, group, BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor, null)); @@ -110,7 +111,7 @@ public class BlogSharingValidatorTest extends SharingValidatorTest { @Test(expected = FormatException.class) public void testRejectsNullPublicKey() throws Exception { - BdfList invalidDescriptor = BdfList.of(authorName, null); + BdfList invalidDescriptor = BdfList.of(authorName, null, false); v.validateMessage(message, group, BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor, null)); @@ -118,7 +119,7 @@ public class BlogSharingValidatorTest extends SharingValidatorTest { @Test(expected = FormatException.class) public void testRejectsNonRawPublicKey() throws Exception { - BdfList invalidDescriptor = BdfList.of(authorName, 123); + BdfList invalidDescriptor = BdfList.of(authorName, 123, false); v.validateMessage(message, group, BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor, null)); @@ -127,7 +128,7 @@ public class BlogSharingValidatorTest extends SharingValidatorTest { @Test(expected = FormatException.class) public void testRejectsTooLongPublicKey() throws Exception { byte[] invalidKey = TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH + 1); - BdfList invalidDescriptor = BdfList.of(authorName, invalidKey); + BdfList invalidDescriptor = BdfList.of(authorName, invalidKey, false); v.validateMessage(message, group, BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor, null)); @@ -136,7 +137,7 @@ public class BlogSharingValidatorTest extends SharingValidatorTest { @Test public void testAcceptsMinLengthPublicKey() throws Exception { byte[] key = TestUtils.getRandomBytes(1); - BdfList validDescriptor = BdfList.of(authorName, key); + BdfList validDescriptor = BdfList.of(authorName, key, false); expectCreateBlog(authorName, key); expectEncodeMetadata(INVITE);