---
title: "Advanced Filters"
author: "Ernest Benedito"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Advanced Filters}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

This vignette describes advanced use cases for the filters used with `MessageHandler` or `CommandHandler`.

## Combining filters

When using `MessageHandler` it is sometimes useful to have more than one filter. This can be done using so called binary operators. Using `telegram.bot`, you can operate `BaseFilter` instances with `&`, `|` and `!` meaning AND, OR and NOT respectively.

### Examples

#### Message is either video, photo, or document (generic file)

```{r, eval = FALSE}
handler <- MessageHandler(
  callback,
  MessageFilters$video | MessageFilters$photo | MessageFilters$document
)
```

#### Message is a forwarded photo

```{r, eval = FALSE}
handler <- MessageHandler(
  callback,
  MessageFilters$forwarded & MessageFilters$photo
)
```

#### Message is a photo and it's not forwarded

```{r, eval = FALSE}
handler <- MessageHandler(
  callback,
  MessageFilters$photo & (!MessageFilters$forwarded)
)
```

## Custom filters

It is also possible to write your own filters used with `MessageHandler` and `CommandHandler`. In essence, a filter is simply a function that receives a `Message` instance and returns either `TRUE` or `FALSE`. This function has to be implemented in a new class that inherits from `BaseFilter`, which allows it to be combined with other filters. If a filter evaluates to `TRUE`, the message will be handled. 

### Examples

#### Restricting users

Say that for the `kill` example we saw in the [previous page](https://github.com/ebeneditos/telegram.bot/wiki/Basic-Functionalities#stopping-the-bot), we would like to filter that command so to make it accessible only for a specific `USER_ID`. Thereby, you could add a filter:

```{r, eval = FALSE}
filter_user <- function(message) message$from_user == "USER_ID"
```

You can make the function an instance of `BaseFilter` either with its generator:

```{r, eval = FALSE}
filter_user <- BaseFilter(filter = filter_user)
```

Or by coercing it with `as.BaseFilter`:

```{r, eval = FALSE}
filter_user <- as.BaseFilter(function(message) message$from_user == "USER_ID")
```

Remember that to make it work, your filter must be a `function` that takes a `message` as input and returns a boolean: `TRUE` if the message should be handled, `FALSE` otherwise.

Now, you could update the handler with this filter:

```{r, eval = FALSE}
kill_handler <- CommandHandler("kill", kill, filter_user)
```

#### Text or command filter

Filters can also be added to the `MessageFilters` object. Within it, we can see that `MessageFilters$text` and `MessageFilters$command` are mutually exclusive, so we could add a filter for messages that can be either one of them. This would result as:

```{r, eval = FALSE}
MessageFilters$text_or_command <- BaseFilter(function(message) {
  !is.null(message$text)
})
```

The class can of cause be named however you want, the only important things are:

- The class has to inherit from `BaseFilter`.
- It has to implement a `filter` method.
- The filter must be a `function` that takes a `message` as input and returns a boolean.

The filter can then be used as:

```{r, eval = FALSE}
handler <- MessageHandler(callback, MessageFilters$text_or_command)
```
