From 30fe9f6e2ae712e07de2a813320efd6a41f1a2dd Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Mon, 20 Jun 2016 16:00:05 -0300 Subject: [PATCH 1/3] Change Blog Paradigm to Short-Form Removes teaser and makes body mandatory. It also adds support for deleting blogs and introduces a getAuthorStatus() method to the IdentityManager that takes a running transaction. --- .../briarproject/api/blogs/BlogConstants.java | 5 - .../briarproject/api/blogs/BlogManager.java | 11 +- .../org/briarproject/api/blogs/BlogPost.java | 24 +--- .../api/blogs/BlogPostFactory.java | 4 +- .../api/blogs/BlogPostHeader.java | 17 +-- .../api/event/BlogPostAddedEvent.java | 32 +++++ .../api/identity/IdentityManager.java | 3 + .../briarproject/blogs/BlogManagerImpl.java | 133 +++++++++++++----- .../blogs/BlogPostFactoryImpl.java | 15 +- .../briarproject/blogs/BlogPostValidator.java | 37 ++--- .../identity/IdentityManagerImpl.java | 25 ++-- .../sharing/BlogSharingManagerImpl.java | 8 +- .../briarproject/sharing/SharingModule.java | 3 + 13 files changed, 203 insertions(+), 114 deletions(-) create mode 100644 briar-api/src/org/briarproject/api/event/BlogPostAddedEvent.java diff --git a/briar-api/src/org/briarproject/api/blogs/BlogConstants.java b/briar-api/src/org/briarproject/api/blogs/BlogConstants.java index 738e012a3..5e483ffc6 100644 --- a/briar-api/src/org/briarproject/api/blogs/BlogConstants.java +++ b/briar-api/src/org/briarproject/api/blogs/BlogConstants.java @@ -16,9 +16,6 @@ public interface BlogConstants { /** The length of a blog post's title in UTF-8 bytes. */ 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. */ int MAX_BLOG_POST_BODY_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024; @@ -31,8 +28,6 @@ public interface BlogConstants { // Metadata keys String KEY_DESCRIPTION = "description"; String KEY_TITLE = "title"; - String KEY_TEASER = "teaser"; - String KEY_HAS_BODY = "hasBody"; String KEY_TIMESTAMP = "timestamp"; String KEY_PARENT = "parent"; String KEY_AUTHOR_ID = "id"; diff --git a/briar-api/src/org/briarproject/api/blogs/BlogManager.java b/briar-api/src/org/briarproject/api/blogs/BlogManager.java index e01fa5efb..0effcfee4 100644 --- a/briar-api/src/org/briarproject/api/blogs/BlogManager.java +++ b/briar-api/src/org/briarproject/api/blogs/BlogManager.java @@ -1,6 +1,5 @@ package org.briarproject.api.blogs; -import org.briarproject.api.FormatException; import org.briarproject.api.db.DbException; import org.briarproject.api.db.Transaction; import org.briarproject.api.identity.LocalAuthor; @@ -20,6 +19,9 @@ public interface BlogManager { Blog addBlog(LocalAuthor localAuthor, String name, String description) throws DbException; + /** Removes and deletes a blog. */ + void removeBlog(Blog b) throws DbException; + /** Stores a local blog post. */ void addLocalPost(BlogPost p) throws DbException; @@ -45,4 +47,11 @@ public interface BlogManager { /** Marks a blog post as read or unread. */ 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; + } + } diff --git a/briar-api/src/org/briarproject/api/blogs/BlogPost.java b/briar-api/src/org/briarproject/api/blogs/BlogPost.java index a6aa1167a..3854c0472 100644 --- a/briar-api/src/org/briarproject/api/blogs/BlogPost.java +++ b/briar-api/src/org/briarproject/api/blogs/BlogPost.java @@ -1,43 +1,27 @@ 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.identity.Author; import org.briarproject.api.sync.Message; import org.briarproject.api.sync.MessageId; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class BlogPost extends ForumPost { @Nullable private final String title; - @NotNull - private final String teaser; - private final boolean hasBody; - public BlogPost(@Nullable String title, @NotNull String teaser, - boolean hasBody, @NotNull Message message, - @Nullable MessageId parent, @NotNull Author author, + public BlogPost(@Nullable String title, @NotNull Message message, + @Nullable MessageId parent, @NotNull Author author, @NotNull String contentType) { super(message, parent, author, contentType); this.title = title; - this.teaser = teaser; - this.hasBody = hasBody; } @Nullable public String getTitle() { return title; } - - @NotNull - public String getTeaser() { - return teaser; - } - - public boolean hasBody() { - return hasBody; - } } diff --git a/briar-api/src/org/briarproject/api/blogs/BlogPostFactory.java b/briar-api/src/org/briarproject/api/blogs/BlogPostFactory.java index 2565bfb0e..6ced9ba20 100644 --- a/briar-api/src/org/briarproject/api/blogs/BlogPostFactory.java +++ b/briar-api/src/org/briarproject/api/blogs/BlogPostFactory.java @@ -12,8 +12,8 @@ import java.security.GeneralSecurityException; public interface BlogPostFactory { 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, - @Nullable byte[] body) + @NotNull byte[] body) throws FormatException, GeneralSecurityException; } diff --git a/briar-api/src/org/briarproject/api/blogs/BlogPostHeader.java b/briar-api/src/org/briarproject/api/blogs/BlogPostHeader.java index 24d421c13..b3a740bcb 100644 --- a/briar-api/src/org/briarproject/api/blogs/BlogPostHeader.java +++ b/briar-api/src/org/briarproject/api/blogs/BlogPostHeader.java @@ -11,33 +11,18 @@ public class BlogPostHeader extends PostHeader { @Nullable private final String title; - @NotNull - private final String teaser; - private final boolean hasBody; - public BlogPostHeader(@Nullable String title, @NotNull String teaser, - boolean hasBody, @NotNull MessageId id, + public BlogPostHeader(@Nullable String title, @NotNull MessageId id, @Nullable MessageId parentId, long timestamp, @NotNull Author author, @NotNull Status authorStatus, @NotNull String contentType, boolean read) { super(id, parentId, timestamp, author, authorStatus, contentType, read); this.title = title; - this.teaser = teaser; - this.hasBody = hasBody; } @Nullable public String getTitle() { return title; } - - @NotNull - public String getTeaser() { - return teaser; - } - - public boolean hasBody() { - return hasBody; - } } diff --git a/briar-api/src/org/briarproject/api/event/BlogPostAddedEvent.java b/briar-api/src/org/briarproject/api/event/BlogPostAddedEvent.java new file mode 100644 index 000000000..c00e4efbf --- /dev/null +++ b/briar-api/src/org/briarproject/api/event/BlogPostAddedEvent.java @@ -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; + } +} diff --git a/briar-api/src/org/briarproject/api/identity/IdentityManager.java b/briar-api/src/org/briarproject/api/identity/IdentityManager.java index e5420a043..e89f49d8a 100644 --- a/briar-api/src/org/briarproject/api/identity/IdentityManager.java +++ b/briar-api/src/org/briarproject/api/identity/IdentityManager.java @@ -29,6 +29,9 @@ public interface IdentityManager { /** Returns the trust-level status of the author */ Status getAuthorStatus(AuthorId a) throws DbException; + /** Returns the trust-level status of the author */ + Status getAuthorStatus(Transaction txn, AuthorId a) throws DbException; + interface AddIdentityHook { void addingIdentity(Transaction txn, LocalAuthor a) throws DbException; } diff --git a/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java b/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java index eabfc251e..70abde036 100644 --- a/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java +++ b/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java @@ -10,9 +10,11 @@ import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.data.BdfEntry; import org.briarproject.api.data.BdfList; +import org.briarproject.api.data.MetadataParser; import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DbException; import org.briarproject.api.db.Transaction; +import org.briarproject.api.event.BlogPostAddedEvent; import org.briarproject.api.identity.Author; import org.briarproject.api.identity.Author.Status; import org.briarproject.api.identity.AuthorId; @@ -21,7 +23,9 @@ import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.Group; import org.briarproject.api.sync.GroupId; +import org.briarproject.api.sync.Message; import org.briarproject.api.sync.MessageId; +import org.briarproject.clients.BdfIncomingMessageHook; import org.briarproject.util.StringUtils; import org.jetbrains.annotations.Nullable; @@ -31,24 +35,24 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.logging.Logger; 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_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_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_PUBLIC_KEY; 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_TITLE; -class BlogManagerImpl implements BlogManager { +class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager { private static final Logger LOG = Logger.getLogger(BlogManagerImpl.class.getName()); @@ -59,17 +63,19 @@ class BlogManagerImpl implements BlogManager { private final DatabaseComponent db; private final IdentityManager identityManager; - private final ClientHelper clientHelper; private final BlogFactory blogFactory; + private final List removeHooks; @Inject BlogManagerImpl(DatabaseComponent db, IdentityManager identityManager, - ClientHelper clientHelper, BlogFactory blogFactory) { + ClientHelper clientHelper, MetadataParser metadataParser, + BlogFactory blogFactory) { + super(clientHelper, metadataParser); this.db = db; this.identityManager = identityManager; - this.clientHelper = clientHelper; this.blogFactory = blogFactory; + removeHooks = new CopyOnWriteArrayList(); } @Override @@ -77,6 +83,17 @@ class BlogManagerImpl implements BlogManager { return CLIENT_ID; } + @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 public Blog addBlog(LocalAuthor localAuthor, String name, String description) throws DbException { @@ -101,13 +118,25 @@ class BlogManagerImpl implements BlogManager { } @Override - public void addLocalPost(BlogPost p) throws DbException { + public void removeBlog(Blog b) throws DbException { + Transaction txn = db.startTransaction(false); 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()); - meta.put(KEY_TEASER, p.getTeaser()); meta.put(KEY_TIMESTAMP, p.getMessage().getTimestamp()); - meta.put(KEY_HAS_BODY, p.hasBody()); if (p.getParent() != null) meta.put(KEY_PARENT, p.getParent()); Author a = p.getAuthor(); @@ -123,6 +152,22 @@ class BlogManagerImpl implements BlogManager { } catch (FormatException 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 @@ -189,16 +234,20 @@ class BlogManagerImpl implements BlogManager { @Nullable public byte[] getPostBody(MessageId m) throws DbException { try { - // content, signature - // content: parent, contentType, title, teaser, body, attachments BdfList message = clientHelper.getMessageAsList(m); - BdfList content = message.getList(0); - return content.getRaw(4); + return getPostBody(message); } catch (FormatException 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 public Collection getPostHeaders(GroupId g) throws DbException { @@ -213,26 +262,9 @@ class BlogManagerImpl implements BlogManager { for (Entry entry : metadata.entrySet()) { try { BdfDictionary meta = entry.getValue(); - String title = meta.getOptionalString(KEY_TITLE); - String teaser = meta.getString(KEY_TEASER); - boolean hasBody = meta.getBoolean(KEY_HAS_BODY); - 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)); + BlogPostHeader h = + getPostHeaderFromMetadata(null, entry.getKey(), meta); + headers.add(h); } catch (FormatException e) { throw new DbException(e); } @@ -251,10 +283,43 @@ class BlogManagerImpl implements BlogManager { } } + @Override + public void registerRemoveBlogHook(RemoveBlogHook hook) { + removeHooks.add(hook); + } + private String getBlogDescription(Transaction txn, GroupId g) throws DbException, FormatException { BdfDictionary d = clientHelper.getGroupMetadataAsDictionary(txn, g); 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); + 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, author, + authorStatus, contentType, read); + } + } diff --git a/briar-core/src/org/briarproject/blogs/BlogPostFactoryImpl.java b/briar-core/src/org/briarproject/blogs/BlogPostFactoryImpl.java index e9ced2d3f..ce134d33c 100644 --- a/briar-core/src/org/briarproject/blogs/BlogPostFactoryImpl.java +++ b/briar-core/src/org/briarproject/blogs/BlogPostFactoryImpl.java @@ -22,7 +22,6 @@ import java.security.GeneralSecurityException; 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_TEASER_LENGTH; import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_POST_TITLE_LENGTH; import static org.briarproject.api.blogs.BlogConstants.MAX_CONTENT_TYPE_LENGTH; @@ -39,25 +38,22 @@ class BlogPostFactoryImpl implements BlogPostFactory { @Override 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, - @NotNull String contentType, @Nullable byte[] body) + @NotNull String contentType, @NotNull byte[] body) throws FormatException, GeneralSecurityException { // Validate the arguments if (title != null && StringUtils.toUtf8(title).length > MAX_BLOG_POST_TITLE_LENGTH) 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) throw new IllegalArgumentException(); - if (body != null && body.length > MAX_BLOG_POST_BODY_LENGTH) + if (body.length > MAX_BLOG_POST_BODY_LENGTH) throw new IllegalArgumentException(); // Serialise the data to be signed - BdfList content = - BdfList.of(parent, contentType, title, teaser, body, null); + BdfList content = BdfList.of(parent, contentType, title, body, null); BdfList signed = BdfList.of(groupId, timestamp, content); // Generate the signature @@ -72,7 +68,6 @@ class BlogPostFactoryImpl implements BlogPostFactory { // Serialise the signed message BdfList message = BdfList.of(content, sig); Message m = clientHelper.createMessage(groupId, timestamp, message); - return new BlogPost(title, teaser, body != null, m, parent, author, - contentType); + return new BlogPost(title, m, parent, author, contentType); } } diff --git a/briar-core/src/org/briarproject/blogs/BlogPostValidator.java b/briar-core/src/org/briarproject/blogs/BlogPostValidator.java index bacf02dff..1ff0e2d46 100644 --- a/briar-core/src/org/briarproject/blogs/BlogPostValidator.java +++ b/briar-core/src/org/briarproject/blogs/BlogPostValidator.java @@ -11,6 +11,7 @@ import org.briarproject.api.crypto.KeyParser; import org.briarproject.api.crypto.PublicKey; import org.briarproject.api.crypto.Signature; import org.briarproject.api.data.BdfDictionary; +import org.briarproject.api.data.BdfEntry; import org.briarproject.api.data.BdfList; import org.briarproject.api.data.MetadataEncoder; import org.briarproject.api.identity.Author; @@ -25,15 +26,16 @@ import java.security.GeneralSecurityException; import java.util.Collection; 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_HAS_BODY; 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_TEASER; import static org.briarproject.api.blogs.BlogConstants.KEY_TIMESTAMP; 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_TEASER_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.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; @@ -60,37 +62,36 @@ class BlogPostValidator extends BdfMessageValidator { checkSize(body, 2); BdfList content = body.getList(0); - // Content: Parent ID, content type, title (optional), teaser, - // post body (optional), attachments (optional) - checkSize(body, 6); + // Content: Parent ID, content type, title (optional), post body, + // attachments (optional) + checkSize(content, 5); // Parent ID is optional byte[] parent = content.getOptionalRaw(0); checkLength(parent, UniqueId.LENGTH); // Content type String contentType = content.getString(1); checkLength(contentType, 0, MAX_CONTENT_TYPE_LENGTH); + if (!contentType.equals("text/plain")) + throw new InvalidMessageException("Invalid content type"); // Blog post title is optional String title = content.getOptionalString(2); checkLength(contentType, 0, MAX_BLOG_POST_TITLE_LENGTH); - // Blog teaser - String teaser = content.getString(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); + // Blog post body + byte[] postBody = content.getRaw(3); checkLength(postBody, 0, MAX_BLOG_POST_BODY_LENGTH); // Attachments - BdfDictionary attachments = content.getOptionalDictionary(5); + BdfDictionary attachments = content.getOptionalDictionary(4); // TODO handle attachments somehow // Signature byte[] sig = body.getRaw(1); checkLength(sig, 0, MAX_SIGNATURE_LENGTH); // Verify the signature + Author a; try { // Get the blog author Blog b = blogFactory.parseBlog(g, ""); // description doesn't matter - Author a = b.getAuthor(); + a = b.getAuthor(); // Parse the public key KeyParser keyParser = crypto.getSignatureKeyParser(); PublicKey key = keyParser.parsePublicKey(a.getPublicKey()); @@ -111,8 +112,12 @@ class BlogPostValidator extends BdfMessageValidator { BdfDictionary meta = new BdfDictionary(); Collection dependencies = null; if (title != null) meta.put(KEY_TITLE, title); - meta.put(KEY_TEASER, teaser); - meta.put(KEY_HAS_BODY, postBody != null); + BdfDictionary author = BdfDictionary.of( + 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()); if (parent != null) { meta.put(KEY_PARENT, parent); diff --git a/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java b/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java index e04e20602..5b1434ad1 100644 --- a/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java +++ b/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java @@ -99,17 +99,24 @@ class IdentityManagerImpl implements IdentityManager { public Status getAuthorStatus(AuthorId authorId) throws DbException { Transaction txn = db.startTransaction(false); try { - // 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; + return getAuthorStatus(txn, authorId); } finally { 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; + } + } diff --git a/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java b/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java index ba67ff635..a25520fac 100644 --- a/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java +++ b/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java @@ -5,6 +5,7 @@ import org.briarproject.api.blogs.Blog; import org.briarproject.api.blogs.BlogFactory; import org.briarproject.api.blogs.BlogInvitationMessage; import org.briarproject.api.blogs.BlogManager; +import org.briarproject.api.blogs.BlogManager.RemoveBlogHook; import org.briarproject.api.blogs.BlogSharingManager; import org.briarproject.api.blogs.BlogSharingMessage.BlogInvitation; import org.briarproject.api.clients.ClientHelper; @@ -40,7 +41,7 @@ import static org.briarproject.api.blogs.BlogConstants.BLOG_TITLE; class BlogSharingManagerImpl extends SharingManagerImpl - implements BlogSharingManager { + implements BlogSharingManager, RemoveBlogHook { static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString( "bee438b5de0b3a685badc4e49d76e72d" @@ -124,6 +125,11 @@ class BlogSharingManagerImpl extends return irrFactory; } + @Override + public void removingBlog(Transaction txn, Blog b) throws DbException { + removingShareable(txn, b); + } + static class SFactory implements ShareableFactory { diff --git a/briar-core/src/org/briarproject/sharing/SharingModule.java b/briar-core/src/org/briarproject/sharing/SharingModule.java index d62c7dccf..3af07e129 100644 --- a/briar-core/src/org/briarproject/sharing/SharingModule.java +++ b/briar-core/src/org/briarproject/sharing/SharingModule.java @@ -1,5 +1,6 @@ package org.briarproject.sharing; +import org.briarproject.api.blogs.BlogManager; import org.briarproject.api.blogs.BlogSharingManager; import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.clients.MessageQueueManager; @@ -49,6 +50,7 @@ public class SharingModule { LifecycleManager lifecycleManager, ContactManager contactManager, MessageQueueManager messageQueueManager, + BlogManager blogManager, BlogSharingManagerImpl blogSharingManager) { lifecycleManager.registerClient(blogSharingManager); @@ -56,6 +58,7 @@ public class SharingModule { contactManager.registerRemoveContactHook(blogSharingManager); messageQueueManager.registerIncomingMessageHook( BlogSharingManagerImpl.CLIENT_ID, blogSharingManager); + blogManager.registerRemoveBlogHook(blogSharingManager); return blogSharingManager; } From a8f51fcb8a0dcee32de5459c68a4f634d71b9df8 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 21 Jun 2016 17:00:13 -0300 Subject: [PATCH 2/3] Backend for Automatic Personal Blogs 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. Part of #436 --- .../src/org/briarproject/api/blogs/Blog.java | 9 ++- .../briarproject/api/blogs/BlogConstants.java | 3 + .../briarproject/api/blogs/BlogFactory.java | 4 + .../briarproject/api/blogs/BlogManager.java | 6 +- .../briarproject/blogs/BlogFactoryImpl.java | 19 ++++- .../briarproject/blogs/BlogManagerImpl.java | 81 ++++++++++++++++++- .../org/briarproject/blogs/BlogsModule.java | 22 ++++- .../sharing/SharingManagerImpl.java | 2 + 8 files changed, 135 insertions(+), 11 deletions(-) diff --git a/briar-api/src/org/briarproject/api/blogs/Blog.java b/briar-api/src/org/briarproject/api/blogs/Blog.java index c97e42be2..4e6827891 100644 --- a/briar-api/src/org/briarproject/api/blogs/Blog.java +++ b/briar-api/src/org/briarproject/api/blogs/Blog.java @@ -11,13 +11,16 @@ 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) { + @NotNull String description, @NotNull Author author, + boolean permanent) { super(group, name, null); this.description = description; this.author = author; + this.permanent = permanent; } @NotNull @@ -29,4 +32,8 @@ 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/BlogConstants.java b/briar-api/src/org/briarproject/api/blogs/BlogConstants.java index 5e483ffc6..3c8e8baf8 100644 --- a/briar-api/src/org/briarproject/api/blogs/BlogConstants.java +++ b/briar-api/src/org/briarproject/api/blogs/BlogConstants.java @@ -19,6 +19,9 @@ public interface BlogConstants { /** The maximum length of a blog post's body in bytes. */ 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 */ String BLOG_TITLE = "blogTitle"; String BLOG_DESC = "blogDescription"; diff --git a/briar-api/src/org/briarproject/api/blogs/BlogFactory.java b/briar-api/src/org/briarproject/api/blogs/BlogFactory.java index 8da9db192..190236bae 100644 --- a/briar-api/src/org/briarproject/api/blogs/BlogFactory.java +++ b/briar-api/src/org/briarproject/api/blogs/BlogFactory.java @@ -1,6 +1,7 @@ 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; @@ -11,6 +12,9 @@ public interface BlogFactory { Blog createBlog(@NotNull String name, @NotNull String description, @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 */ Blog parseBlog(@NotNull Group g, @NotNull String description) throws FormatException; diff --git a/briar-api/src/org/briarproject/api/blogs/BlogManager.java b/briar-api/src/org/briarproject/api/blogs/BlogManager.java index 0effcfee4..7d6188fed 100644 --- a/briar-api/src/org/briarproject/api/blogs/BlogManager.java +++ b/briar-api/src/org/briarproject/api/blogs/BlogManager.java @@ -2,6 +2,7 @@ package org.briarproject.api.blogs; import org.briarproject.api.db.DbException; import org.briarproject.api.db.Transaction; +import org.briarproject.api.identity.Author; import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.GroupId; @@ -31,9 +32,12 @@ public interface BlogManager { /** Returns the blog with the given ID. */ 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 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. */ Collection getBlogs() throws DbException; diff --git a/briar-core/src/org/briarproject/blogs/BlogFactoryImpl.java b/briar-core/src/org/briarproject/blogs/BlogFactoryImpl.java index b04401f5d..9a3e0583a 100644 --- a/briar-core/src/org/briarproject/blogs/BlogFactoryImpl.java +++ b/briar-core/src/org/briarproject/blogs/BlogFactoryImpl.java @@ -4,6 +4,7 @@ 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; @@ -13,6 +14,8 @@ import org.jetbrains.annotations.NotNull; import javax.inject.Inject; +import static org.briarproject.api.blogs.BlogConstants.PERSONAL_BLOG_NAME; + class BlogFactoryImpl implements BlogFactory { private final GroupFactory groupFactory; @@ -31,6 +34,16 @@ class BlogFactoryImpl implements BlogFactory { @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); + } + + private Blog createBlog(@NotNull String name, @NotNull String description, + @NotNull Author author, boolean permanent) { try { BdfList blog = BdfList.of( name, @@ -40,7 +53,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); + return new Blog(g, name, description, author, permanent); } catch (FormatException e) { throw new RuntimeException(e); } @@ -55,7 +68,9 @@ class BlogFactoryImpl implements BlogFactory { BdfList blog = clientHelper.toList(descriptor, 0, descriptor.length); Author a = 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); } } diff --git a/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java b/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java index 70abde036..45b3bbe84 100644 --- a/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java +++ b/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java @@ -6,7 +6,10 @@ import org.briarproject.api.blogs.BlogFactory; import org.briarproject.api.blogs.BlogManager; import org.briarproject.api.blogs.BlogPost; import org.briarproject.api.blogs.BlogPostHeader; +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.data.BdfDictionary; import org.briarproject.api.data.BdfEntry; import org.briarproject.api.data.BdfList; @@ -19,6 +22,8 @@ import org.briarproject.api.identity.Author; import org.briarproject.api.identity.Author.Status; import org.briarproject.api.identity.AuthorId; 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.sync.ClientId; import org.briarproject.api.sync.Group; @@ -51,8 +56,12 @@ 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_TIMESTAMP; 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 extends BdfIncomingMessageHook implements BlogManager { +class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, + AddContactHook, RemoveContactHook, Client, + AddIdentityHook, RemoveIdentityHook { private static final Logger LOG = Logger.getLogger(BlogManagerImpl.class.getName()); @@ -83,6 +92,68 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager { 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 { @@ -208,6 +279,11 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager { return Collections.unmodifiableList(blogs); } + @Override + public Blog getPersonalBlog(Author author) throws DbException { + return blogFactory.createPersonalBlog(author); + } + @Override public Collection getBlogs() throws DbException { try { @@ -291,7 +367,7 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager { private String getBlogDescription(Transaction txn, GroupId g) throws DbException, FormatException { BdfDictionary d = clientHelper.getGroupMetadataAsDictionary(txn, g); - return d.getString(KEY_DESCRIPTION); + return d.getString(KEY_DESCRIPTION, ""); } private BlogPostHeader getPostHeaderFromMetadata(@Nullable Transaction txn, @@ -321,5 +397,4 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager { return new BlogPostHeader(title, id, parentId, timestamp, author, authorStatus, contentType, read); } - } diff --git a/briar-core/src/org/briarproject/blogs/BlogsModule.java b/briar-core/src/org/briarproject/blogs/BlogsModule.java index 4cf7894d1..055328ad9 100644 --- a/briar-core/src/org/briarproject/blogs/BlogsModule.java +++ b/briar-core/src/org/briarproject/blogs/BlogsModule.java @@ -4,11 +4,12 @@ import org.briarproject.api.blogs.BlogFactory; import org.briarproject.api.blogs.BlogManager; import org.briarproject.api.blogs.BlogPostFactory; import org.briarproject.api.clients.ClientHelper; +import org.briarproject.api.contact.ContactManager; import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.data.MetadataEncoder; -import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.identity.AuthorFactory; import org.briarproject.api.identity.IdentityManager; +import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.sync.GroupFactory; import org.briarproject.api.sync.ValidationManager; import org.briarproject.api.system.Clock; @@ -19,17 +20,31 @@ import javax.inject.Singleton; import dagger.Module; import dagger.Provides; +import static org.briarproject.blogs.BlogManagerImpl.CLIENT_ID; + @Module public class BlogsModule { public static class EagerSingletons { @Inject BlogPostValidator blogPostValidator; + @Inject + BlogManager blogManager; } @Provides @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; } @@ -54,8 +69,7 @@ public class BlogsModule { BlogPostValidator validator = new BlogPostValidator(crypto, blogFactory, clientHelper, metadataEncoder, clock); - validationManager.registerMessageValidator( - BlogManagerImpl.CLIENT_ID, validator); + validationManager.registerMessageValidator(CLIENT_ID, validator); return validator; } diff --git a/briar-core/src/org/briarproject/sharing/SharingManagerImpl.java b/briar-core/src/org/briarproject/sharing/SharingManagerImpl.java index 0d55b4a3c..e4929fb79 100644 --- a/briar-core/src/org/briarproject/sharing/SharingManagerImpl.java +++ b/briar-core/src/org/briarproject/sharing/SharingManagerImpl.java @@ -792,6 +792,8 @@ abstract class SharingManagerImpl Date: Wed, 22 Jun 2016 12:27:58 -0300 Subject: [PATCH 3/3] Store and expose time a blog post was received This is useful when sorting blog posts in the combined feed. It ensures you do not miss older posts that were just synced to you. --- .../src/org/briarproject/api/blogs/BlogConstants.java | 1 + .../src/org/briarproject/api/blogs/BlogPostHeader.java | 9 ++++++++- .../src/org/briarproject/blogs/BlogManagerImpl.java | 6 ++++-- .../src/org/briarproject/blogs/BlogPostValidator.java | 2 ++ 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/briar-api/src/org/briarproject/api/blogs/BlogConstants.java b/briar-api/src/org/briarproject/api/blogs/BlogConstants.java index 3c8e8baf8..7bbaacdb8 100644 --- a/briar-api/src/org/briarproject/api/blogs/BlogConstants.java +++ b/briar-api/src/org/briarproject/api/blogs/BlogConstants.java @@ -32,6 +32,7 @@ public interface BlogConstants { String KEY_DESCRIPTION = "description"; String KEY_TITLE = "title"; String KEY_TIMESTAMP = "timestamp"; + String KEY_TIME_RECEIVED = "timeReceived"; String KEY_PARENT = "parent"; String KEY_AUTHOR_ID = "id"; String KEY_AUTHOR_NAME = "name"; diff --git a/briar-api/src/org/briarproject/api/blogs/BlogPostHeader.java b/briar-api/src/org/briarproject/api/blogs/BlogPostHeader.java index b3a740bcb..980ea27eb 100644 --- a/briar-api/src/org/briarproject/api/blogs/BlogPostHeader.java +++ b/briar-api/src/org/briarproject/api/blogs/BlogPostHeader.java @@ -11,18 +11,25 @@ public class BlogPostHeader extends PostHeader { @Nullable private final String title; + private final long timeReceived; public BlogPostHeader(@Nullable String title, @NotNull MessageId id, - @Nullable MessageId parentId, long timestamp, + @Nullable MessageId parentId, long timestamp, long timeReceived, @NotNull Author author, @NotNull Status authorStatus, @NotNull String contentType, boolean read) { super(id, parentId, timestamp, author, authorStatus, contentType, read); this.title = title; + this.timeReceived = timeReceived; } @Nullable public String getTitle() { return title; } + + public long getTimeReceived() { + return timeReceived; + } + } diff --git a/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java b/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java index 45b3bbe84..182ea1186 100644 --- a/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java +++ b/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java @@ -55,6 +55,7 @@ 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_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.contact.ContactManager.AddContactHook; import static org.briarproject.api.contact.ContactManager.RemoveContactHook; @@ -376,6 +377,7 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, 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)); @@ -394,7 +396,7 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, String contentType = meta.getString(KEY_CONTENT_TYPE); boolean read = meta.getBoolean(KEY_READ); - return new BlogPostHeader(title, id, parentId, timestamp, author, - authorStatus, contentType, read); + return new BlogPostHeader(title, id, parentId, timestamp, timeReceived, + author, authorStatus, contentType, read); } } diff --git a/briar-core/src/org/briarproject/blogs/BlogPostValidator.java b/briar-core/src/org/briarproject/blogs/BlogPostValidator.java index 1ff0e2d46..d412f10ae 100644 --- a/briar-core/src/org/briarproject/blogs/BlogPostValidator.java +++ b/briar-core/src/org/briarproject/blogs/BlogPostValidator.java @@ -34,6 +34,7 @@ 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_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.MAX_BLOG_POST_BODY_LENGTH; import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_POST_TITLE_LENGTH; @@ -119,6 +120,7 @@ class BlogPostValidator extends BdfMessageValidator { ); meta.put(KEY_AUTHOR, author); meta.put(KEY_TIMESTAMP, m.getTimestamp()); + meta.put(KEY_TIME_RECEIVED, clock.currentTimeMillis()); if (parent != null) { meta.put(KEY_PARENT, parent); dependencies = Collections.singletonList(new MessageId(parent));