0

I am currently writing a blog PoC on EOS. I would like the ability to delete a post. Now deleting by the ID alone is simple, I have it implemented as follows:

whisper::post_index posts(_code, _code.value);
//Find the post with the key
auto itr = posts.find(key);
if (itr != posts.end())
{
    .....    
}

Now obviously anyone can then just pass on an ID and delete a post, so I would like to ensure that only the owner of the post can delete their post.

My posts table does store the owner of the post, it is as follows:

 struct [[ eosio::table, eosio::contract("whisper") ]] posts
  {
    uint64_t key; //Primary key (ID)
    name account; //Account that made the post
    std::string headerImage; //Header image of the post
    std::string title; //Title of the post
    std::string excerpt; //Excerpt of the post
    std::string content; //Content of the post

    uint64_t primary_key() const { return key; }
  };

Is there a way to use .find on the table to search for both the primary key and the owner of the post? If not - how would you suggest on ensuring that only the owner can delete the post?+

3 Answers 3

2

Depending on other logic implemented in the contract I'd personally choose this implementation:

struct [[ eosio::table, eosio::contract("whisper") ]] posts
{
    uint64_t key; //Primary key (ID)
    name account; //Account that made the post
    ...
    ...

    uint128_t primary_key() const { return ((uint128_t)key << 64) & account.value; }
};
typedef eosio::multi_index<"posts"_n, posts> poststable;

now you can use

whisper::post_index posts(_code, _code.value);

uin128_t composite_key = ((uin128_t)key << 64) & account.value;
auto itr = posts.find(composite_key);

to search for a post by key and account

and

whisper::post_index posts(_code, _code.value);

uin128_t composite key = ((uin128_t)key << 64) & 0;
auto itr = posts.lower_bound(composite_key); // or upper_bound(composite_key);

to search for a post by key only.

This way you neither need an extra index nor the account-field in your table-struct wich on the other side means you can't iterate by account.

0

Is there a way to use .find on the table to search for both the primary key and the owner of the post? If not - how would you suggest on ensuring that only the owner can delete the post?+

Yes, you can use a composite key.

 struct [[ eosio::table, eosio::contract("whisper") ]] posts
  {
    uint64_t key; //Primary key (ID)
    name account; //Account that made the post
    std::string headerImage; //Header image of the post
    std::string title; //Title of the post
    std::string excerpt; //Excerpt of the post
    std::string content; //Content of the post

    uint64_t primary_key() const { return key; }
    uint64_t by_key_owner() const { return key + account.value; }
  };

Then make sure to properly define the index:

  typedef eosio::multi_index<"posts"_n, posts,
      indexed_by<"keyowner"_n, const_mem_fun<posts, uint64_t, &stats::by_key_owner>>> poststable;

And to use it...

whisper::poststable posts(_self, _self.value);
auto idx = posts.get_index<"keyowner"_n>();
auto iterator = idx.find(key + account.value);
4
  • 1
    To mention that key + account.value is not unique. But composite keys seem like the right way.
    – cmadh
    Commented Sep 21, 2019 at 14:54
  • Seems the key is the blog id which is always unique so adding username value to it would keep it unique. Commented Sep 21, 2019 at 22:37
  • 1
    No. Key + account.value is a sum of two variables. Just as an example, if user with account.value 100 creates blogpost 80, sum is 180. If user with account.value 80 creates blogpost 100 sum is 180, too.
    – cmadh
    Commented Sep 22, 2019 at 12:05
  • 1
    If you want it to be unique you have to shift bits. uint128_t my_unique = (uint128_t)key << 64 & account.value. This would also allow to use a single index instead of primary + secondary .
    – cmadh
    Commented Sep 22, 2019 at 12:06
-1

Okay so all I did was to check that the account of the iterator after the find was equal to the user making the call. So it ended up looking like this:

//Get the posts
whisper::post_index posts(_code, _code.value);
//Find the post with the key
auto iterator = posts.find(key);
//Check that the post could be found
eosio_assert(iterator != posts.end(), "Post could not be found");
//Check that the user owns the post
eosio_assert(iterator->account == user, "User does not own the post.");
if (iterator != posts.end())
{
    iterator = posts.erase(iterator);
}
1
  • This method is less than efficient. I have provided an answer below that uses composite keys for an index. Commented Aug 22, 2019 at 3:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.