From 44c1f1580f762d5d172526b703e7d63dfc611ef2 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 31 Mar 2019 22:11:09 +0200 Subject: [PATCH] added other clean API entries for channel: createComment(), createVote() and createPost() --- libretroshare/src/retroshare/rsgxschannels.h | 63 ++++-- libretroshare/src/services/p3gxschannels.cc | 200 ++++++++++++++++--- libretroshare/src/services/p3gxschannels.h | 33 +++ 3 files changed, 256 insertions(+), 40 deletions(-) diff --git a/libretroshare/src/retroshare/rsgxschannels.h b/libretroshare/src/retroshare/rsgxschannels.h index 8ed0dc285..9f76aec84 100644 --- a/libretroshare/src/retroshare/rsgxschannels.h +++ b/libretroshare/src/retroshare/rsgxschannels.h @@ -99,6 +99,7 @@ public: explicit RsGxsChannels(RsGxsIface& gxs) : RsGxsIfaceHelper(gxs) {} virtual ~RsGxsChannels() {} +#ifdef REMOVED /** * @brief Create channel. Blocking API. * @jsonapi{development} @@ -106,6 +107,7 @@ public: * @return false on error, true otherwise */ virtual bool createChannel(RsGxsChannelGroup& channel) = 0; +#endif /** * @brief Create channel. Blocking API. @@ -115,43 +117,76 @@ public: * @param[in] image Thumbnail that is shown to advertise the channel. Possibly empty. * @param[in] author_id GxsId of the contact author. For an anonymous channel, leave this to RsGxsId()="00000....0000" * @param[in] circle_type Type of visibility restriction, among { GXS_CIRCLE_TYPE_PUBLIC, GXS_CIRCLE_TYPE_EXTERNAL, GXS_CIRCLE_TYPE_YOUR_FRIENDS_ONLY, GXS_CIRCLE_TYPE_YOUR_EYES_ONLY } - * @param[in] circle_id Id of the circle (should be an external circle or GXS_CIRCLE_TYPE_EXTERNAL, a local friend group for GXS_CIRCLE_TYPE_YOUR_FRIENDS_ONLY, GxsCircleId()="000....000" otherwise + * @param[in] circle_id Id of the circle (should be an external circle for GXS_CIRCLE_TYPE_EXTERNAL, a local friend group for GXS_CIRCLE_TYPE_YOUR_FRIENDS_ONLY, GxsCircleId()="000....000" otherwise * @param[out] channel_group_id Group id of the created channel, if command succeeds. * @param[out] error_message Error messsage supplied when the channel creation fails. * @return False on error, true otherwise. */ virtual bool createChannel(const std::string& name, const std::string& description, - const RsGxsImage& image, - const RsGxsId& author_id, - uint32_t circle_type, - RsGxsCircleId& circle_id, - RsGxsGroupId& channel_group_id, - std::string& error_message)=0; + const RsGxsImage& image, + const RsGxsId& author_id, + uint32_t circle_type, + RsGxsCircleId& circle_id, + RsGxsGroupId& channel_group_id, + std::string& error_message )=0; /** * @brief Add a comment on a post or on another comment * @jsonapi{development} - * @param[inout] comment + * @param[in] groupId Id of the channel in which the comment is to be posted + * @param[in] parentMsgId Id of the parent of the comment that is either a channel post Id or the Id of another comment. + * @param[in] comment UTF-8 string containing the comment + * @param[out] commentMessageId Id of the comment that was created + * @param[out] error_string Error message supplied when the comment creation fails. * @return false on error, true otherwise */ - virtual bool createComment(RsGxsComment& comment) = 0; + virtual bool createComment(const RsGxsGroupId& groupId, + const RsGxsMessageId& parentMsgId, + const std::string& comment, + RsGxsMessageId& commentMessageId, + std::string& error_message )=0; /** * @brief Create channel post. Blocking API. * @jsonapi{development} - * @param[inout] post + * @param[in] groupId Id of the channel where to put the post (publish rights needed!) + * @param[in] origMsgId Id of the post you are replacing. If left blank (RsGxsMssageId()="0000.....0000", a new post will be created + * @param[in] msgName Title of the post + * @param[in] msg Text content of the post + * @param[in] files List of attached files. These are supposed to be shared otherwise (use ExtraFileHash() below) + * @param[in] thumbnail Image displayed in the list of posts. Can be left blank. + * @param[out] messsageId Id of the message that was created + * @param[out] error_message Error text if anything bad happens * @return false on error, true otherwise */ - virtual bool createPost(RsGxsChannelPost& post) = 0; - + virtual bool createPost(const RsGxsGroupId& groupId, + const RsGxsMessageId& origMsgId, + const std::string& msgName, + const std::string& msg, + const std::list& files, + const RsGxsImage& thumbnail, + RsGxsMessageId& messageId, + std::string& error_message) = 0; /** * @brief createVote * @jsonapi{development} - * @param[inout] vote + * @param[in] groupId Id of the channel where to put the post (publish rights needed!) + * @param[in] threadId Id of the channel post in which a comment is voted + * @param[in] commentMesssageId Id of the comment that is voted + * @param[in] authorId Id of the author. Needs to be your identity. + * @param[in] voteType Type of vote (GXS_VOTE_NONE=0x00, GXS_VOTE_DOWN=0x01, GXS_VOTE_UP=0x02) + * @param[out] voteMessageId Id of the vote message produced + * @param[out] error_message Error text if anything bad happens * @return false on error, true otherwise */ - virtual bool createVote(RsGxsVote& vote) = 0; + virtual bool createVote( const RsGxsGroupId& groupId, + const RsGxsMessageId& threadId, + const RsGxsMessageId& commentMessageId, + const RsGxsId& authorId, + uint32_t voteType, + RsGxsMessageId& voteMessageId, + std::string& error_message)=0; /** * @brief Edit channel details. diff --git a/libretroshare/src/services/p3gxschannels.cc b/libretroshare/src/services/p3gxschannels.cc index f332dfbac..e1fdd9281 100644 --- a/libretroshare/src/services/p3gxschannels.cc +++ b/libretroshare/src/services/p3gxschannels.cc @@ -1166,6 +1166,7 @@ bool p3GxsChannels::createChannel(const std::string& name, return true; } +#ifdef REMOVED bool p3GxsChannels::createChannel(RsGxsChannelGroup& channel) { uint32_t token; @@ -1196,58 +1197,91 @@ bool p3GxsChannels::createChannel(RsGxsChannelGroup& channel) return true; } +#endif -bool p3GxsChannels::createComment(RsGxsComment& comment) +bool p3GxsChannels::createVote( const RsGxsGroupId& groupId, + const RsGxsMessageId & threadId, + const RsGxsMessageId& commentMessageId, + const RsGxsId& authorId, + uint32_t voteType, + RsGxsMessageId& voteMessageId, + std::string& error_message) { - uint32_t token; - if(!createNewComment(token, comment)) + // Do some checks + + std::vector channelsInfo; + + if(!getChannelsInfo(std::list({groupId}),channelsInfo)) // does the channel actually exist? + { + error_message = std::string("Channel with Id " + groupId.toStdString() + " does not exist."); + return false; + } + + if(commentMessageId.isNull()) // has a correct comment msg id been supplied? + { + error_message = std::string("You cannot vote on null comment " + commentMessageId.toStdString() + " of channel with Id " + groupId.toStdString() + ": please supply a non null comment Id!"); + return false; + } + + std::set s({commentMessageId}); + std::vector posts; + std::vector comments; + + if(!getChannelContent( groupId,s,posts,comments )) // does the comment to vote actually exist? { - std::cerr << __PRETTY_FUNCTION__ << "Error! Failed creating comment." - << std::endl; + error_message = std::string("You cannot vote on comment " + commentMessageId.toStdString() + " of channel with Id " + groupId.toStdString() + ": this comment does not locally exist!"); return false; } - if(waitToken(token) != RsTokenService::COMPLETE) + if(posts.front().mMeta.mParentId.isNull()) // is the ID a comment ID or a post ID? It should be comment => should have a parent ID { - std::cerr << __PRETTY_FUNCTION__ << "Error! GXS operation failed." - << std::endl; + error_message = std::string("You cannot vote on channel message " + commentMessageId.toStdString() + " of channel with Id " + groupId.toStdString() + ": this ID refers to a post, not a comment!"); return false; } - if(!RsGenExchange::getPublishedMsgMeta(token, comment.mMeta)) - { - std::cerr << __PRETTY_FUNCTION__ << "Error! Failure getting generated " - << " comment data." << std::endl; + if(voteType != GXS_VOTE_NONE && voteType != GXS_VOTE_UP && voteType != GXS_VOTE_DOWN) // is voteType consistent? + { + error_message = std::string("Your vote to channel with Id " + groupId.toStdString() + " has wrong vote type. Only GXS_VOTE_NONE, GXS_VOTE_UP, GXS_VOTE_DOWN accepted."); return false; - } + } - return true; -} + if(!rsIdentity->isOwnId(authorId)) // is the voter ID actually ours? + { + error_message = std::string("You cannot vote to channel with Id " + groupId.toStdString() + " with identity " + authorId.toStdString() + " because it is not yours."); + return false; + } + + // Create the vote + + RsGxsVote vote; + + vote.mMeta.mGroupId = groupId; + vote.mMeta.mThreadId = threadId; + vote.mMeta.mParentId = commentMessageId; + vote.mMeta.mAuthorId = authorId; + + vote.mVoteType = voteType; -bool p3GxsChannels::createVote(RsGxsVote& vote) -{ uint32_t token; if(!createNewVote(token, vote)) { - std::cerr << __PRETTY_FUNCTION__ << "Error! Failed creating vote." - << std::endl; + error_message = std::string("Error! Failed creating vote."); return false; } if(waitToken(token) != RsTokenService::COMPLETE) { - std::cerr << __PRETTY_FUNCTION__ << "Error! GXS operation failed." - << std::endl; + error_message = std::string("Error! GXS operation failed."); return false; } if(!RsGenExchange::getPublishedMsgMeta(token, vote.mMeta)) { - std::cerr << __PRETTY_FUNCTION__ << "Error! Failure getting generated " - << " vote data." << std::endl; + error_message = std::string("Error! Failure getting generated vote data."); return false; } + voteMessageId = vote.mMeta.mMsgId; return true; } @@ -1282,11 +1316,60 @@ bool p3GxsChannels::editChannel(RsGxsChannelGroup& channel) return true; } -bool p3GxsChannels::createPost(RsGxsChannelPost& post) +bool p3GxsChannels::createPost(const RsGxsGroupId& groupId, + const RsGxsMessageId &origMsgId, + const std::string& msgName, + const std::string& msg, + const std::list& files, + const RsGxsImage& thumbnail, + RsGxsMessageId &message_id, + std::string& error_message) { + // Do some checks + + std::vector channelsInfo; + + if(!getChannelsInfo(std::list({groupId}),channelsInfo)) + { + error_message = std::string("Channel with Id " + groupId.toStdString() + " does not exist."); + return false; + } + + const RsGxsChannelGroup& cg(*channelsInfo.begin()); + + if(!(cg.mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_PUBLISH)) + { + error_message = std::string("You cannot post to channel with Id " + groupId.toStdString() + ": missing publish rights!"); + return false; + } + + if(!origMsgId.isNull()) + { + std::set s({origMsgId}); + std::vector posts; + std::vector comments; + + if(!getChannelContent( groupId,s,posts,comments )) + { + error_message = std::string("You cannot edit post " + origMsgId.toStdString() + " of channel with Id " + groupId.toStdString() + ": this post does not locally exist!"); + return false; + } + } + + // Create the post + RsGxsChannelPost post; + + post.mMeta.mGroupId = groupId; + post.mMeta.mOrigMsgId = origMsgId; + post.mMeta.mMsgName = msgName; + + post.mMsg = msg; + post.mFiles = files; + post.mThumbnail = thumbnail; + uint32_t token; - if( !createPost(token, post) - || waitToken(token) != RsTokenService::COMPLETE ) return false; + if( !createPost(token, post) || waitToken(token) != RsTokenService::COMPLETE ) + return false; if(RsGenExchange::getPublishedMsgMeta(token,post.mMeta)) { @@ -1294,12 +1377,77 @@ bool p3GxsChannels::createPost(RsGxsChannelPost& post) DeepSearch::indexChannelPost(post); #endif // RS_DEEP_SEARCH + message_id = post.mMeta.mMsgId; return true; } + error_message = std::string("cannot publish message. Check that you have publish rights on this channel?"); return false; } +bool p3GxsChannels::createComment(const RsGxsGroupId& groupId, + const RsGxsMessageId& parentMsgId, + const std::string& comment, + RsGxsMessageId& commentMessageId, + std::string& error_message) +{ + // Do some checks + + std::vector channelsInfo; + + if(!getChannelsInfo(std::list({groupId}),channelsInfo)) + { + error_message = std::string("Channel with Id " + groupId.toStdString() + " does not exist."); + return false; + } + + if(parentMsgId.isNull()) + { + error_message = std::string("You cannot comment post " + parentMsgId.toStdString() + " of channel with Id " + groupId.toStdString() + ": please supply a non null post Id!"); + return false; + } + + std::set s({parentMsgId}); + std::vector posts; + std::vector comments; + + if(!getChannelContent( groupId,s,posts,comments )) + { + error_message = std::string("You cannot comment post " + parentMsgId.toStdString() + " of channel with Id " + groupId.toStdString() + ": this post does not locally exist!"); + return false; + } + + // Now create the comment + + RsGxsComment cmt; + + cmt.mComment = comment; + cmt.mMeta.mGroupId = groupId; + cmt.mMeta.mParentId = parentMsgId; + + uint32_t token; + if(!createNewComment(token, cmt)) + { + error_message = std::string("Error! Failed creating comment."); + return false; + } + + if(waitToken(token) != RsTokenService::COMPLETE) + { + error_message = std::string("Error! GXS operation failed."); + return false; + } + + if(!RsGenExchange::getPublishedMsgMeta(token, cmt.mMeta)) + { + error_message = std::string("Error! Failure getting generated comment data."); + return false; + } + + commentMessageId = cmt.mMeta.mMsgId; + return true; +} + bool p3GxsChannels::subscribeToChannel( const RsGxsGroupId& groupId, bool subscribe ) { diff --git a/libretroshare/src/services/p3gxschannels.h b/libretroshare/src/services/p3gxschannels.h index 6ddcedadb..3203be1dd 100644 --- a/libretroshare/src/services/p3gxschannels.h +++ b/libretroshare/src/services/p3gxschannels.h @@ -194,8 +194,10 @@ virtual bool ExtraFileRemove(const RsFileHash &hash); virtual bool getContentSummaries( const RsGxsGroupId& channelId, std::vector& summaries ); +#ifdef REMOVED /// Implementation of @see RsGxsChannels::createChannel virtual bool createChannel(RsGxsChannelGroup& channel); +#endif /// Implementation of @see RsGxsChannels::createChannel virtual bool createChannel(const std::string& name, @@ -207,17 +209,48 @@ virtual bool ExtraFileRemove(const RsFileHash &hash); RsGxsGroupId& channel_group_id, std::string& error_message); +#ifdef REMOVED /// Implementation of @see RsGxsChannels::createComment virtual bool createComment(RsGxsComment& comment); +#endif + + /// Implementation of @see RsGxsChannels::createComment + virtual bool createComment(const RsGxsGroupId& groupId, + const RsGxsMessageId& parentMsgId, + const std::string& comment, + RsGxsMessageId& commentMessageId, + std::string& error_message); /// Implementation of @see RsGxsChannels::editChannel virtual bool editChannel(RsGxsChannelGroup& channel); +#ifdef REMOVED /// Implementation of @see RsGxsChannels::createPost virtual bool createPost(RsGxsChannelPost& post); +#endif + /// Implementation of @see RsGxsChannels::createPost + virtual bool createPost(const RsGxsGroupId& groupId, + const RsGxsMessageId& origMsgId, + const std::string& msgName, + const std::string& msg, + const std::list& files, + const RsGxsImage& thumbnail, + RsGxsMessageId &message_id, + std::string& error_message) ; +#ifdef REMOVED /// Implementation of @see RsGxsChannels::createVote virtual bool createVote(RsGxsVote& vote); +#endif + + /// Implementation of @see RsGxsChannels::createVote + virtual bool createVote(const RsGxsGroupId& groupId, + const RsGxsMessageId& threadId, + const RsGxsMessageId& commentMessageId, + const RsGxsId& authorId, + uint32_t voteType, + RsGxsMessageId& voteMessageId, + std::string& error_message); /// Implementation of @see RsGxsChannels::subscribeToChannel virtual bool subscribeToChannel( const RsGxsGroupId &groupId,