diff --git a/src/retroshare/rsposted.h b/src/retroshare/rsposted.h index 9829d973b6..84ec19c103 100644 --- a/src/retroshare/rsposted.h +++ b/src/retroshare/rsposted.h @@ -29,9 +29,11 @@ #include "retroshare/rstokenservice.h" #include "retroshare/rsgxsifacehelper.h" -#include "retroshare/rsgxscommon.h" -#include "retroshare/rsgxscircles.h" -#include "serialiser/rsserializable.h" +#include "retroshare/rsgxscommon.h" +#include "retroshare/rsgxscircles.h" +#include "serialiser/rsserializable.h" +#include "serialiser/rstlvidset.h" +#include "serialiser/rstypeserializer.h" class RsPosted; @@ -41,25 +43,36 @@ class RsPosted; */ extern RsPosted* rsPosted; -struct RsPostedGroup: public RsSerializable, RsGxsGenericGroupData -{ - std::string mDescription; - RsGxsImage mGroupImage; - - /// @see RsSerializable - virtual void serial_process( RsGenericSerializer::SerializeJob j, - RsGenericSerializer::SerializeContext& ctx ) override - { - RS_SERIAL_PROCESS(mMeta); - RS_SERIAL_PROCESS(mDescription); - RS_SERIAL_PROCESS(mGroupImage); - } -}; - -struct RsPostedPost: public RsSerializable, RsGxsGenericMsgData -{ - RsPostedPost(): mHaveVoted(false), mUpVotes(0), mDownVotes(0), mComments(0), - mHotScore(0), mTopScore(0), mNewScore(0) {} +struct RsPostedGroup: public RsSerializable, RsGxsGenericGroupData +{ + std::string mDescription; + RsGxsImage mGroupImage; + RsTlvGxsMsgIdSet mPinnedPosts; + + /// @see RsSerializable + virtual void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) override + { + RS_SERIAL_PROCESS(mMeta); + RS_SERIAL_PROCESS(mDescription); + RS_SERIAL_PROCESS(mGroupImage); + + switch(j) + { + case RsGenericSerializer::TO_JSON: // fallthrough + case RsGenericSerializer::FROM_JSON: + RsTypeSerializer::serial_process(j, ctx, mPinnedPosts.ids, "mPinnedPosts"); + break; + default: + RS_SERIAL_PROCESS(mPinnedPosts); + } + } +}; + +struct RsPostedPost: public RsSerializable, RsGxsGenericMsgData +{ + RsPostedPost(): mHaveVoted(false), mUpVotes(0), mDownVotes(0), mComments(0), + mHotScore(0), mTopScore(0), mNewScore(0), mPinned(false) {} bool calculateScores(rstime_t ref_time); @@ -75,9 +88,10 @@ struct RsPostedPost: public RsSerializable, RsGxsGenericMsgData // and Calculated Scores:??? - double mHotScore; - double mTopScore; - double mNewScore; + double mHotScore; + double mTopScore; + double mNewScore; + bool mPinned; RsGxsImage mImage; @@ -92,12 +106,13 @@ struct RsPostedPost: public RsSerializable, RsGxsGenericMsgData RS_SERIAL_PROCESS(mHaveVoted); RS_SERIAL_PROCESS(mUpVotes); RS_SERIAL_PROCESS(mDownVotes); - RS_SERIAL_PROCESS(mComments); - RS_SERIAL_PROCESS(mHotScore); - RS_SERIAL_PROCESS(mTopScore); - RS_SERIAL_PROCESS(mNewScore); - } -}; + RS_SERIAL_PROCESS(mComments); + RS_SERIAL_PROCESS(mHotScore); + RS_SERIAL_PROCESS(mTopScore); + RS_SERIAL_PROCESS(mNewScore); + RS_SERIAL_PROCESS(mPinned); + } +}; //#define RSPOSTED_MSGTYPE_POST 0x0001 @@ -128,10 +143,11 @@ enum class RsPostedEventCode: uint8_t STATISTICS_CHANGED = 0x07, MESSAGE_VOTES_UPDATED = 0x08, SYNC_PARAMETERS_UPDATED = 0x09, - NEW_COMMENT = 0x0a, - NEW_VOTE = 0x0b, - BOARD_DELETED = 0x0c, -}; + NEW_COMMENT = 0x0a, + NEW_VOTE = 0x0b, + BOARD_DELETED = 0x0c, + PINNED_POSTS_CHANGED = 0x0d, +}; struct RsGxsPostedEvent: RsEvent @@ -238,7 +254,22 @@ class RsPosted : public RsGxsIfaceHelper, public RsGxsCommentService * @param[in] board Board data (name, description...) with modifications * @return false on error, true otherwise */ - virtual bool editBoard(RsPostedGroup& board) =0; + virtual bool editBoard(RsPostedGroup& board) =0; + + /** + * @brief Pin or unpin a board post. + * @jsonapi{development} + * @param[in] boardId id of the board containing the post + * @param[in] postId id of the post to pin or unpin + * @param[in] pinned true to pin, false to unpin + * @param[out] errorMessage possible error message if the method returns false + * @return false on error, true otherwise + */ + virtual bool setPostPinned( + const RsGxsGroupId& boardId, + const RsGxsMessageId& postId, + bool pinned, + std::string& errorMessage ) = 0; /** * @brief Create board. Blocking API. diff --git a/src/rsitems/rsposteditems.cc b/src/rsitems/rsposteditems.cc index 3c16ff5bd9..c7a8c804cc 100644 --- a/src/rsitems/rsposteditems.cc +++ b/src/rsitems/rsposteditems.cc @@ -42,18 +42,26 @@ void RsGxsPostedPostItem::serial_process(RsGenericSerializer::SerializeJob j,RsG RsTypeSerializer::serial_process(j,ctx,mImage,"mImage") ; } -void RsGxsPostedGroupItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) -{ - RsTypeSerializer::serial_process(j,ctx,TLV_TYPE_STR_DESCR ,mDescription,"mDescription") ; - - if(j == RsGenericSerializer::DESERIALIZE && ctx.mOffset == ctx.mSize) - return ; - - if((j == RsGenericSerializer::SIZE_ESTIMATE || j == RsGenericSerializer::SERIALIZE) && mGroupImage.empty()) - return ; - - RsTypeSerializer::serial_process(j,ctx,mGroupImage,"mGroupImage") ; -} +void RsGxsPostedGroupItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) +{ + RsTypeSerializer::serial_process(j,ctx,TLV_TYPE_STR_DESCR ,mDescription,"mDescription") ; + + if(j == RsGenericSerializer::DESERIALIZE && ctx.mOffset == ctx.mSize) + return ; + + if((j == RsGenericSerializer::SIZE_ESTIMATE || j == RsGenericSerializer::SERIALIZE) && mGroupImage.empty() && mPinnedPosts.ids.empty()) + return ; + + RsTypeSerializer::serial_process(j,ctx,mGroupImage,"mGroupImage") ; + + if(j == RsGenericSerializer::DESERIALIZE && ctx.mOffset == ctx.mSize) + return ; + + if((j == RsGenericSerializer::SIZE_ESTIMATE || j == RsGenericSerializer::SERIALIZE) && mPinnedPosts.ids.empty()) + return ; + + RsTypeSerializer::serial_process(j,ctx,mPinnedPosts,"mPinnedPosts") ; +} RsItem *RsGxsPostedSerialiser::create_item(uint16_t service_id,uint8_t item_subtype) const { @@ -115,20 +123,22 @@ void RsGxsPostedPostItem::clear() mPost.mNotes.clear(); mImage.TlvClear(); } -void RsGxsPostedGroupItem::clear() -{ - mDescription.clear(); - mGroupImage.TlvClear(); -} - -bool RsGxsPostedGroupItem::fromPostedGroup(RsPostedGroup &group, bool moveImage) -{ - clear(); - meta = group.mMeta; - mDescription = group.mDescription; - - if (moveImage) - { +void RsGxsPostedGroupItem::clear() +{ + mDescription.clear(); + mPinnedPosts.TlvClear(); + mGroupImage.TlvClear(); +} + +bool RsGxsPostedGroupItem::fromPostedGroup(RsPostedGroup &group, bool moveImage) +{ + clear(); + meta = group.mMeta; + mDescription = group.mDescription; + mPinnedPosts = group.mPinnedPosts; + + if (moveImage) + { mGroupImage.binData.bin_data = group.mGroupImage.mData; mGroupImage.binData.bin_len = group.mGroupImage.mSize; group.mGroupImage.shallowClear(); @@ -140,12 +150,14 @@ bool RsGxsPostedGroupItem::fromPostedGroup(RsPostedGroup &group, bool moveImage) return true; } -bool RsGxsPostedGroupItem::toPostedGroup(RsPostedGroup &group, bool moveImage) -{ - group.mMeta = meta; - group.mDescription = mDescription; - if (moveImage) - { +bool RsGxsPostedGroupItem::toPostedGroup(RsPostedGroup &group, bool moveImage) +{ + group.mMeta = meta; + group.mDescription = mDescription; + group.mPinnedPosts = mPinnedPosts; + + if (moveImage) + { group.mGroupImage.take((uint8_t *) mGroupImage.binData.bin_data, mGroupImage.binData.bin_len); // mGroupImage doesn't have a ShallowClear at the moment! mGroupImage.binData.TlvShallowClear(); diff --git a/src/rsitems/rsposteditems.h b/src/rsitems/rsposteditems.h index 910471c19f..8e26612a59 100644 --- a/src/rsitems/rsposteditems.h +++ b/src/rsitems/rsposteditems.h @@ -23,9 +23,10 @@ #define RSPOSTEDITEMS_H #include "rsitems/rsserviceids.h" -#include "rsitems/rsgxscommentitems.h" -#include "rsitems/rsgxsitems.h" -#include "serialiser/rstlvimage.h" +#include "rsitems/rsgxscommentitems.h" +#include "rsitems/rsgxsitems.h" +#include "serialiser/rstlvimage.h" +#include "serialiser/rstlvidset.h" #include "retroshare/rsposted.h" @@ -46,10 +47,11 @@ class RsGxsPostedGroupItem : public RsGxsGrpItem bool fromPostedGroup(RsPostedGroup &group, bool moveImage); bool toPostedGroup(RsPostedGroup &group, bool moveImage); - std::string mDescription; - RsTlvImage mGroupImage; - -}; + std::string mDescription; + RsTlvImage mGroupImage; + RsTlvGxsMsgIdSet mPinnedPosts; + +}; class RsGxsPostedPostItem : public RsGxsMsgItem { diff --git a/src/services/p3posted.cc b/src/services/p3posted.cc index 2bb4f08471..ac0a12735f 100644 --- a/src/services/p3posted.cc +++ b/src/services/p3posted.cc @@ -890,5 +890,41 @@ bool p3Posted::editBoard(RsPostedGroup& board) return true; } +bool p3Posted::setPostPinned( + const RsGxsGroupId& boardId, + const RsGxsMessageId& postId, + bool pinned, + std::string& errorMessage ) +{ + const auto failure = [&](const std::string& err) + { + errorMessage = err; + RsErr() << __PRETTY_FUNCTION__ << " " << err << std::endl; + return false; + }; + + std::vector groupsInfo; + if(!getBoardsInfo({ boardId }, groupsInfo) || groupsInfo.size() != 1) + return failure("Board with Id " + boardId.toStdString() + " does not exist."); + + std::vector posts; + std::vector comments; + std::vector votes; + + if(!getBoardContent(boardId, { postId }, posts, comments, votes) || posts.size() != 1) + return failure( + "Post with Id " + postId.toStdString() + " does not exist in board " + + boardId.toStdString() + "."); + + RsPostedGroup board = groupsInfo.front(); + + if(pinned) + board.mPinnedPosts.ids.insert(postId); + else + board.mPinnedPosts.ids.erase(postId); + + return editBoard(board); +} + RsPosted::~RsPosted() = default; RsGxsPostedEvent::~RsGxsPostedEvent() = default; diff --git a/src/services/p3posted.h b/src/services/p3posted.h index 4adc2cf299..abfc9a985d 100644 --- a/src/services/p3posted.h +++ b/src/services/p3posted.h @@ -77,6 +77,12 @@ virtual void receiveHelperChanges(std::vector& changes) bool editBoard(RsPostedGroup& board) override; + bool setPostPinned( + const RsGxsGroupId& boardId, + const RsGxsMessageId& postId, + bool pinned, + std::string& errorMessage ) override; + bool createBoard(RsPostedGroup& board) override; bool createBoardV2(const std::string& board_name,