diff --git a/briar-android-tests/src/test/java/org/briarproject/BlogManagerTest.java b/briar-android-tests/src/test/java/org/briarproject/BlogManagerTest.java index e6f667ad4833a278294bcba35335038c1464a336..ad14a5ebc46032d3665c6f06bf2ce606cc9fea43 100644 --- a/briar-android-tests/src/test/java/org/briarproject/BlogManagerTest.java +++ b/briar-android-tests/src/test/java/org/briarproject/BlogManagerTest.java @@ -33,7 +33,9 @@ import org.briarproject.sync.SyncModule; import org.briarproject.transport.TransportModule; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -94,6 +96,9 @@ public class BlogManagerTest { private BlogManagerTestComponent t0, t1; + @Rule + public ExpectedException thrown = ExpectedException.none(); + @Before public void setUp() throws Exception { BlogManagerTestComponent component = @@ -249,6 +254,7 @@ public class BlogManagerTest { assertEquals(3, blogs0.size()); assertTrue(blogs0.contains(blog)); assertEquals(2, blogManager0.getBlogs(author0).size()); + assertTrue(blogManager0.canBeRemoved(blog.getId())); // remove blog blogManager0.removeBlog(blog); @@ -260,6 +266,27 @@ public class BlogManagerTest { stopLifecycles(); } + @Test + public void testCanNotRemoveContactsPersonalBlog() throws Exception { + startLifecycles(); + defaultInit(); + + assertFalse(blogManager0.canBeRemoved(blog1.getId())); + assertFalse(blogManager1.canBeRemoved(blog0.getId())); + + // the following two calls should throw a DbException now + thrown.expect(DbException.class); + + blogManager0.removeBlog(blog1); + blogManager1.removeBlog(blog0); + + // blogs have not been removed + assertEquals(2, blogManager0.getBlogs().size()); + assertEquals(2, blogManager1.getBlogs().size()); + + stopLifecycles(); + } + @After public void tearDown() throws Exception { TestUtils.deleteTestDirectory(testDir); diff --git a/briar-android-tests/src/test/java/org/briarproject/BlogSharingIntegrationTest.java b/briar-android-tests/src/test/java/org/briarproject/BlogSharingIntegrationTest.java index 8bf630581a415ca02826807c6fe8a55e17e2e8cd..ce88e0cd7e03733296aafc0340161af7d7e55eb7 100644 --- a/briar-android-tests/src/test/java/org/briarproject/BlogSharingIntegrationTest.java +++ b/briar-android-tests/src/test/java/org/briarproject/BlogSharingIntegrationTest.java @@ -68,7 +68,7 @@ public class BlogSharingIntegrationTest extends BriarTestCase { private LifecycleManager lifecycleManager0, lifecycleManager1, lifecycleManager2; private SyncSessionFactory sync0, sync1, sync2; - private BlogManager blogManager0, blogManager1; + private BlogManager blogManager0, blogManager1, blogManager2; private ContactManager contactManager0, contactManager1, contactManager2; private Contact contact1, contact2, contact01, contact02; private ContactId contactId1, contactId2, contactId01, contactId02; @@ -139,6 +139,7 @@ public class BlogSharingIntegrationTest extends BriarTestCase { contactManager2 = t2.getContactManager(); blogManager0 = t0.getBlogManager(); blogManager1 = t1.getBlogManager(); + blogManager2 = t2.getBlogManager(); blogSharingManager0 = t0.getBlogSharingManager(); blogSharingManager1 = t1.getBlogSharingManager(); blogSharingManager2 = t2.getBlogSharingManager(); @@ -402,6 +403,106 @@ public class BlogSharingIntegrationTest extends BriarTestCase { stopLifecycles(); } + @Test + public void testRemovingSharedBlog() throws Exception { + startLifecycles(); + + // initialize and let invitee accept all requests + defaultInit(true); + + // send invitation + blogSharingManager0 + .sendInvitation(blog2.getId(), contactId1, "Hi!"); + + // sync first request message + sync0To1(); + eventWaiter.await(TIMEOUT, 1); + assertTrue(listener1.requestReceived); + + // sync response back + sync1To0(); + eventWaiter.await(TIMEOUT, 1); + assertTrue(listener0.responseReceived); + + // blog was added successfully and is shard both ways + assertEquals(3, blogManager1.getBlogs().size()); + Collection<Contact> sharedWith = + blogSharingManager0.getSharedWith(blog2.getId()); + assertEquals(1, sharedWith.size()); + assertEquals(contact1, sharedWith.iterator().next()); + Collection<Contact> sharedBy = + blogSharingManager1.getSharedBy(blog2.getId()); + assertEquals(1, sharedBy.size()); + assertEquals(contact01, sharedBy.iterator().next()); + + // shared blog can be removed + assertTrue(blogManager1.canBeRemoved(blog2.getId())); + + // invitee removes blog again + blogManager1.removeBlog(blog2); + + // sync LEAVE message + sync1To0(); + + // sharer does not share this blog anymore with invitee + sharedWith = + blogSharingManager0.getSharedWith(blog2.getId()); + assertEquals(0, sharedWith.size()); + + stopLifecycles(); + } + + @Test + public void testSharedBlogBecomesPermanent() throws Exception { + startLifecycles(); + + // initialize and let invitee accept all requests + defaultInit(true); + + // invitee only sees two blogs + assertEquals(2, blogManager1.getBlogs().size()); + + // sharer sends invitation for 2's blog to 1 + blogSharingManager0 + .sendInvitation(blog2.getId(), contactId1, "Hi!"); + + // sync first request message + sync0To1(); + eventWaiter.await(TIMEOUT, 1); + assertTrue(listener1.requestReceived); + + // make sure blog2 is shared by 0 + Collection<Contact> contacts = + blogSharingManager1.getSharedBy(blog2.getId()); + assertEquals(1, contacts.size()); + assertTrue(contacts.contains(contact01)); + + // sync response back + sync1To0(); + eventWaiter.await(TIMEOUT, 1); + assertTrue(listener0.responseReceived); + + // blog was added and can be removed + assertEquals(3, blogManager1.getBlogs().size()); + assertTrue(blogManager1.canBeRemoved(blog2.getId())); + + // 1 and 2 are adding each other + contactManager1.addContact(author2, + author1.getId(), master, clock.currentTimeMillis(), true, + true + ); + contactManager2.addContact(author1, + author2.getId(), master, clock.currentTimeMillis(), true, + true + ); + assertEquals(3, blogManager1.getBlogs().size()); + + // now blog can not be removed anymore + assertFalse(blogManager1.canBeRemoved(blog2.getId())); + + stopLifecycles(); + } + @After public void tearDown() throws InterruptedException { diff --git a/briar-android/res/menu/blogs_blog_actions.xml b/briar-android/res/menu/blogs_blog_actions.xml index e8f680a7c3cae5a409275c3de62670f7a116a432..3661a49dffb91a655b61845b9deec7daf8afe860 100644 --- a/briar-android/res/menu/blogs_blog_actions.xml +++ b/briar-android/res/menu/blogs_blog_actions.xml @@ -14,4 +14,10 @@ android:title="@string/sharing_status" app:showAsAction="never"/> + <item + android:id="@+id/action_blog_delete" + android:icon="@drawable/action_delete_white" + android:title="@string/blogs_remove_blog" + app:showAsAction="never"/> + </menu> \ No newline at end of file diff --git a/briar-android/res/values-pt-rBR/strings.xml b/briar-android/res/values-pt-rBR/strings.xml index 52ec3c902679a2dbd9adf590e85090f4de540582..8269ad132fc1f7b03681765abdca413e4de6530a 100644 --- a/briar-android/res/values-pt-rBR/strings.xml +++ b/briar-android/res/values-pt-rBR/strings.xml @@ -267,13 +267,12 @@ Ou o autor não não postou nada ainda, ou a pessoa que compartilhou esse Blog c <string name="blogs_feed_empty_state">Esse é o feed de blog global. Parece que ninguém postou nada, ainda. Seja o primeiro a postar e clique no Ãcone da caneta para escrever um novo Post pro Blog.</string> - <string name="blogs_delete_blog">Deletar Blog</string> - <string name="blogs_delete_blog_dialog_message">Você ter certeza que quer deletar esse Blog e todos seus Posts? + <string name="blogs_remove_blog">Remover Blog</string> + <string name="blogs_remove_blog_dialog_message">Você ter certeza que quer deletar esse Blog e todos seus Posts? Note que isso não irá deletar o Blog dos dispositivos de outras pessoas. </string> - <string name="blogs_delete_blog_ok">Deletar Blog</string> + <string name="blogs_remove_blog_ok">Deletar Blog</string> <string name="blogs_delete_blog_cancel">Manter</string> - <string name="blogs_blog_deleted">Blog Deletado</string> - <string name="blogs_remove_blog">Remover Blog</string> + <string name="blogs_blog_removed">Blog Deletado</string> <string name="blogs_blog_list">Lista de blogs</string> <string name="blogs_available_blogs">Blogs DisponÃveis </string> <string name="blogs_drafts">Rascunhos</string> diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index d6c5807fc4f15dd42db82f1b7161e808c02316d1..bdea4954b26f2387e13f1692855e3eff4d87a46f 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -297,15 +297,13 @@ <string name="blogs_blog_post_received">New Blog Post Received</string> <string name="blogs_blog_post_scroll_to">Scroll To</string> <string name="blogs_blog_failed_to_load">Blog failed to load</string> - <string name="blogs_blog_post_failed_to_load">Blog Post failed to load</string> + <string name="blogs_blog_post_failed_to_load">Blog post failed to load</string> <string name="blogs_feed_empty_state">This is the global blog feed.\n\nIt looks like nobody blogged anything, yet.\n\nBe the first and tap the pen icon to write a new blog post.</string> <string name="blogs_personal_blog">%s\'s Personal Blog</string> - <string name="blogs_delete_blog">Delete Blog</string> - <string name="blogs_delete_blog_dialog_message">Are you sure that you want to delete this Blog and all posts?\nNote that this will not delete the blog from other people\'s devices.</string> - <string name="blogs_delete_blog_ok">Delete Blog</string> - <string name="blogs_delete_blog_cancel">Keep</string> - <string name="blogs_blog_deleted">Blog Deleted</string> <string name="blogs_remove_blog">Remove Blog</string> + <string name="blogs_remove_blog_dialog_message">Are you sure that you want to remove this blog and all posts?\nNote that this will not remove the blog from other people\'s devices.</string> + <string name="blogs_remove_blog_ok">Remove Blog</string> + <string name="blogs_blog_removed">Blog Removed</string> <string name="blogs_sharing_share">Share Blog</string> <string name="blogs_sharing_error">There was an error sharing this blog.</string> <string name="blogs_sharing_button">Share Blog</string> diff --git a/briar-android/src/org/briarproject/android/blogs/BlogController.java b/briar-android/src/org/briarproject/android/blogs/BlogController.java index 532d2dd2505dbb0cd75498f308522df0026e669f..8436813de64e2505bd8fa27eea954199282ba867 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogController.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogController.java @@ -3,7 +3,9 @@ package org.briarproject.android.blogs; import android.support.annotation.Nullable; import org.briarproject.android.controller.ActivityLifecycleController; +import org.briarproject.android.controller.handler.ResultExceptionHandler; import org.briarproject.android.controller.handler.ResultHandler; +import org.briarproject.api.db.DbException; import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; @@ -22,6 +24,9 @@ public interface BlogController extends ActivityLifecycleController { @Nullable MessageId getBlogPostId(int position); + void canDeleteBlog(GroupId groupId, + ResultExceptionHandler<Boolean, DbException> resultHandler); + void deleteBlog(ResultHandler<Boolean> resultHandler); interface BlogPostListener { diff --git a/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java b/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java index 0ec355d70be0d64088baaf0d7c799ffbfc68fce5..0095b4beeca507d5e02e055a2cff57603e921f89 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java @@ -4,6 +4,7 @@ import android.app.Activity; import android.support.annotation.Nullable; import org.briarproject.android.controller.DbControllerImpl; +import org.briarproject.android.controller.handler.ResultExceptionHandler; import org.briarproject.android.controller.handler.ResultHandler; import org.briarproject.api.blogs.Blog; import org.briarproject.api.blogs.BlogManager; @@ -175,6 +176,27 @@ public class BlogControllerImpl extends DbControllerImpl return null; } + @Override + public void canDeleteBlog(final GroupId g, + final ResultExceptionHandler<Boolean, DbException> resultHandler) { + runOnDbThread(new Runnable() { + @Override + public void run() { + if (groupId == null) { + resultHandler.onResult(false); + return; + } + try { + resultHandler.onResult(blogManager.canBeRemoved(groupId)); + } catch (DbException e) { + if (LOG.isLoggable(WARNING)) + LOG.log(WARNING, e.toString(), e); + resultHandler.onException(e); + } + } + }); + } + @Override public void deleteBlog(final ResultHandler<Boolean> resultHandler) { runOnDbThread(new Runnable() { diff --git a/briar-android/src/org/briarproject/android/blogs/BlogFragment.java b/briar-android/src/org/briarproject/android/blogs/BlogFragment.java index 9b9cf4f090941212b44ed1f7a9fda2dd41eb2933..9629d0426441f2430483904a57be4377c0537776 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogFragment.java @@ -21,11 +21,13 @@ import org.briarproject.R; import org.briarproject.android.ActivityComponent; import org.briarproject.android.blogs.BlogController.BlogPostListener; import org.briarproject.android.blogs.BlogPostAdapter.OnBlogPostClickListener; +import org.briarproject.android.controller.handler.UiResultExceptionHandler; import org.briarproject.android.controller.handler.UiResultHandler; import org.briarproject.android.fragment.BaseFragment; import org.briarproject.android.sharing.ShareBlogActivity; import org.briarproject.android.sharing.SharingStatusBlogActivity; import org.briarproject.android.util.BriarRecyclerView; +import org.briarproject.api.db.DbException; import org.briarproject.api.sync.GroupId; import java.util.Collection; @@ -57,6 +59,7 @@ public class BlogFragment extends BaseFragment implements BlogPostListener { private boolean myBlog; private BlogPostAdapter adapter; private BriarRecyclerView list; + private MenuItem deleteButton = null; static BlogFragment newInstance(GroupId groupId, String name, boolean myBlog, boolean isNew) { @@ -124,6 +127,7 @@ public class BlogFragment extends BaseFragment implements BlogPostListener { public void onStart() { super.onStart(); loadData(false); + if (!myBlog) checkIfBlogCanBeDeleted(); } @Override @@ -144,6 +148,8 @@ public class BlogFragment extends BaseFragment implements BlogPostListener { inflater.inflate(R.menu.blogs_my_blog_actions, menu); } else { inflater.inflate(R.menu.blogs_blog_actions, menu); + deleteButton = menu.findItem(R.id.action_blog_delete); + deleteButton.setVisible(false); } super.onCreateOptionsMenu(menu, inflater); } @@ -179,6 +185,9 @@ public class BlogFragment extends BaseFragment implements BlogPostListener { i3.putExtra(GROUP_ID, groupId.getBytes()); startActivity(i3, options.toBundle()); return true; + case R.id.action_blog_delete: + showDeleteDialog(); + return true; default: return super.onOptionsItemSelected(item); } @@ -232,6 +241,28 @@ public class BlogFragment extends BaseFragment implements BlogPostListener { loadData(true); } + private void checkIfBlogCanBeDeleted() { + blogController.canDeleteBlog(groupId, + new UiResultExceptionHandler<Boolean, DbException>( + getActivity()) { + @Override + public void onResultUi(Boolean canBeDeleted) { + if (canBeDeleted) { + showDeleteButton(); + } + } + @Override + public void onExceptionUi(DbException exception) { + // nothing to do here, delete button is already hidden + } + }); + } + + private void showDeleteButton() { + if (deleteButton != null) + deleteButton.setVisible(true); + } + private void displaySnackbar(int stringId) { Snackbar snackbar = Snackbar.make(list, stringId, Snackbar.LENGTH_SHORT); @@ -249,11 +280,11 @@ public class BlogFragment extends BaseFragment implements BlogPostListener { }; AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.BriarDialogTheme); - builder.setTitle(getString(R.string.blogs_delete_blog)); + builder.setTitle(getString(R.string.blogs_remove_blog)); builder.setMessage( - getString(R.string.blogs_delete_blog_dialog_message)); - builder.setPositiveButton(R.string.blogs_delete_blog_cancel, null); - builder.setNegativeButton(R.string.blogs_delete_blog_ok, okListener); + getString(R.string.blogs_remove_blog_dialog_message)); + builder.setPositiveButton(R.string.cancel_button, null); + builder.setNegativeButton(R.string.blogs_remove_blog_ok, okListener); builder.show(); } @@ -264,7 +295,7 @@ public class BlogFragment extends BaseFragment implements BlogPostListener { public void onResultUi(Boolean result) { if (!result) return; Toast.makeText(getActivity(), - R.string.blogs_blog_deleted, LENGTH_SHORT) + R.string.blogs_blog_removed, LENGTH_SHORT) .show(); getActivity().supportFinishAfterTransition(); } diff --git a/briar-api/src/org/briarproject/api/blogs/Blog.java b/briar-api/src/org/briarproject/api/blogs/Blog.java index 4e6827891a67ebde4d63d842fa7e0e5bce2c1269..c97e42be2aae72185845fa2b5ea05ee257ebd17c 100644 --- a/briar-api/src/org/briarproject/api/blogs/Blog.java +++ b/briar-api/src/org/briarproject/api/blogs/Blog.java @@ -11,16 +11,13 @@ public class Blog extends Forum { private final String description; @NotNull private final Author author; - private final boolean permanent; public Blog(@NotNull Group group, @NotNull String name, - @NotNull String description, @NotNull Author author, - boolean permanent) { + @NotNull String description, @NotNull Author author) { super(group, name, null); this.description = description; this.author = author; - this.permanent = permanent; } @NotNull @@ -32,8 +29,4 @@ public class Blog extends Forum { public Author getAuthor() { return author; } - - public boolean isPermanent() { - return permanent; - } } diff --git a/briar-api/src/org/briarproject/api/blogs/BlogFactory.java b/briar-api/src/org/briarproject/api/blogs/BlogFactory.java index 190236bae1f5ae92efc79f535fa1c36e4a02c0e3..585d0700cb2280748fa3e772a54daa07c379c453 100644 --- a/briar-api/src/org/briarproject/api/blogs/BlogFactory.java +++ b/briar-api/src/org/briarproject/api/blogs/BlogFactory.java @@ -1,7 +1,6 @@ package org.briarproject.api.blogs; import org.briarproject.api.FormatException; -import org.briarproject.api.contact.Contact; import org.briarproject.api.identity.Author; import org.briarproject.api.sync.Group; import org.jetbrains.annotations.NotNull; diff --git a/briar-api/src/org/briarproject/api/blogs/BlogManager.java b/briar-api/src/org/briarproject/api/blogs/BlogManager.java index f39a90d629fc6a244854cb2f1737b72a9c435161..368069f11fc394decf529479149ce079e375c89b 100644 --- a/briar-api/src/org/briarproject/api/blogs/BlogManager.java +++ b/briar-api/src/org/briarproject/api/blogs/BlogManager.java @@ -20,6 +20,9 @@ public interface BlogManager { Blog addBlog(LocalAuthor localAuthor, String name, String description) throws DbException; + /** Returns true if a blog can be removed. */ + boolean canBeRemoved(GroupId g) throws DbException; + /** Removes and deletes a blog. */ void removeBlog(Blog b) throws DbException; diff --git a/briar-core/src/org/briarproject/blogs/BlogFactoryImpl.java b/briar-core/src/org/briarproject/blogs/BlogFactoryImpl.java index 68fbe1258e9f09e16730c9578208c8773badd3b2..82f7d7ab2848104dc492f169e184194f69c24e1c 100644 --- a/briar-core/src/org/briarproject/blogs/BlogFactoryImpl.java +++ b/briar-core/src/org/briarproject/blogs/BlogFactoryImpl.java @@ -4,7 +4,6 @@ import org.briarproject.api.FormatException; import org.briarproject.api.blogs.Blog; import org.briarproject.api.blogs.BlogFactory; import org.briarproject.api.clients.ClientHelper; -import org.briarproject.api.contact.Contact; import org.briarproject.api.data.BdfList; import org.briarproject.api.identity.Author; import org.briarproject.api.identity.AuthorFactory; @@ -31,19 +30,14 @@ class BlogFactoryImpl implements BlogFactory { this.clientHelper = clientHelper; } - @Override - public Blog createBlog(@NotNull String name, @NotNull String description, - @NotNull Author author) { - return createBlog(name, description, author, false); - } - @Override public Blog createPersonalBlog(@NotNull Author a) { - return createBlog(PERSONAL_BLOG_NAME, "", a, true); + return createBlog(PERSONAL_BLOG_NAME, "", a); } - private Blog createBlog(@NotNull String name, @NotNull String description, - @NotNull Author author, boolean permanent) { + @Override + public Blog createBlog(@NotNull String name, @NotNull String description, + @NotNull Author author) { try { BdfList blog = BdfList.of( name, @@ -53,7 +47,7 @@ class BlogFactoryImpl implements BlogFactory { byte[] descriptor = clientHelper.toByteArray(blog); Group g = groupFactory .createGroup(BlogManagerImpl.CLIENT_ID, descriptor); - return new Blog(g, name, description, author, permanent); + return new Blog(g, name, description, author); } catch (FormatException e) { throw new RuntimeException(e); } @@ -66,11 +60,10 @@ class BlogFactoryImpl implements BlogFactory { byte[] descriptor = g.getDescriptor(); // Blog Name, Author Name, Public Key BdfList blog = clientHelper.toList(descriptor, 0, descriptor.length); + String name = blog.getString(0); Author a = authorFactory.createAuthor(blog.getString(1), blog.getRaw(2)); - // TODO change permanent depending on how this will be used - boolean permanent = true; - return new Blog(g, blog.getString(0), description, a, permanent); + return new Blog(g, name, description, a); } } diff --git a/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java b/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java index 5a20d8934f07417394e330b206cdbf8d1c4eb613..cc84d7dd2a72f917b1e48c0dd3c68efb8c1212f1 100644 --- a/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java +++ b/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java @@ -10,6 +10,7 @@ import org.briarproject.api.clients.Client; import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.ContactId; +import org.briarproject.api.contact.ContactManager; import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.data.BdfEntry; import org.briarproject.api.data.BdfList; @@ -73,17 +74,19 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, private final DatabaseComponent db; private final IdentityManager identityManager; + private final ContactManager contactManager; private final BlogFactory blogFactory; private final List<RemoveBlogHook> removeHooks; @Inject BlogManagerImpl(DatabaseComponent db, IdentityManager identityManager, ClientHelper clientHelper, MetadataParser metadataParser, - BlogFactory blogFactory) { + ContactManager contactManager, BlogFactory blogFactory) { super(clientHelper, metadataParser); this.db = db; this.identityManager = identityManager; + this.contactManager = contactManager; this.blogFactory = blogFactory; removeHooks = new CopyOnWriteArrayList<RemoveBlogHook>(); } @@ -189,11 +192,36 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, return b; } + @Override + public boolean canBeRemoved(GroupId g) throws DbException { + Transaction txn = db.startTransaction(true); + try { + boolean canBeRemoved = canBeRemoved(txn, g); + txn.setComplete(); + return canBeRemoved; + } finally { + db.endTransaction(txn); + } + } + + private boolean canBeRemoved(Transaction txn, GroupId g) + throws DbException { + boolean canBeRemoved; + Blog b = getBlog(txn, g); + AuthorId authorId = b.getAuthor().getId(); + LocalAuthor localAuthor = identityManager.getLocalAuthor(txn); + canBeRemoved = !contactManager + .contactExists(txn, authorId, localAuthor.getId()); + return canBeRemoved; + } + @Override public void removeBlog(Blog b) throws DbException { // TODO if this gets used, check for RSS feeds posting into this blog Transaction txn = db.startTransaction(false); try { + if (!canBeRemoved(txn, b.getId())) + throw new DbException(); for (RemoveBlogHook hook : removeHooks) hook.removingBlog(txn, b); db.removeGroup(txn, b.getGroup()); diff --git a/briar-tests/src/org/briarproject/blogs/BlogManagerImplTest.java b/briar-tests/src/org/briarproject/blogs/BlogManagerImplTest.java index 745ea254c2ad48653980bde75a09d113f11adb43..efaf20650c2435ee574aafedb1e1660c6c297566 100644 --- a/briar-tests/src/org/briarproject/blogs/BlogManagerImplTest.java +++ b/briar-tests/src/org/briarproject/blogs/BlogManagerImplTest.java @@ -9,6 +9,7 @@ import org.briarproject.api.blogs.BlogPostHeader; import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.ContactId; +import org.briarproject.api.contact.ContactManager; import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.data.BdfEntry; import org.briarproject.api.data.BdfList; @@ -59,6 +60,8 @@ public class BlogManagerImplTest extends BriarTestCase { private final ClientHelper clientHelper = context.mock(ClientHelper.class); private final MetadataParser metadataParser = context.mock(MetadataParser.class); + private final ContactManager contactManager = + context.mock(ContactManager.class); private final BlogFactory blogFactory = context.mock(BlogFactory.class); private final Blog blog1, blog2; @@ -67,7 +70,7 @@ public class BlogManagerImplTest extends BriarTestCase { public BlogManagerImplTest() { blogManager = new BlogManagerImpl(db, identityManager, clientHelper, - metadataParser, blogFactory); + metadataParser, contactManager, blogFactory); blog1 = getBlog("Test Blog 1", "Test Description 1"); blog2 = getBlog("Test Blog 2", "Test Description 2"); @@ -246,6 +249,17 @@ public class BlogManagerImplTest extends BriarTestCase { context.checking(new Expectations() {{ oneOf(db).startTransaction(false); will(returnValue(txn)); + oneOf(db).getGroup(txn, blog1.getId()); + will(returnValue(blog1.getGroup())); + oneOf(clientHelper) + .getGroupMetadataAsDictionary(txn, blog1.getId()); + oneOf(blogFactory).parseBlog(blog1.getGroup(), ""); + will(returnValue(blog1)); + oneOf(identityManager).getLocalAuthor(txn); + will(returnValue(blog2.getAuthor())); + oneOf(contactManager).contactExists(txn, blog1.getAuthor().getId(), + blog2.getAuthor().getId()); + will(returnValue(false)); oneOf(db).removeGroup(txn, blog1.getGroup()); oneOf(db).endTransaction(txn); }}); @@ -306,7 +320,7 @@ public class BlogManagerImplTest extends BriarTestCase { final LocalAuthor localAuthor = new LocalAuthor(authorId, "Author", publicKey, privateKey, created); - return new Blog(group, name, desc, localAuthor, false); + return new Blog(group, name, desc, localAuthor); } private BdfDictionary authorToBdfDictionary(Author a) { diff --git a/briar-tests/src/org/briarproject/blogs/BlogPostValidatorTest.java b/briar-tests/src/org/briarproject/blogs/BlogPostValidatorTest.java index 90dba5912728e4ba1da6335c4217be28d29cc26d..e70fce8afbffc46c5bb17fd6bb8b69a55c7097c9 100644 --- a/briar-tests/src/org/briarproject/blogs/BlogPostValidatorTest.java +++ b/briar-tests/src/org/briarproject/blogs/BlogPostValidatorTest.java @@ -67,7 +67,7 @@ public class BlogPostValidatorTest extends BriarTestCase { AuthorId authorId = new AuthorId(TestUtils.getRandomBytes(AuthorId.LENGTH)); byte[] publicKey = TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH); author = new Author(authorId, "Author", publicKey); - blog = new Blog(group, "Test Blog", "", author, false); + blog = new Blog(group, "Test Blog", "", author); MessageId messageId = new MessageId(TestUtils.getRandomId()); long timestamp = System.currentTimeMillis();