Merge branch '436-automatic-personal-blogs-backend' into 'master'

Backend for Automatic Micro Blogs

This MR introduces automatic personal blogs to the Blog client. When a contact is added, her personal blog will also be added automatically. Also, when a new identity is added, a personal blog for that identity is created.

The first commit changes the blog paradigm to short-form blogs and introduces other things that will be useful later in the UI (!214) such as a BlogPostAdded event and the possibility to delete/remove blogs (not the personal ones).

This MR is based on !224 to prevent crashes that are fixed by it. So please review and merge !224 first.

See merge request !223
This commit is contained in:
Torsten Grote
2016-06-23 15:05:46 +00:00
18 changed files with 346 additions and 121 deletions

View File

@@ -11,13 +11,16 @@ public class Blog extends Forum {
private final String description; private final String description;
@NotNull @NotNull
private final Author author; private final Author author;
private final boolean permanent;
public Blog(@NotNull Group group, @NotNull String name, public Blog(@NotNull Group group, @NotNull String name,
@NotNull String description, @NotNull Author author) { @NotNull String description, @NotNull Author author,
boolean permanent) {
super(group, name, null); super(group, name, null);
this.description = description; this.description = description;
this.author = author; this.author = author;
this.permanent = permanent;
} }
@NotNull @NotNull
@@ -29,4 +32,8 @@ public class Blog extends Forum {
public Author getAuthor() { public Author getAuthor() {
return author; return author;
} }
public boolean isPermanent() {
return permanent;
}
} }

View File

@@ -16,12 +16,12 @@ public interface BlogConstants {
/** The length of a blog post's title in UTF-8 bytes. */ /** The length of a blog post's title in UTF-8 bytes. */
int MAX_BLOG_POST_TITLE_LENGTH = 100; int MAX_BLOG_POST_TITLE_LENGTH = 100;
/** The length of a blog post's teaser in UTF-8 bytes. */
int MAX_BLOG_POST_TEASER_LENGTH = 240;
/** The maximum length of a blog post's body in bytes. */ /** The maximum length of a blog post's body in bytes. */
int MAX_BLOG_POST_BODY_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024; int MAX_BLOG_POST_BODY_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024;
/** The internal name of personal blogs that are created automatically */
String PERSONAL_BLOG_NAME = "briar.PERSONAL_BLOG_NAME";
/* Blog Sharing Constants */ /* Blog Sharing Constants */
String BLOG_TITLE = "blogTitle"; String BLOG_TITLE = "blogTitle";
String BLOG_DESC = "blogDescription"; String BLOG_DESC = "blogDescription";
@@ -31,9 +31,8 @@ public interface BlogConstants {
// Metadata keys // Metadata keys
String KEY_DESCRIPTION = "description"; String KEY_DESCRIPTION = "description";
String KEY_TITLE = "title"; String KEY_TITLE = "title";
String KEY_TEASER = "teaser";
String KEY_HAS_BODY = "hasBody";
String KEY_TIMESTAMP = "timestamp"; String KEY_TIMESTAMP = "timestamp";
String KEY_TIME_RECEIVED = "timeReceived";
String KEY_PARENT = "parent"; String KEY_PARENT = "parent";
String KEY_AUTHOR_ID = "id"; String KEY_AUTHOR_ID = "id";
String KEY_AUTHOR_NAME = "name"; String KEY_AUTHOR_NAME = "name";

View File

@@ -1,6 +1,7 @@
package org.briarproject.api.blogs; package org.briarproject.api.blogs;
import org.briarproject.api.FormatException; import org.briarproject.api.FormatException;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.identity.Author; import org.briarproject.api.identity.Author;
import org.briarproject.api.sync.Group; import org.briarproject.api.sync.Group;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -11,6 +12,9 @@ public interface BlogFactory {
Blog createBlog(@NotNull String name, @NotNull String description, Blog createBlog(@NotNull String name, @NotNull String description,
@NotNull Author author); @NotNull Author author);
/** Creates a personal blog for a given author. */
Blog createPersonalBlog(@NotNull Author author);
/** Parses a blog with the given Group and description */ /** Parses a blog with the given Group and description */
Blog parseBlog(@NotNull Group g, @NotNull String description) Blog parseBlog(@NotNull Group g, @NotNull String description)
throws FormatException; throws FormatException;

View File

@@ -1,8 +1,8 @@
package org.briarproject.api.blogs; package org.briarproject.api.blogs;
import org.briarproject.api.FormatException;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Transaction; import org.briarproject.api.db.Transaction;
import org.briarproject.api.identity.Author;
import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.ClientId;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
@@ -20,6 +20,9 @@ public interface BlogManager {
Blog addBlog(LocalAuthor localAuthor, String name, String description) Blog addBlog(LocalAuthor localAuthor, String name, String description)
throws DbException; throws DbException;
/** Removes and deletes a blog. */
void removeBlog(Blog b) throws DbException;
/** Stores a local blog post. */ /** Stores a local blog post. */
void addLocalPost(BlogPost p) throws DbException; void addLocalPost(BlogPost p) throws DbException;
@@ -29,9 +32,12 @@ public interface BlogManager {
/** Returns the blog with the given ID. */ /** Returns the blog with the given ID. */
Blog getBlog(Transaction txn, GroupId g) throws DbException; Blog getBlog(Transaction txn, GroupId g) throws DbException;
/** Returns all blogs to which the localAuthor created. */ /** Returns all blogs owned by the given localAuthor. */
Collection<Blog> getBlogs(LocalAuthor localAuthor) throws DbException; Collection<Blog> getBlogs(LocalAuthor localAuthor) throws DbException;
/** Returns only the personal blog of the given author. */
Blog getPersonalBlog(Author author) throws DbException;
/** Returns all blogs to which the user subscribes. */ /** Returns all blogs to which the user subscribes. */
Collection<Blog> getBlogs() throws DbException; Collection<Blog> getBlogs() throws DbException;
@@ -45,4 +51,11 @@ public interface BlogManager {
/** Marks a blog post as read or unread. */ /** Marks a blog post as read or unread. */
void setReadFlag(MessageId m, boolean read) throws DbException; void setReadFlag(MessageId m, boolean read) throws DbException;
/** Registers a hook to be called whenever a blog is removed. */
void registerRemoveBlogHook(RemoveBlogHook hook);
interface RemoveBlogHook {
void removingBlog(Transaction txn, Blog b) throws DbException;
}
} }

View File

@@ -1,43 +1,27 @@
package org.briarproject.api.blogs; package org.briarproject.api.blogs;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.briarproject.api.forum.ForumPost; import org.briarproject.api.forum.ForumPost;
import org.briarproject.api.identity.Author; import org.briarproject.api.identity.Author;
import org.briarproject.api.sync.Message; import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class BlogPost extends ForumPost { public class BlogPost extends ForumPost {
@Nullable @Nullable
private final String title; private final String title;
@NotNull
private final String teaser;
private final boolean hasBody;
public BlogPost(@Nullable String title, @NotNull String teaser, public BlogPost(@Nullable String title, @NotNull Message message,
boolean hasBody, @NotNull Message message, @Nullable MessageId parent, @NotNull Author author,
@Nullable MessageId parent, @NotNull Author author,
@NotNull String contentType) { @NotNull String contentType) {
super(message, parent, author, contentType); super(message, parent, author, contentType);
this.title = title; this.title = title;
this.teaser = teaser;
this.hasBody = hasBody;
} }
@Nullable @Nullable
public String getTitle() { public String getTitle() {
return title; return title;
} }
@NotNull
public String getTeaser() {
return teaser;
}
public boolean hasBody() {
return hasBody;
}
} }

View File

@@ -12,8 +12,8 @@ import java.security.GeneralSecurityException;
public interface BlogPostFactory { public interface BlogPostFactory {
BlogPost createBlogPost(@NotNull GroupId groupId, @Nullable String title, BlogPost createBlogPost(@NotNull GroupId groupId, @Nullable String title,
@NotNull String teaser, long timestamp, @Nullable MessageId parent, long timestamp, @Nullable MessageId parent,
@NotNull LocalAuthor author, @NotNull String contentType, @NotNull LocalAuthor author, @NotNull String contentType,
@Nullable byte[] body) @NotNull byte[] body)
throws FormatException, GeneralSecurityException; throws FormatException, GeneralSecurityException;
} }

View File

@@ -11,20 +11,16 @@ public class BlogPostHeader extends PostHeader {
@Nullable @Nullable
private final String title; private final String title;
@NotNull private final long timeReceived;
private final String teaser;
private final boolean hasBody;
public BlogPostHeader(@Nullable String title, @NotNull String teaser, public BlogPostHeader(@Nullable String title, @NotNull MessageId id,
boolean hasBody, @NotNull MessageId id, @Nullable MessageId parentId, long timestamp, long timeReceived,
@Nullable MessageId parentId, long timestamp,
@NotNull Author author, @NotNull Status authorStatus, @NotNull Author author, @NotNull Status authorStatus,
@NotNull String contentType, boolean read) { @NotNull String contentType, boolean read) {
super(id, parentId, timestamp, author, authorStatus, contentType, read); super(id, parentId, timestamp, author, authorStatus, contentType, read);
this.title = title; this.title = title;
this.teaser = teaser; this.timeReceived = timeReceived;
this.hasBody = hasBody;
} }
@Nullable @Nullable
@@ -32,12 +28,8 @@ public class BlogPostHeader extends PostHeader {
return title; return title;
} }
@NotNull public long getTimeReceived() {
public String getTeaser() { return timeReceived;
return teaser;
} }
public boolean hasBody() {
return hasBody;
}
} }

View File

@@ -0,0 +1,32 @@
package org.briarproject.api.event;
import org.briarproject.api.blogs.BlogPostHeader;
import org.briarproject.api.sync.GroupId;
/** An event that is broadcast when a blog post was added to the database. */
public class BlogPostAddedEvent extends Event {
private final GroupId groupId;
private final BlogPostHeader header;
private final boolean local;
public BlogPostAddedEvent(GroupId groupId, BlogPostHeader header,
boolean local) {
this.groupId = groupId;
this.header = header;
this.local = local;
}
public GroupId getGroupId() {
return groupId;
}
public BlogPostHeader getHeader() {
return header;
}
public boolean isLocal() {
return local;
}
}

View File

@@ -29,6 +29,9 @@ public interface IdentityManager {
/** Returns the trust-level status of the author */ /** Returns the trust-level status of the author */
Status getAuthorStatus(AuthorId a) throws DbException; Status getAuthorStatus(AuthorId a) throws DbException;
/** Returns the trust-level status of the author */
Status getAuthorStatus(Transaction txn, AuthorId a) throws DbException;
interface AddIdentityHook { interface AddIdentityHook {
void addingIdentity(Transaction txn, LocalAuthor a) throws DbException; void addingIdentity(Transaction txn, LocalAuthor a) throws DbException;
} }

View File

@@ -4,6 +4,7 @@ import org.briarproject.api.FormatException;
import org.briarproject.api.blogs.Blog; import org.briarproject.api.blogs.Blog;
import org.briarproject.api.blogs.BlogFactory; import org.briarproject.api.blogs.BlogFactory;
import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.data.BdfList; import org.briarproject.api.data.BdfList;
import org.briarproject.api.identity.Author; import org.briarproject.api.identity.Author;
import org.briarproject.api.identity.AuthorFactory; import org.briarproject.api.identity.AuthorFactory;
@@ -13,6 +14,8 @@ import org.jetbrains.annotations.NotNull;
import javax.inject.Inject; import javax.inject.Inject;
import static org.briarproject.api.blogs.BlogConstants.PERSONAL_BLOG_NAME;
class BlogFactoryImpl implements BlogFactory { class BlogFactoryImpl implements BlogFactory {
private final GroupFactory groupFactory; private final GroupFactory groupFactory;
@@ -31,6 +34,16 @@ class BlogFactoryImpl implements BlogFactory {
@Override @Override
public Blog createBlog(@NotNull String name, @NotNull String description, public Blog createBlog(@NotNull String name, @NotNull String description,
@NotNull Author author) { @NotNull Author author) {
return createBlog(name, description, author, false);
}
@Override
public Blog createPersonalBlog(@NotNull Author a) {
return createBlog(PERSONAL_BLOG_NAME, "", a, true);
}
private Blog createBlog(@NotNull String name, @NotNull String description,
@NotNull Author author, boolean permanent) {
try { try {
BdfList blog = BdfList.of( BdfList blog = BdfList.of(
name, name,
@@ -40,7 +53,7 @@ class BlogFactoryImpl implements BlogFactory {
byte[] descriptor = clientHelper.toByteArray(blog); byte[] descriptor = clientHelper.toByteArray(blog);
Group g = groupFactory Group g = groupFactory
.createGroup(BlogManagerImpl.CLIENT_ID, descriptor); .createGroup(BlogManagerImpl.CLIENT_ID, descriptor);
return new Blog(g, name, description, author); return new Blog(g, name, description, author, permanent);
} catch (FormatException e) { } catch (FormatException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -55,7 +68,9 @@ class BlogFactoryImpl implements BlogFactory {
BdfList blog = clientHelper.toList(descriptor, 0, descriptor.length); BdfList blog = clientHelper.toList(descriptor, 0, descriptor.length);
Author a = Author a =
authorFactory.createAuthor(blog.getString(1), blog.getRaw(2)); authorFactory.createAuthor(blog.getString(1), blog.getRaw(2));
return new Blog(g, blog.getString(0), description, a); // TODO change permanent depending on how this will be used
boolean permanent = false;
return new Blog(g, blog.getString(0), description, a, permanent);
} }
} }

View File

@@ -6,22 +6,31 @@ import org.briarproject.api.blogs.BlogFactory;
import org.briarproject.api.blogs.BlogManager; import org.briarproject.api.blogs.BlogManager;
import org.briarproject.api.blogs.BlogPost; import org.briarproject.api.blogs.BlogPost;
import org.briarproject.api.blogs.BlogPostHeader; import org.briarproject.api.blogs.BlogPostHeader;
import org.briarproject.api.clients.Client;
import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.data.BdfEntry; import org.briarproject.api.data.BdfEntry;
import org.briarproject.api.data.BdfList; import org.briarproject.api.data.BdfList;
import org.briarproject.api.data.MetadataParser;
import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Transaction; import org.briarproject.api.db.Transaction;
import org.briarproject.api.event.BlogPostAddedEvent;
import org.briarproject.api.identity.Author; import org.briarproject.api.identity.Author;
import org.briarproject.api.identity.Author.Status; import org.briarproject.api.identity.Author.Status;
import org.briarproject.api.identity.AuthorId; import org.briarproject.api.identity.AuthorId;
import org.briarproject.api.identity.IdentityManager; import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.identity.IdentityManager.AddIdentityHook;
import org.briarproject.api.identity.IdentityManager.RemoveIdentityHook;
import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.ClientId;
import org.briarproject.api.sync.Group; import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
import org.briarproject.clients.BdfIncomingMessageHook;
import org.briarproject.util.StringUtils; import org.briarproject.util.StringUtils;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -31,24 +40,29 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.inject.Inject; import javax.inject.Inject;
import static java.util.logging.Level.WARNING;
import static org.briarproject.api.blogs.BlogConstants.KEY_AUTHOR; import static org.briarproject.api.blogs.BlogConstants.KEY_AUTHOR;
import static org.briarproject.api.blogs.BlogConstants.KEY_AUTHOR_ID; import static org.briarproject.api.blogs.BlogConstants.KEY_AUTHOR_ID;
import static org.briarproject.api.blogs.BlogConstants.KEY_AUTHOR_NAME; import static org.briarproject.api.blogs.BlogConstants.KEY_AUTHOR_NAME;
import static org.briarproject.api.blogs.BlogConstants.KEY_CONTENT_TYPE; import static org.briarproject.api.blogs.BlogConstants.KEY_CONTENT_TYPE;
import static org.briarproject.api.blogs.BlogConstants.KEY_DESCRIPTION; import static org.briarproject.api.blogs.BlogConstants.KEY_DESCRIPTION;
import static org.briarproject.api.blogs.BlogConstants.KEY_HAS_BODY;
import static org.briarproject.api.blogs.BlogConstants.KEY_PARENT; import static org.briarproject.api.blogs.BlogConstants.KEY_PARENT;
import static org.briarproject.api.blogs.BlogConstants.KEY_PUBLIC_KEY; import static org.briarproject.api.blogs.BlogConstants.KEY_PUBLIC_KEY;
import static org.briarproject.api.blogs.BlogConstants.KEY_READ; import static org.briarproject.api.blogs.BlogConstants.KEY_READ;
import static org.briarproject.api.blogs.BlogConstants.KEY_TEASER;
import static org.briarproject.api.blogs.BlogConstants.KEY_TIMESTAMP; import static org.briarproject.api.blogs.BlogConstants.KEY_TIMESTAMP;
import static org.briarproject.api.blogs.BlogConstants.KEY_TIME_RECEIVED;
import static org.briarproject.api.blogs.BlogConstants.KEY_TITLE; import static org.briarproject.api.blogs.BlogConstants.KEY_TITLE;
import static org.briarproject.api.contact.ContactManager.AddContactHook;
import static org.briarproject.api.contact.ContactManager.RemoveContactHook;
class BlogManagerImpl implements BlogManager { class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
AddContactHook, RemoveContactHook, Client,
AddIdentityHook, RemoveIdentityHook {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(BlogManagerImpl.class.getName()); Logger.getLogger(BlogManagerImpl.class.getName());
@@ -59,17 +73,19 @@ class BlogManagerImpl implements BlogManager {
private final DatabaseComponent db; private final DatabaseComponent db;
private final IdentityManager identityManager; private final IdentityManager identityManager;
private final ClientHelper clientHelper;
private final BlogFactory blogFactory; private final BlogFactory blogFactory;
private final List<RemoveBlogHook> removeHooks;
@Inject @Inject
BlogManagerImpl(DatabaseComponent db, IdentityManager identityManager, BlogManagerImpl(DatabaseComponent db, IdentityManager identityManager,
ClientHelper clientHelper, BlogFactory blogFactory) { ClientHelper clientHelper, MetadataParser metadataParser,
BlogFactory blogFactory) {
super(clientHelper, metadataParser);
this.db = db; this.db = db;
this.identityManager = identityManager; this.identityManager = identityManager;
this.clientHelper = clientHelper;
this.blogFactory = blogFactory; this.blogFactory = blogFactory;
removeHooks = new CopyOnWriteArrayList<RemoveBlogHook>();
} }
@Override @Override
@@ -77,6 +93,79 @@ class BlogManagerImpl implements BlogManager {
return CLIENT_ID; return CLIENT_ID;
} }
@Override
public void createLocalState(Transaction txn) throws DbException {
// Ensure every identity does have its own personal blog
// TODO this can probably be removed once #446 is resolved and all users migrated to a new version
for (LocalAuthor a : db.getLocalAuthors(txn)) {
Blog b = blogFactory.createPersonalBlog(a);
Group g = b.getGroup();
if (!db.containsGroup(txn, g.getId())) {
db.addGroup(txn, g);
for (ContactId c : db.getContacts(txn, a.getId())) {
db.setVisibleToContact(txn, c, g.getId(), true);
}
}
}
// Ensure that we have the personal blogs of all pre-existing contacts
for (Contact c : db.getContacts(txn)) addingContact(txn, c);
}
@Override
public void addingContact(Transaction txn, Contact c) throws DbException {
// get personal blog of the contact
Blog b = blogFactory.createPersonalBlog(c.getAuthor());
Group g = b.getGroup();
if (!db.containsGroup(txn, g.getId())) {
// add the personal blog of the contact
db.addGroup(txn, g);
db.setVisibleToContact(txn, c.getId(), g.getId(), true);
// share our personal blog with the new contact
LocalAuthor a = db.getLocalAuthor(txn, c.getLocalAuthorId());
Blog b2 = blogFactory.createPersonalBlog(a);
db.setVisibleToContact(txn, c.getId(), b2.getId(), true);
}
}
@Override
public void removingContact(Transaction txn, Contact c) throws DbException {
if (c != null) {
Blog b = blogFactory.createPersonalBlog(c.getAuthor());
db.removeGroup(txn, b.getGroup());
}
}
@Override
public void addingIdentity(Transaction txn, LocalAuthor a)
throws DbException {
// add a personal blog for the new identity
LOG.info("New Personal Blog Added.");
Blog b = blogFactory.createPersonalBlog(a);
db.addGroup(txn, b.getGroup());
}
@Override
public void removingIdentity(Transaction txn, LocalAuthor a)
throws DbException {
// remove the personal blog of that identity
Blog b = blogFactory.createPersonalBlog(a);
db.removeGroup(txn, b.getGroup());
}
@Override
protected void incomingMessage(Transaction txn, Message m, BdfList list,
BdfDictionary meta) throws DbException, FormatException {
GroupId groupId = m.getGroupId();
BlogPostHeader h = getPostHeaderFromMetadata(txn, m.getId(), meta);
BlogPostAddedEvent event =
new BlogPostAddedEvent(groupId, h, false);
txn.attach(event);
}
@Override @Override
public Blog addBlog(LocalAuthor localAuthor, String name, public Blog addBlog(LocalAuthor localAuthor, String name,
String description) throws DbException { String description) throws DbException {
@@ -101,13 +190,25 @@ class BlogManagerImpl implements BlogManager {
} }
@Override @Override
public void addLocalPost(BlogPost p) throws DbException { public void removeBlog(Blog b) throws DbException {
Transaction txn = db.startTransaction(false);
try { try {
BdfDictionary meta = new BdfDictionary(); for (RemoveBlogHook hook : removeHooks)
hook.removingBlog(txn, b);
db.removeGroup(txn, b.getGroup());
txn.setComplete();
} finally {
db.endTransaction(txn);
}
}
@Override
public void addLocalPost(BlogPost p) throws DbException {
BdfDictionary meta;
try {
meta = new BdfDictionary();
if (p.getTitle() != null) meta.put(KEY_TITLE, p.getTitle()); if (p.getTitle() != null) meta.put(KEY_TITLE, p.getTitle());
meta.put(KEY_TEASER, p.getTeaser());
meta.put(KEY_TIMESTAMP, p.getMessage().getTimestamp()); meta.put(KEY_TIMESTAMP, p.getMessage().getTimestamp());
meta.put(KEY_HAS_BODY, p.hasBody());
if (p.getParent() != null) meta.put(KEY_PARENT, p.getParent()); if (p.getParent() != null) meta.put(KEY_PARENT, p.getParent());
Author a = p.getAuthor(); Author a = p.getAuthor();
@@ -123,6 +224,22 @@ class BlogManagerImpl implements BlogManager {
} catch (FormatException e) { } catch (FormatException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
// broadcast event about new post
Transaction txn = db.startTransaction(true);
try {
GroupId groupId = p.getMessage().getGroupId();
MessageId postId = p.getMessage().getId();
BlogPostHeader h = getPostHeaderFromMetadata(txn, postId, meta);
BlogPostAddedEvent event =
new BlogPostAddedEvent(groupId, h, true);
txn.attach(event);
txn.setComplete();
} catch (FormatException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} finally {
db.endTransaction(txn);
}
} }
@Override @Override
@@ -163,6 +280,11 @@ class BlogManagerImpl implements BlogManager {
return Collections.unmodifiableList(blogs); return Collections.unmodifiableList(blogs);
} }
@Override
public Blog getPersonalBlog(Author author) throws DbException {
return blogFactory.createPersonalBlog(author);
}
@Override @Override
public Collection<Blog> getBlogs() throws DbException { public Collection<Blog> getBlogs() throws DbException {
try { try {
@@ -189,16 +311,20 @@ class BlogManagerImpl implements BlogManager {
@Nullable @Nullable
public byte[] getPostBody(MessageId m) throws DbException { public byte[] getPostBody(MessageId m) throws DbException {
try { try {
// content, signature
// content: parent, contentType, title, teaser, body, attachments
BdfList message = clientHelper.getMessageAsList(m); BdfList message = clientHelper.getMessageAsList(m);
BdfList content = message.getList(0); return getPostBody(message);
return content.getRaw(4);
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} }
} }
private byte[] getPostBody(BdfList message) throws FormatException {
// content, signature
// content: parent, contentType, title, body, attachments
BdfList content = message.getList(0);
return content.getRaw(3);
}
@Override @Override
public Collection<BlogPostHeader> getPostHeaders(GroupId g) public Collection<BlogPostHeader> getPostHeaders(GroupId g)
throws DbException { throws DbException {
@@ -213,26 +339,9 @@ class BlogManagerImpl implements BlogManager {
for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) { for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) {
try { try {
BdfDictionary meta = entry.getValue(); BdfDictionary meta = entry.getValue();
String title = meta.getOptionalString(KEY_TITLE); BlogPostHeader h =
String teaser = meta.getString(KEY_TEASER); getPostHeaderFromMetadata(null, entry.getKey(), meta);
boolean hasBody = meta.getBoolean(KEY_HAS_BODY); headers.add(h);
long timestamp = meta.getLong(KEY_TIMESTAMP);
MessageId parentId = null;
if (meta.containsKey(KEY_PARENT))
parentId = new MessageId(meta.getRaw(KEY_PARENT));
BdfDictionary d = meta.getDictionary(KEY_AUTHOR);
AuthorId authorId = new AuthorId(d.getRaw(KEY_AUTHOR_ID));
String name = d.getString(KEY_AUTHOR_NAME);
byte[] publicKey = d.getRaw(KEY_PUBLIC_KEY);
Author author = new Author(authorId, name, publicKey);
Status authorStatus = identityManager.getAuthorStatus(authorId);
String contentType = meta.getString(KEY_CONTENT_TYPE);
boolean read = meta.getBoolean(KEY_READ);
headers.add(new BlogPostHeader(title, teaser, hasBody,
entry.getKey(), parentId, timestamp, author,
authorStatus, contentType, read));
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} }
@@ -251,10 +360,43 @@ class BlogManagerImpl implements BlogManager {
} }
} }
@Override
public void registerRemoveBlogHook(RemoveBlogHook hook) {
removeHooks.add(hook);
}
private String getBlogDescription(Transaction txn, GroupId g) private String getBlogDescription(Transaction txn, GroupId g)
throws DbException, FormatException { throws DbException, FormatException {
BdfDictionary d = clientHelper.getGroupMetadataAsDictionary(txn, g); BdfDictionary d = clientHelper.getGroupMetadataAsDictionary(txn, g);
return d.getString(KEY_DESCRIPTION); return d.getString(KEY_DESCRIPTION, "");
} }
private BlogPostHeader getPostHeaderFromMetadata(@Nullable Transaction txn,
MessageId id, BdfDictionary meta)
throws DbException, FormatException {
String title = meta.getOptionalString(KEY_TITLE);
long timestamp = meta.getLong(KEY_TIMESTAMP);
long timeReceived = meta.getLong(KEY_TIME_RECEIVED, timestamp);
MessageId parentId = null;
if (meta.containsKey(KEY_PARENT))
parentId = new MessageId(meta.getRaw(KEY_PARENT));
BdfDictionary d = meta.getDictionary(KEY_AUTHOR);
AuthorId authorId = new AuthorId(d.getRaw(KEY_AUTHOR_ID));
String name = d.getString(KEY_AUTHOR_NAME);
byte[] publicKey = d.getRaw(KEY_PUBLIC_KEY);
Author author = new Author(authorId, name, publicKey);
Status authorStatus;
if (txn == null)
authorStatus = identityManager.getAuthorStatus(authorId);
else {
authorStatus = identityManager.getAuthorStatus(txn, authorId);
}
String contentType = meta.getString(KEY_CONTENT_TYPE);
boolean read = meta.getBoolean(KEY_READ);
return new BlogPostHeader(title, id, parentId, timestamp, timeReceived,
author, authorStatus, contentType, read);
}
} }

View File

@@ -22,7 +22,6 @@ import java.security.GeneralSecurityException;
import javax.inject.Inject; import javax.inject.Inject;
import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_POST_BODY_LENGTH; import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_POST_BODY_LENGTH;
import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_POST_TEASER_LENGTH;
import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_POST_TITLE_LENGTH; import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_POST_TITLE_LENGTH;
import static org.briarproject.api.blogs.BlogConstants.MAX_CONTENT_TYPE_LENGTH; import static org.briarproject.api.blogs.BlogConstants.MAX_CONTENT_TYPE_LENGTH;
@@ -39,25 +38,22 @@ class BlogPostFactoryImpl implements BlogPostFactory {
@Override @Override
public BlogPost createBlogPost(@NotNull GroupId groupId, public BlogPost createBlogPost(@NotNull GroupId groupId,
@Nullable String title, @NotNull String teaser, long timestamp, @Nullable String title, long timestamp,
@Nullable MessageId parent, @NotNull LocalAuthor author, @Nullable MessageId parent, @NotNull LocalAuthor author,
@NotNull String contentType, @Nullable byte[] body) @NotNull String contentType, @NotNull byte[] body)
throws FormatException, GeneralSecurityException { throws FormatException, GeneralSecurityException {
// Validate the arguments // Validate the arguments
if (title != null && if (title != null &&
StringUtils.toUtf8(title).length > MAX_BLOG_POST_TITLE_LENGTH) StringUtils.toUtf8(title).length > MAX_BLOG_POST_TITLE_LENGTH)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
if (StringUtils.toUtf8(teaser).length > MAX_BLOG_POST_TEASER_LENGTH)
throw new IllegalArgumentException();
if (StringUtils.toUtf8(contentType).length > MAX_CONTENT_TYPE_LENGTH) if (StringUtils.toUtf8(contentType).length > MAX_CONTENT_TYPE_LENGTH)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
if (body != null && body.length > MAX_BLOG_POST_BODY_LENGTH) if (body.length > MAX_BLOG_POST_BODY_LENGTH)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
// Serialise the data to be signed // Serialise the data to be signed
BdfList content = BdfList content = BdfList.of(parent, contentType, title, body, null);
BdfList.of(parent, contentType, title, teaser, body, null);
BdfList signed = BdfList.of(groupId, timestamp, content); BdfList signed = BdfList.of(groupId, timestamp, content);
// Generate the signature // Generate the signature
@@ -72,7 +68,6 @@ class BlogPostFactoryImpl implements BlogPostFactory {
// Serialise the signed message // Serialise the signed message
BdfList message = BdfList.of(content, sig); BdfList message = BdfList.of(content, sig);
Message m = clientHelper.createMessage(groupId, timestamp, message); Message m = clientHelper.createMessage(groupId, timestamp, message);
return new BlogPost(title, teaser, body != null, m, parent, author, return new BlogPost(title, m, parent, author, contentType);
contentType);
} }
} }

View File

@@ -11,6 +11,7 @@ import org.briarproject.api.crypto.KeyParser;
import org.briarproject.api.crypto.PublicKey; import org.briarproject.api.crypto.PublicKey;
import org.briarproject.api.crypto.Signature; import org.briarproject.api.crypto.Signature;
import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.data.BdfEntry;
import org.briarproject.api.data.BdfList; import org.briarproject.api.data.BdfList;
import org.briarproject.api.data.MetadataEncoder; import org.briarproject.api.data.MetadataEncoder;
import org.briarproject.api.identity.Author; import org.briarproject.api.identity.Author;
@@ -25,15 +26,17 @@ import java.security.GeneralSecurityException;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import static org.briarproject.api.blogs.BlogConstants.KEY_AUTHOR;
import static org.briarproject.api.blogs.BlogConstants.KEY_AUTHOR_ID;
import static org.briarproject.api.blogs.BlogConstants.KEY_AUTHOR_NAME;
import static org.briarproject.api.blogs.BlogConstants.KEY_CONTENT_TYPE; import static org.briarproject.api.blogs.BlogConstants.KEY_CONTENT_TYPE;
import static org.briarproject.api.blogs.BlogConstants.KEY_HAS_BODY;
import static org.briarproject.api.blogs.BlogConstants.KEY_PARENT; import static org.briarproject.api.blogs.BlogConstants.KEY_PARENT;
import static org.briarproject.api.blogs.BlogConstants.KEY_PUBLIC_KEY;
import static org.briarproject.api.blogs.BlogConstants.KEY_READ; import static org.briarproject.api.blogs.BlogConstants.KEY_READ;
import static org.briarproject.api.blogs.BlogConstants.KEY_TEASER;
import static org.briarproject.api.blogs.BlogConstants.KEY_TIMESTAMP; import static org.briarproject.api.blogs.BlogConstants.KEY_TIMESTAMP;
import static org.briarproject.api.blogs.BlogConstants.KEY_TIME_RECEIVED;
import static org.briarproject.api.blogs.BlogConstants.KEY_TITLE; import static org.briarproject.api.blogs.BlogConstants.KEY_TITLE;
import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_POST_BODY_LENGTH; import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_POST_BODY_LENGTH;
import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_POST_TEASER_LENGTH;
import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_POST_TITLE_LENGTH; import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_POST_TITLE_LENGTH;
import static org.briarproject.api.blogs.BlogConstants.MAX_CONTENT_TYPE_LENGTH; import static org.briarproject.api.blogs.BlogConstants.MAX_CONTENT_TYPE_LENGTH;
import static org.briarproject.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; import static org.briarproject.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH;
@@ -60,37 +63,36 @@ class BlogPostValidator extends BdfMessageValidator {
checkSize(body, 2); checkSize(body, 2);
BdfList content = body.getList(0); BdfList content = body.getList(0);
// Content: Parent ID, content type, title (optional), teaser, // Content: Parent ID, content type, title (optional), post body,
// post body (optional), attachments (optional) // attachments (optional)
checkSize(body, 6); checkSize(content, 5);
// Parent ID is optional // Parent ID is optional
byte[] parent = content.getOptionalRaw(0); byte[] parent = content.getOptionalRaw(0);
checkLength(parent, UniqueId.LENGTH); checkLength(parent, UniqueId.LENGTH);
// Content type // Content type
String contentType = content.getString(1); String contentType = content.getString(1);
checkLength(contentType, 0, MAX_CONTENT_TYPE_LENGTH); checkLength(contentType, 0, MAX_CONTENT_TYPE_LENGTH);
if (!contentType.equals("text/plain"))
throw new InvalidMessageException("Invalid content type");
// Blog post title is optional // Blog post title is optional
String title = content.getOptionalString(2); String title = content.getOptionalString(2);
checkLength(contentType, 0, MAX_BLOG_POST_TITLE_LENGTH); checkLength(contentType, 0, MAX_BLOG_POST_TITLE_LENGTH);
// Blog teaser // Blog post body
String teaser = content.getString(3); byte[] postBody = content.getRaw(3);
// TODO make sure that there is only text in the teaser
checkLength(contentType, 0, MAX_BLOG_POST_TEASER_LENGTH);
// Blog post body is optional
byte[] postBody = content.getOptionalRaw(4);
checkLength(postBody, 0, MAX_BLOG_POST_BODY_LENGTH); checkLength(postBody, 0, MAX_BLOG_POST_BODY_LENGTH);
// Attachments // Attachments
BdfDictionary attachments = content.getOptionalDictionary(5); BdfDictionary attachments = content.getOptionalDictionary(4);
// TODO handle attachments somehow // TODO handle attachments somehow
// Signature // Signature
byte[] sig = body.getRaw(1); byte[] sig = body.getRaw(1);
checkLength(sig, 0, MAX_SIGNATURE_LENGTH); checkLength(sig, 0, MAX_SIGNATURE_LENGTH);
// Verify the signature // Verify the signature
Author a;
try { try {
// Get the blog author // Get the blog author
Blog b = blogFactory.parseBlog(g, ""); // description doesn't matter Blog b = blogFactory.parseBlog(g, ""); // description doesn't matter
Author a = b.getAuthor(); a = b.getAuthor();
// Parse the public key // Parse the public key
KeyParser keyParser = crypto.getSignatureKeyParser(); KeyParser keyParser = crypto.getSignatureKeyParser();
PublicKey key = keyParser.parsePublicKey(a.getPublicKey()); PublicKey key = keyParser.parsePublicKey(a.getPublicKey());
@@ -111,9 +113,14 @@ class BlogPostValidator extends BdfMessageValidator {
BdfDictionary meta = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();
Collection<MessageId> dependencies = null; Collection<MessageId> dependencies = null;
if (title != null) meta.put(KEY_TITLE, title); if (title != null) meta.put(KEY_TITLE, title);
meta.put(KEY_TEASER, teaser); BdfDictionary author = BdfDictionary.of(
meta.put(KEY_HAS_BODY, postBody != null); new BdfEntry(KEY_AUTHOR_ID, a.getId()),
new BdfEntry(KEY_AUTHOR_NAME, a.getName()),
new BdfEntry(KEY_PUBLIC_KEY, a.getPublicKey())
);
meta.put(KEY_AUTHOR, author);
meta.put(KEY_TIMESTAMP, m.getTimestamp()); meta.put(KEY_TIMESTAMP, m.getTimestamp());
meta.put(KEY_TIME_RECEIVED, clock.currentTimeMillis());
if (parent != null) { if (parent != null) {
meta.put(KEY_PARENT, parent); meta.put(KEY_PARENT, parent);
dependencies = Collections.singletonList(new MessageId(parent)); dependencies = Collections.singletonList(new MessageId(parent));

View File

@@ -4,11 +4,12 @@ import org.briarproject.api.blogs.BlogFactory;
import org.briarproject.api.blogs.BlogManager; import org.briarproject.api.blogs.BlogManager;
import org.briarproject.api.blogs.BlogPostFactory; import org.briarproject.api.blogs.BlogPostFactory;
import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.data.MetadataEncoder; import org.briarproject.api.data.MetadataEncoder;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.identity.AuthorFactory; import org.briarproject.api.identity.AuthorFactory;
import org.briarproject.api.identity.IdentityManager; import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.sync.GroupFactory; import org.briarproject.api.sync.GroupFactory;
import org.briarproject.api.sync.ValidationManager; import org.briarproject.api.sync.ValidationManager;
import org.briarproject.api.system.Clock; import org.briarproject.api.system.Clock;
@@ -19,17 +20,31 @@ import javax.inject.Singleton;
import dagger.Module; import dagger.Module;
import dagger.Provides; import dagger.Provides;
import static org.briarproject.blogs.BlogManagerImpl.CLIENT_ID;
@Module @Module
public class BlogsModule { public class BlogsModule {
public static class EagerSingletons { public static class EagerSingletons {
@Inject @Inject
BlogPostValidator blogPostValidator; BlogPostValidator blogPostValidator;
@Inject
BlogManager blogManager;
} }
@Provides @Provides
@Singleton @Singleton
BlogManager provideBlogManager(BlogManagerImpl blogManager) { BlogManager provideBlogManager(BlogManagerImpl blogManager,
LifecycleManager lifecycleManager, ContactManager contactManager,
IdentityManager identityManager,
ValidationManager validationManager) {
lifecycleManager.registerClient(blogManager);
contactManager.registerAddContactHook(blogManager);
contactManager.registerRemoveContactHook(blogManager);
identityManager.registerAddIdentityHook(blogManager);
identityManager.registerRemoveIdentityHook(blogManager);
validationManager.registerIncomingMessageHook(CLIENT_ID, blogManager);
return blogManager; return blogManager;
} }
@@ -54,8 +69,7 @@ public class BlogsModule {
BlogPostValidator validator = new BlogPostValidator(crypto, BlogPostValidator validator = new BlogPostValidator(crypto,
blogFactory, clientHelper, metadataEncoder, clock); blogFactory, clientHelper, metadataEncoder, clock);
validationManager.registerMessageValidator( validationManager.registerMessageValidator(CLIENT_ID, validator);
BlogManagerImpl.CLIENT_ID, validator);
return validator; return validator;
} }

View File

@@ -99,17 +99,24 @@ class IdentityManagerImpl implements IdentityManager {
public Status getAuthorStatus(AuthorId authorId) throws DbException { public Status getAuthorStatus(AuthorId authorId) throws DbException {
Transaction txn = db.startTransaction(false); Transaction txn = db.startTransaction(false);
try { try {
// Compare to the IDs of the user's identities return getAuthorStatus(txn, authorId);
for (LocalAuthor a : db.getLocalAuthors(txn))
if (a.getId().equals(authorId)) return VERIFIED;
// Compare to the IDs of contacts' identities
for (Contact c : db.getContacts(txn))
if (c.getAuthor().getId().equals(authorId)) return VERIFIED;
// TODO also handle UNVERIFIED when #261 is implemented
return UNKNOWN;
} finally { } finally {
db.endTransaction(txn); db.endTransaction(txn);
} }
} }
@Override
public Status getAuthorStatus(Transaction txn, AuthorId authorId)
throws DbException {
// Compare to the IDs of the user's identities
for (LocalAuthor a : db.getLocalAuthors(txn))
if (a.getId().equals(authorId)) return VERIFIED;
// Compare to the IDs of contacts' identities
for (Contact c : db.getContacts(txn))
if (c.getAuthor().getId().equals(authorId)) return VERIFIED;
// TODO also handle UNVERIFIED when #261 is implemented
return UNKNOWN;
}
} }

View File

@@ -5,6 +5,7 @@ import org.briarproject.api.blogs.Blog;
import org.briarproject.api.blogs.BlogFactory; import org.briarproject.api.blogs.BlogFactory;
import org.briarproject.api.blogs.BlogInvitationMessage; import org.briarproject.api.blogs.BlogInvitationMessage;
import org.briarproject.api.blogs.BlogManager; import org.briarproject.api.blogs.BlogManager;
import org.briarproject.api.blogs.BlogManager.RemoveBlogHook;
import org.briarproject.api.blogs.BlogSharingManager; import org.briarproject.api.blogs.BlogSharingManager;
import org.briarproject.api.blogs.BlogSharingMessage.BlogInvitation; import org.briarproject.api.blogs.BlogSharingMessage.BlogInvitation;
import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.clients.ClientHelper;
@@ -40,7 +41,7 @@ import static org.briarproject.api.blogs.BlogConstants.BLOG_TITLE;
class BlogSharingManagerImpl extends class BlogSharingManagerImpl extends
SharingManagerImpl<Blog, BlogInvitation, BlogInvitationMessage, BlogInviteeSessionState, BlogSharerSessionState, BlogInvitationReceivedEvent, BlogInvitationResponseReceivedEvent> SharingManagerImpl<Blog, BlogInvitation, BlogInvitationMessage, BlogInviteeSessionState, BlogSharerSessionState, BlogInvitationReceivedEvent, BlogInvitationResponseReceivedEvent>
implements BlogSharingManager { implements BlogSharingManager, RemoveBlogHook {
static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString( static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString(
"bee438b5de0b3a685badc4e49d76e72d" "bee438b5de0b3a685badc4e49d76e72d"
@@ -124,6 +125,11 @@ class BlogSharingManagerImpl extends
return irrFactory; return irrFactory;
} }
@Override
public void removingBlog(Transaction txn, Blog b) throws DbException {
removingShareable(txn, b);
}
static class SFactory implements static class SFactory implements
ShareableFactory<Blog, BlogInvitation, BlogInviteeSessionState, BlogSharerSessionState> { ShareableFactory<Blog, BlogInvitation, BlogInviteeSessionState, BlogSharerSessionState> {

View File

@@ -792,6 +792,8 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IM
} else if (task == TASK_REMOVE_SHAREABLE_FROM_LIST_SHARED_WITH_US) { } else if (task == TASK_REMOVE_SHAREABLE_FROM_LIST_SHARED_WITH_US) {
removeFromList(txn, groupId, SHARED_WITH_US, f); removeFromList(txn, groupId, SHARED_WITH_US, f);
} else if (task == TASK_ADD_SHARED_SHAREABLE) { } else if (task == TASK_ADD_SHARED_SHAREABLE) {
// TODO we might want to call the add() method of the respective
// manager here, because blogs add a description for example
db.addGroup(txn, f.getGroup()); db.addGroup(txn, f.getGroup());
db.setVisibleToContact(txn, contactId, f.getId(), true); db.setVisibleToContact(txn, contactId, f.getId(), true);
} else if (task == TASK_ADD_SHAREABLE_TO_LIST_TO_BE_SHARED_BY_US) { } else if (task == TASK_ADD_SHAREABLE_TO_LIST_TO_BE_SHARED_BY_US) {

View File

@@ -1,5 +1,6 @@
package org.briarproject.sharing; package org.briarproject.sharing;
import org.briarproject.api.blogs.BlogManager;
import org.briarproject.api.blogs.BlogSharingManager; import org.briarproject.api.blogs.BlogSharingManager;
import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.clients.MessageQueueManager; import org.briarproject.api.clients.MessageQueueManager;
@@ -49,6 +50,7 @@ public class SharingModule {
LifecycleManager lifecycleManager, LifecycleManager lifecycleManager,
ContactManager contactManager, ContactManager contactManager,
MessageQueueManager messageQueueManager, MessageQueueManager messageQueueManager,
BlogManager blogManager,
BlogSharingManagerImpl blogSharingManager) { BlogSharingManagerImpl blogSharingManager) {
lifecycleManager.registerClient(blogSharingManager); lifecycleManager.registerClient(blogSharingManager);
@@ -56,6 +58,7 @@ public class SharingModule {
contactManager.registerRemoveContactHook(blogSharingManager); contactManager.registerRemoveContactHook(blogSharingManager);
messageQueueManager.registerIncomingMessageHook( messageQueueManager.registerIncomingMessageHook(
BlogSharingManagerImpl.CLIENT_ID, blogSharingManager); BlogSharingManagerImpl.CLIENT_ID, blogSharingManager);
blogManager.registerRemoveBlogHook(blogSharingManager);
return blogSharingManager; return blogSharingManager;
} }