giseldo/neodataset huggingface dataset:
Admins unable to bypass staggered MFA when adding missing withdrawals

<!---
Please read this!

Before opening a new issue, make sure to search for keywords in the issues
filtered by the "T - Bug" label and verify the issue you're about to submit isn't a duplicate.
--->

### Summary

Admins are currently unable to bypass MFA for to add missing withdrawals. This is a regression in the MFA withdrawal changes where admin has not been made exempt from one part of the process. https://gitlab.com/minds/engine/-/commit/f1b0ba83deac32289ba2d7ba28e225243fd03613

### Steps to reproduce

1. Login as admin in Canary
2. Try to add a missing withdrawal.

### Platform information 

Platform agnostic web

### What is the current *bug* behavior?

Error shown (see below)

### What is the expected *correct* behavior?

Should allow the addition of a missing withdrawal

### Relevant logs and/or screenshots

![image](/uploads/9ecc19754c10f8fa9e7da9bdd90881be/image.png)

### Possible fixes

(If you can, link to the line of code that might be responsible for the problem)

Story points: 3.0
Explore improved trending tag logic

It could be worthwhile exploring the current trending tag logic, and exploring if this could be improved.

* Current trending logic : https://gitlab.com/minds/engine/-/tree/master/Core/Trending
* https://www.minds.com/discovery/tags/trending

Trending tags are currently quite stale, and generally include broad tags such as `#life` `#politics` `#meme` - Trending should be a window into what's new / topical. New/topical tags presumably would be more effective in prompting engagement.

```Algorithm determines what is trending by favoring sharp spikes rather than gradual sustained growth, data scientist Gilad Lotan has explained. Trends are determined by a combination of volume and how much time it takes to create volume. In other words, one-day growth is trending, while 30 days is just more news.```

https://rethinkmedia.org/blog/how-does-twitter-decide-what-trending

cc @jotto141 - we touched on this last week, so thought I just create an issue what we can at least follow up on it moving forward.

## Deliverables

- [ ] Exploration
- [ ] Prototype of how it could work

Story points: 5.0
Build node web3 microservice PoC

<!---
Please read this!

Before opening a new issue, make sure to search for keywords in the issues
filtered by the "T - Bug" label and verify the issue you're about to submit isn't a duplicate.
--->

Merge Requests to evaluate:

* Service: https://gitlab.com/minds/web3-server/-/merge_requests/1
* Engine side: https://gitlab.com/minds/engine/-/merge_requests/913
___

* Make a PoC express service that can handle Withdraw dispatching.
* Make endpoint for handling parameter encoding - returning encoded params in response.
* Make it able to handle message signing and transaction signing - returning signed data in response.
* Tie it in with the engine for withdrawals, delegating responsibility to the service.

Story points: 20.0
Extend the Core/Newsfeed/Controller to be able to support unseen 'top' content

- [ ] 'api/v3/newsfeed/feed/unseen-top' endpoint
- [ ] Using a salted hash, so that we can see what a user has seen, record a list of seen entities in a redis key (use a 24 hour ttl).
- [ ] When fetching the top content, exclude the already seen keys

Story points: 13.0
Investigate and explore skETH faucet

skETH is used to pay for transaction gas on the SKALE network and has NO MONETARY VALUE. Users have to have it to send transactions, and we need a method to distribute it to them.

We will need to investigate either:

##### 1. Distribution mechanisms for skETH 

* From a central wallet that users can request funds from?
* From a contract?
* Share X amount across all active wallets, give new accounts some? (how would users then get more?)

I'm concerned about the chance for Sybil attacks if we were to distribute the skETH ourselves. Though there's no monetary value associated with it, I do anticipate us having to try devise a Sybil-resistant distribution mechanism to prevent malicious users from trying to hoard skETH. This for example is an issue for things like Rinkeby ETH, where people try to hoard it despite it being valueless - thus faucets usually have to connect to Twitter to verify a users uniqueness.

##### 2. Allow members to mine in browser for skETH.

Even though its a very simple and lightweight in terms of operations (presuming this is the bulk of the logic https://github.com/skalenetwork/pow-demo/blob/main/skale-miner.js), this option would technically be building a miner into our web app, unless we spin a separate app up on a subdomain. We need to spin that demo app up locally so that we can get a full grasp of how things like a new block being proposed happen in any case to fully evaluate the option.

Various examples of methods of handling this can be found at:
* https://github.com/skalenetwork/pow-demo 
* https://docs.skale.network/skaled/3.7.x/skale-chain-eth

Story points: 3.0
Change guest-mode bottom banner text and make bar smaller

<!---
Please read this!

Before opening a new issue, make sure to search for keywords in the issues
filtered by the "T - Bug" label and verify the issue you're about to submit isn't a duplicate.
--->

https://www.sketch.com/s/fa301655-276b-4d88-9247-9c61363c1eae/v/ebVWVW/a/JnpAyMr/r/w8ODnD

Story points: 1.0
Decide on bottom-bar text content for guest-mode

<!---
Please read this!

Before opening a new issue, make sure to search for keywords in the issues
filtered by the "T - Bug" label and verify the issue you're about to submit isn't a duplicate.
--->

https://www.sketch.com/s/fa301655-276b-4d88-9247-9c61363c1eae/a/DPvWGve

Decided on this copy for now:

> Speak freely and earn crypto.

And this is with the expectation that we can reduce the height of the bar to (1) look good with the shorter string, and (b) be less in the way.

Story points: 1.0
Reports of email MFA codes still not working

<!---
Please read this!

Before opening a new issue, make sure to search for keywords in the issues
filtered by the "T - Bug" label and verify the issue you're about to submit isn't a duplicate.
--->

### Summary

Some members are still reporting issues with their MFA codes not being accepted for various actions such as withdrawals and enabling other forms of MFA

### Steps to reproduce

Unable to replicate the issue at present.

### Platform information 

In this report, multiple devices with Windows 10 & Brave.

### What is the current *bug* behavior?

Member cannot enter the MFA code dispatched to their email (entered within a couple of minutes)

### What is the expected *correct* behavior?

The MFA code that is sent should be valid for 5 minutes.

### Relevant logs and/or screenshots

N/A

### Possible fixes

Fixing this issue will have to be somewhat blind - if we could find a way to replicate consistently, that would simplify the process slightly. One thing to check is that client-side timestamps are not being used, as there could be issues caused by timezones.

Story points: 5.0
Update circulating supply calculation in token analytics dashboard

## Summary

The historical circulating supply data is incorrect because it thinks certain addresses are included in the calculation when they should not be.

We need to add a few more addresses to make sure they are not included in the calculation.

## Tasks

- [ ] Update addresses to exclude from Circulating Supply calculaton
- [ ] Re-run script to obtain historical data for Circulating Supply in token analytics dashboard

## Addresses To Exclude From Circulating Supply

- [x] Sale `0x1f28c6fb3ea8ba23038c70a51d8986c5d1276a8d`
- [x] Withdraw (current) `0x6f2548b1bee178a49c8ea09be6845f6aeaf3e8da`
- [x] Gnosis Safe `0xef5Be346D746761DC4a400A536E50B06B8F56b09`
- [x] Coinbase Custody `0x7ef271b4613c2f61ecd69fd4f5d1de91860bce4b`
- [x] Withdraw (legacy) `0x14e421986c5ff2951979987cdd82fa3c0637d569`
- [x] Minds General `0x1820ffad63fd64d7077da4355e9641dfff4dad0d`
- [x] Bounties `0x85c040378d17e84d5cc21398b3bbafe08e0eae6f`

## Addresses To Include In Circulating Supply (currently excluded)

- [ ] Boost `0x112ca67c8e9a6ac65e1a2753613d37b89ab7436b`
- [ ] Pro `0x97749850000766d54f882406adc9d47458b2c137`
- [ ] Create new address for Minds+ redemptions

## Questions

- Process to move reclaimed off-chain tokens into respective on-chain addresses (boost, pro, plus)
- What to do with Minds Sales wallet?
- What is the Minds Other wallet?

Story points: 2.0
Exception: Session required

Sentry Issue: [ENGINE-VCG](https://sentry.io/organizations/minds-inc/issues/2377712746/?referrer=gitlab_integration)

```
Exception: Session required
  File "/Core/Sessions/Manager.php", line 319, in Minds\Core\Sessions\Manager::delete
    throw new Exception("Session required");
  File "/Controllers/api/v1/authenticate.php", line 162, in Minds\Controllers\api\v1\authenticate::delete
    $sessions->delete();
  File "/Api/Factory.php", line 87, in Minds\Api\Factory::build
    return $handler->$method($pages);
  File "/Controllers/api/api.php", line 91, in Minds\Controllers\api\api::delete
    return Factory::build($pages, $this->request, $this->response);
  File "/Core/Router/PrePsr7/Router.php", line 154, in Minds\Core\Router\PrePsr7\Router::route
    return $handler->$method($pages);
...
(9 additional frame(s) were not displayed)

Exception: Session required in /var/www/Minds/engine/Core/Sessions/Manager.php:319
Stack trace:
#0 /var/www/Minds/engine/Controllers/api/v1/authenticate.php(162): Minds\Core\Sessions\Manager->delete()
#1 /var/www/Minds/engine/Api/Factory.php(87): Minds\Controllers\api\v1\authenticate->delete(Array)
#2 /var/www/Minds/engine/Controllers/api/api.php(91): Minds\Api\Factory::build(Array, Object(Zend\Diactoros\ServerRequest), Object(Zend\Diactoros\Response\JsonResponse))
#3 /var/www/Minds/engine/Core/Router/PrePsr7/Router.php(154): Minds\Controllers\api\api->delete(Array)
#4 /var/www/Minds/engine/Core/Router/PrePsr7/Fallback.php(80): Minds\Core\Router\PrePsr7\Router->route('/api/v1/authent...', 'delete')
#5 /var/www/Minds/engine/Core/Router/Middleware/Kernel/RouteResolverMiddleware.php(81): Minds\Core\Router\PrePsr7\Fallback->handle(Object(Zend\Diactoros\ServerRequest))
#6 /var/www/Minds/engine/Core/Router/Dispatcher.php(57): Minds\Core\Router\Middleware\Kernel\RouteResolverMiddleware->process(Object(Zend\Diactoros
```

Story points: 2.0
Ensure iframely proxy exceptions are caught and not throwing 500 errors

Sentry Issue: [ENGINE-2FYB](https://sentry.io/organizations/minds-inc/issues/2693683639/?referrer=gitlab_integration)

```
GuzzleHttp\Exception\ClientException: Client error: `GET https://open.iframe.ly/api/iframely?origin=minds&api_key=00d65e11718feb4a1e2956&url=https%3A%2F%2Fm.facebook.com%2Fstory.php%3Fstory_fbid%3D10209681773479153%26id%3D1774255843%26sfnsn%3Dmo` resulted in a `404 Not Found` response:
{
    "status": 404,
    "error": "Iframely could not fetch the given URL. The content is no longer available at the ori (truncated...)

  File "/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php", line 113, in GuzzleHttp\Exception\RequestException::create
    return new $className($message, $request, $response, $previous, $ctx);
  File "/vendor/guzzlehttp/guzzle/src/Middleware.php", line 65, in GuzzleHttp\Middleware::GuzzleHttp\{closure}
    throw RequestException::create($request, $response);
  File "/vendor/guzzlehttp/promises/src/Promise.php", line 204, in GuzzleHttp\Promise\Promise::callHandler
    $promise->resolve($f($value));
  File "/vendor/guzzlehttp/promises/src/Promise.php", line 153, in GuzzleHttp\Promise\Promise::GuzzleHttp\Promise\{closure}
    self::callHandler($id, $value, $handler);
  File "/vendor/guzzlehttp/promises/src/TaskQueue.php", line 48, in GuzzleHttp\Promise\TaskQueue::run
    $task();
...
(21 additional frame(s) were not displayed)

GuzzleHttp\Exception\ClientException: Client error: `GET https://open.iframe.ly/api/iframely?origin=minds&api_key=00d65e11718feb4a1e2956&url=https%3A%2F%2Fm.facebook.com%2Fstory.php%3Fstory_fbid%3D10209681773479153%26id%3D1774255843%26sfnsn%3Dmo` resulted in a `404 Not Found` response:
{
    "status": 404,
    "error": "Iframely could not fetch the given URL. The content is no longer available at the ori (truncated...)
 in /var/www/Minds/engine/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php:113
Stack trace:
#0 /var/www/Minds/engine/vendor/guzzlehttp/guzzle/src/Middleware.php(65): GuzzleHttp\Exception\RequestException::create(Object(GuzzleHttp\Psr7\Request), Object(GuzzleHttp\Psr7\Response))
#1 /var/www/Minds/engine/vendor/guzzlehttp/promises/src/Promise.php(204): GuzzleHttp\Middleware::GuzzleHttp\{closure}(Object(GuzzleHttp\Psr7\Response))
#2 /var/www/Minds/engine/vendor/guzzlehttp/promises/src/Promise.php(153): GuzzleHttp\Promise\Promise::callHandler(1, Object(GuzzleHttp\Psr7\Response), NULL)
#3
```

Story points: 2.0
TypeError: Minds\Controllers\api\v1\blog::checkBalance(): Argument #1 ($user) must be of type Minds\Entities...

Sentry Issue: [ENGINE-QBW](https://sentry.io/organizations/minds-inc/issues/1829367935/?referrer=gitlab_integration)

```
TypeError: Minds\Controllers\api\v1\blog::checkBalance(): Argument #1 ($user) must be of type Minds\Entities\User, null given, called in /var/www/Minds/engine/Controllers/api/v1/blog.php on line 156
  File "/Controllers/api/v1/blog.php", line 442, in Minds\Controllers\api\v1\blog::checkBalance
    private function checkBalance(User $user): bool
  File "/Controllers/api/v1/blog.php", line 156, in Minds\Controllers\api\v1\blog::get
    $response['require_login'] = !$this->checkBalance($owner);
  File "/Api/Factory.php", line 87, in Minds\Api\Factory::build
    return $handler->$method($pages);
  File "/Controllers/api/api.php", line 76, in Minds\Controllers\api\api::get
    return Factory::build($pages, $this->request, $this->response);
  File "/Core/Router/PrePsr7/Router.php", line 154, in Minds\Core\Router\PrePsr7\Router::route
    return $handler->$method($pages);
...
(9 additional frame(s) were not displayed)

TypeError: Minds\Controllers\api\v1\blog::checkBalance(): Argument #1 ($user) must be of type Minds\Entities\User, null given, called in /var/www/Minds/engine/Controllers/api/v1/blog.php on line 156 and defined in /var/www/Minds/engine/Controllers/api/v1/blog.php:442
Stack trace:
#0 /var/www/Minds/engine/Controllers/api/v1/blog.php(156): Minds\Controllers\api\v1\blog->checkBalance(NULL)
#1 /var/www/Minds/engine/Api/Factory.php(87): Minds\Controllers\api\v1\blog->get(Array)
#2 /var/www/Minds/engine/Controllers/api/api.php(76): Minds\Api\Factory::build(Array, Object(Zend\Diactoros\ServerRequest), Object(Zend\Diactoros\Response\JsonResponse))
#3 /var/www/Minds/engine/Core/Router/PrePsr7/Router.php(154): Minds\Controllers\api\api->get(Array)
#4 /var/www/Minds/engine/Core/Router/PrePsr7/Fallback.php(80): Minds\Core\Router\PrePsr7\Router->route('/api/v1/blog/99...', 'get')
#5 /var/www/Minds/engine/Core/Router/Middleware/Kernel/RouteResolverMiddleware.php(81): Minds\Core\Router\PrePsr7\Fallback->handle(Object(Zend\D
```

Story points: 1.0
TypeError: setcookie(): Argument #2 ($value) must be of type string, Lcobucci\JWT\Token\Plain given

Sentry Issue: [ENGINE-Y8Y](https://sentry.io/organizations/minds-inc/issues/2509747153/?referrer=gitlab_integration)

```
TypeError: setcookie(): Argument #2 ($value) must be of type string, Lcobucci\JWT\Token\Plain given
  File "/Common/Cookie.php", line 70, in setcookie
    setcookie($this->name, $this->value, $this->expire, $this->path, $this->domain, $this->secure, $this->httpOnly);
  File "/Common/Cookie.php", line 70, in Minds\Common\Cookie::create
    setcookie($this->name, $this->value, $this->expire, $this->path, $this->domain, $this->secure, $this->httpOnly);
  File "/Core/Sessions/Manager.php", line 283, in Minds\Core\Sessions\Manager::save
    ->create();
  File "/Core/SSO/Manager.php", line 161, in Minds\Core\SSO\Manager::authorize
    ->save();
  File "/Controllers/api/v2/sso/authorize.php", line 59, in Minds\Controllers\api\v2\sso\authorize::post
    ->authorize($_POST['token']);
...
(12 additional frame(s) were not displayed)

TypeError: setcookie(): Argument #2 ($value) must be of type string, Lcobucci\JWT\Token\Plain given in /var/www/Minds/engine/Common/Cookie.php:70
Stack trace:
#0 /var/www/Minds/engine/Common/Cookie.php(70): setcookie('minds_sess', Object(Lcobucci\JWT\Token\Plain), 1637315192, '/', '', true, true)
#1 /var/www/Minds/engine/Core/Sessions/Manager.php(283): Minds\Common\Cookie->create()
#2 /var/www/Minds/engine/Core/SSO/Manager.php(161): Minds\Core\Sessions\Manager->save()
#3 /var/www/Minds/engine/Controllers/api/v2/sso/authorize.php(59): Minds\Core\SSO\Manager->authorize('eyJ0eXAiOiJKV1Q...')
#4 /var/www/Minds/engine/Api/Factory.php(87): Minds\Controllers\api\v2\sso\authorize->post(Array)
#5 /var/www/Minds/engine/Controllers/api/api.php(81): Minds\Api\Factory::build(Array, Object(Zend\Diactoros\ServerRequest), Object(Zend\Diactoros\Response\JsonResponse))
#6 /var/www/Minds/engine/Core/Router/PrePsr7/Router.php(154): Minds\Controllers\api\api->post(Array)
#7 /var/www/Minds/engine/Core/Router/PrePsr7/Fallback.php(8
```

Story points: 1.0
"api/v3/oauth/token" should not return a valid session if the user is banned

Currently, when an account is banned, they will be able to log into the app and get past the auth state. But when they enter the app they can't do anything. And when the app is restarted, they will go back to the auth page.

## What should happen

- Given a user is banned, an error should be shown on the login screen.
- Given a user is banned and they're logged in, an error should be shown to them to let them know they've been banned and they should be navigated to the login screen.

Story points: 1.0
Create a Recommendations module that is expandable

- [x] Create a module that can return entities based on a 'placement' variable
- [x] api/v3/recommendations controller
- [x] Spec tests


## Recommendations algorithms
  - [x] use Suggestions for 'suggested-channels' algorithm
  - [x] Create 'wider-network' recommendations algorithm
  - [ ] Create 'inferred' recommendations algorithm

## Vision for the module

We want to create a module that can be easily expanded as we learn more about our data and usage patterns of the site. For example we want to be able to support multiple answers such as 'posts that by subscriptions have voted on' but also 'top posts my subscriptions have made'.

The API should be able to dynamically determine what algorithms or queries to return based on the `location` that is provided. This will allow us to easily change the recommendations and run experiments from a single place. The frontend only needs to support a simple component that can render the entities.  

### Example API Call

#### GET `api/v3/recommendations/?location=feed-sidebar`
RESPONSE:
```json
{
  "query": "wider-network",
  "entities": [ ],
}
```
```json
{
  "query": "inferred",
  "entities": [ ],
}
```
```json
{
  "query": "favourite-subscribed-posts",
  "entities": [ ],
}
```

### Example queries

#### Wider network
This will return entities from my wider network (ie. content that my subscribers have interacted with.

#### Inferred 
This will return entities based on content that I have interacted

Story points: 20.0
Re-index all autosuggested users with new analyzer to support numbers

<!---
Please read this!

Before opening a new issue, make sure to search for keywords in the issues
filtered by the "T - Bug" label and verify the issue you're about to submit isn't a duplicate.
--->

### Summary

It seems that usernames that are numbers, or begin with numbers, do not appear in search.
REF: https://www.minds.com/newsfeed/1003716877810827264

### Steps to reproduce

Search "1085243" in the top search bar. Observe ES does not find the user.

### Platform information 

Cross-platform

### What is the current *bug* behavior?

ElasticSearch is not weighting numerical names appropriately.

### What is the expected *correct* behavior?

The name should appear when typed in.

### Relevant logs and/or screenshots

![image](/uploads/f857bfcc52acc6809f7855c66556183a/image.png)

### Possible fixes

I'm presuming something needs tweaking at an ElasticSearch level.

Story points: 4.0
Boosts from blocked users are being shown

<!---
Please read this!

Before opening a new issue, make sure to search for keywords in the issues
filtered by the "T - Bug" label and verify the issue you're about to submit isn't a duplicate.
--->

### Summary

When user 'A' blocks user 'B', user 'A' is being served the boosts from user 'B'.

### Steps to reproduce

1. Block a user
2. Go to Newsfeed
3. Boosts from that user persist

### What is the expected *correct* behavior?

Boosts should be blocked too.

### Relevant logs and/or screenshots

https://www.minds.com/newsfeed/1002258011014168576
https://www.minds.com/newsfeed/1031185109487849472

Story points: 3.0
(feature) Extend the limit on group items to support infinite (just like a user's own feed)

Here's the feedback from the squad leaders on the current situation

Emi: There's a 150 posts hard limit on feeds right now.

Emi: We should workaround something for user's own feeds

Emi: because it seems that people like to scroll to the bottom of their own channel

Mark Harding: own channels is infinite now, newsfeed should be able to copy that logic easily

Emi: ah!, but I think they're mostly complaining about that for their own feeds and groups


Let's verify that there's more than a 150 posts on a user's own channel and then apply those changes to the back end

Story points: 1.0
(feature) Extend the limit on newsfeed items to support infinite (just like a user's own feed)

Here's the feedback from the squad leaders on the current situation

Emi: There's a 150 posts hard limit on feeds right now.

Emi: We should workaround something for user's own feeds

Emi: because it seems that people like to scroll to the bottom of their own channel

Mark Harding: own channels is infinite now, newsfeed should be able to copy that logic easily

Emi: ah!, but I think they're mostly complaining about that for their own feeds and groups


Let's verify that there's more than a 150 posts on a user's own channel and then apply those changes to the back end

Story points: 10.0
(bug): Group chat stuck loading

<!---
Please read this!

Before opening a new issue, make sure to search for keywords in the issues
filtered by the "T - Bug" label and verify the issue you're about to submit isn't a duplicate.
--->

### Summary

Group chats are not loading. Happens in canary and non-canary.

### Steps to reproduce

1. Open a group
2. See its not loading

### Platform information 

Reproduced on Chrome / Ubuntu and MacOS.

### What is the current *bug* behavior?

Group chat does not load.

### What is the expected *correct* behavior?

Group chat should load.

### Relevant logs and/or screenshots

```
"StaticInjectorError[l -> l]:
StaticInjectorError(Platform: core)[l -> l]:
NullInjectorError: No provider for l!"
```

![image](/uploads/2d5d8368e3c310dae241b92718157d12/image.png)

### Possible fixes

I see references to the CDN in the logs, need to further investigate.

Story points: 1.0
(chore) Refactors to support PHP 7.3

If you upgrade to php@7.2, phpspec will start failing because Minds\Entities\Object is now a reserved word. It won't even compile.

There are various additional errors that need resolving to upgrade to PHP 7.3...
* Use of `continue` in `case` statements that need replacing with either `break` or `continue 2`
* method signatures of classes that are extending an abstract class where the new method signatures do not match the method signatures of the abstract

Story points: 2.0