| Commit message (Collapse) | Author | Age | Lines | 
| ...                            |  | 
| | | | | | | | | | | | | | | |  | 
 | 
| | | | | | | | | | | | | | | |  | 
 | 
| | | | | | | | | | | | | | | |  | 
 | 
| | | | | | | | | | | | | | | | 
| | | | | | | | | | | | | | | 
| | | | | | | | | | | | | | | 
| | | | | | | | | | | | | | |  | 
siblings
 | 
| | | | | | | | | | | | | | | |  | 
 | 
| | | | | | | | | | | | | | | |  | 
 | 
| | | | | | | | | | | | | | | |  | 
 | 
| | | | | | | | | | | | | | | | 
| | | | | | | | | | | | | | | 
| | | | | | | | | | | | | | | 
| | | | | | | | | | | | | | |  | 
symbol is a module
 | 
| | | | | | | | | | | | | | | |  | 
 | 
| | | | | | | | | | | | | | | |  | 
 | 
| | | | | | | | | | | | | | | |  | 
 | 
| | | |_|_|_|_|_|_|_|/ / / / /  
| |/| | | | | | | | | | | |    | 
 | 
| | | | | | | | | | |_|_|/ /  
| | | | | | | | |/| | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |   
| | | | | | | | | | | | |    | 
#### Closes #231
Applying the algorithm for `Needles and Haystack` to find and match tag in tags, for example:

This only applies to searching tag_name with more than 3 in length, and at least 80% of its letters are found, from left to right.
There are 3 levels of checking, stop at first found:
- Check if exact name ( case insensitive ) O(1) getting from a dictionary Dict[str, Tag]
- Check for all tags that has 100% matching via algorithm
- Check for all tags that has >= 80% matching
If there are more than one hit, it will be shown as suggestions:

In order to avoid api being called multiple times, I've implemented a cache to only refresh itself when the is a gap of more than 5 minutes from the last api call to get all tags.
Editing / Adding / Deleting tags will also modify the cache directly.
##### What about other solution like fuzzywuzzy?
fuzzywuzzy was considered for using, but from testing, it was giving much lower scores than expected:
Code used to test:
```py
from fuzzywuzzy import fuzz
def _fuzzy_search(search: str, target: str) -> bool:
    found = 0
    index = 0
    _search = search.lower().replace(' ', '')
    _target = target.lower().replace(' ', '')
    for letter in _search:
        index = _target.find(letter, index)
        if index == -1:
            break
        found += index > 0
    # return found / len(_search) * 100
    return (
        found / len(_search) * 100,
        fuzz.ratio(search, target),
        fuzz.partial_ratio(search, target)
    )
tests = (
    'this-is-gonna-be-fun',
    'this-too-will-be-fun'
)
for test in tests:
    print(test, '->', _fuzzy_search('this too fun', test))
```
Result from test:
```py
this-is-gonna-be-fun -> (30.0, 50, 50)
this-too-will-be-fun -> (90.0, 62, 58)
```
 | 
| | | | | | | | | | | | | |  | 
 | 
| | | | | | | | | | | | | | 
| | | | | | | | | | | | | 
| | | | | | | | | | | | | 
| | | | | | | | | | | | | 
| | | | | | | | | | | | |  | 
Fix incorrect docstring and comment
Co-Authored-By: Mark <[email protected]>
 | 
| | | | | | | | | | | | | |  | 
 | 
| | | | | | | | | | | | | | 
| | | | | | | | | | | | | 
| | | | | | | | | | | | | 
| | | | | | | | | | | | |  | 
This reverts commit 56696b3b1858ad27dc7f3dce2898c7a6eb151f43.
 | 
| | | | | | | | | | | | | |  | 
 | 
| | | | | | | | | | | | | |  | 
 | 
| | |_|_|_|_|_|_|_|_|_|_|/  
|/| | | | | | | | | | |    | 
 | 
| |\ \ \ \ \ \ \ \ \ \ \ \  
| |_|_|_|/ / / / / / / /  
|/| | | | | | | | | | |   
| | | | | | | | | | | |   
| | | | | | | | | | | |    | 
Prepend emoji indicative of success of !eval
Co-authored-by: null <[email protected]>
 | 
| | |\ \ \ \ \ \ \ \ \ \ \  
| |/ / / / / / / / / / /  
|/| | | | | | | | | | |    | 
 | 
| |\ \ \ \ \ \ \ \ \ \ \ \  
| |_|_|/ / / / / / / / /  
|/| | | | | | | | | | |    | 
Don't show infraction total outside staff channels.
 | 
| | | | | | | | | | | | |  | 
 | 
| |/ / / / / / / / / / /   | 
 | 
| |\ \ \ \ \ \ \ \ \ \ \  
| | | | | | | | | | | | 
| | | | | | | | | | | |  | 
Fix defcon having wrong text when disabling.
 | 
| | |\ \ \ \ \ \ \ \ \ \ \  
| |/ / / / / / / / / / /  
|/| | | | | | | | | | |    | 
 | 
| |\ \ \ \ \ \ \ \ \ \ \ \  
| | | | | | | | | | | | | 
| | | | | | | | | | | | |  | 
Migrating the test suite to the `unittest` framework
 | 
| | |\ \ \ \ \ \ \ \ \ \ \ \  
| |/ / / / / / / / / / / /  
|/| | | | | | | | | | | |    | 
 | 
| |\ \ \ \ \ \ \ \ \ \ \ \ \  
| | | | | | | | | | | | | | 
| | | | | | | | | | | | | |  | 
Antimalware cog
 | 
| | |\ \ \ \ \ \ \ \ \ \ \ \ \  
| |/ / / / / / / / / / / / /  
|/| | | | | | | | | | | | |    | 
 | 
| |\ \ \ \ \ \ \ \ \ \ \ \ \ \  
| |_|_|_|_|_|_|_|_|_|/ / / /  
|/| | | | | | | | | | | | |    | 
Pluralize "infractions" as necessary.
 | 
| | | | | | | | | | | | | | |  | 
 | 
| |/ / / / / / / / / / / / /   | 
 | 
| |\ \ \ \ \ \ \ \ \ \ \ \ \  
| |_|_|_|_|_|/ / / / / / /  
|/| | | | | | | | | | | |    | 
Fix rule alias.
 | 
| | |\ \ \ \ \ \ \ \ \ \ \ \  
| |/ / / / / / / / / / / /  
|/| | | | | | | | | | | |    | 
 | 
| | | |_|_|_|_|_|_|_|/ / /  
| |/| | | | | | | | | |   
| | | | | | | | | | | |   
| | | | | | | | | | | |   
| | | | | | | | | | | |   
| | | | | | | | | | | |    | 
Allow rule alias to take rule numbers, passes them to the `site rules`
command. Rules are now 1-indexed to conform with the representation on
the website.
 | 
| | | | | | | | | | | | |  | 
 | 
| | | | | | | | | | | | |  | 
 | 
| | | | | | | | | | | | |  | 
 | 
| | | | | | | | | | | | |  | 
 | 
| | | | | | | | | | | | |  | 
 | 
| | | | | | | | | | | | |  | 
 | 
| | | | | | | | | | | | |  | 
 | 
| | | | |\ \ \ \ \ \ \ \ \  
| | |_|/ / / / / / / / /  
| |/| | | | | | | | | |   
| | | | | | | | | | | |   
| | | | | | | | | | | |    | 
Resolving merge conflicts from master in `.gitignore` and
`tests/helpers.py`.
 | 
| | | | | | | | | | | | |  | 
 | 
| | | | |\ \ \ \ \ \ \ \ \   | 
 | 
| | | | | | | | | | | | | | 
| | | | | | | | | | | | | 
| | | | | | | | | | | | | 
| | | | | | | | | | | | | 
| | | | | | | | | | | | | 
| | | | | | | | | | | | | 
| | | | | | | | | | | | |  | 
This commit replaces the standard MagicMocks by our specialized mocks
for discord.py objects. It also adds the missing `channel` attribute
to the `tests.helpers.MockMessage` mock and moves the file to the
correct folder.
 | 
| | | | | | | | | | | | | |  | 
 | 
| | | | |/ / / / / / / / /   | 
 |