> For the complete documentation index, see [llms.txt](https://docs.lenoscripts.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.lenoscripts.com/scripts/lenoreports/exports-and-events.md).

# Exports and Events

Public exports, lifecycle events, and owner hooks for integrating with other resources.

Use **exports** and **lifecycle events** when another resource needs to talk to LenoReports. Use **hooks** when you own the server and want to override access or react inside this resource.

Lifecycle events are **server-local** (`TriggerEvent` / `AddEventHandler`). Do not use `RegisterNetEvent` for them.

## Client exports

| Export         | Returns      | Description                                                  |
| -------------- | ------------ | ------------------------------------------------------------ |
| `OpenPlayer()` | `boolean`    | Force-open the player report UI (hooks + permission checks)  |
| `OpenStaff()`  | `boolean`    | Force-open the staff reports UI                              |
| `Close()`      | —            | Close the reports UI                                         |
| `IsOpen()`     | `open, mode` | `open` is boolean; `mode` is `'player'`, `'staff'`, or `nil` |

## Server exports

| Export                                        | Returns                   | Description                                                                                            |
| --------------------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------ |
| `IsStaff(source)`                             | `boolean`                 | Whether the player is staff                                                                            |
| `IsStaffOnDuty(source)`                       | `boolean`                 | Staff and currently on duty                                                                            |
| `SetStaffDuty(source, onDuty)`                | `ok, onDutyOrErr`         | Set duty (`onDuty` must be a boolean). Fires `staffDutyChanged`                                        |
| `CreateReport(source, data)`                  | `reportId \| false, err?` | Create a report (`category`, `subject`, `description`; optional `involved` / `nearby`)                 |
| `ClaimReport(staffSource, reportId)`          | `payload \| false, err?`  | Claim an open report as staff                                                                          |
| `CloseReport(staffSource, reportId, reason?)` | `payload \| false, err?`  | Close as staff. Defaults to `Resolved`; supported reasons and the `Other` limitation are listed below. |
| `GetReport(reportId)`                         | `report \| nil, err?`     | Compact report DTO (no mark-read side effect)                                                          |
| `GetReports(filter?)`                         | `table`                   | Filter: `status` (default `open`, or `all`), `category`, `assignee`, `author`, `limit` (max 100)       |
| `GetOpenCount()`                              | `number`                  | Count of open reports                                                                                  |
| `GetPlayerActiveReports(source)`              | `table`                   | Open reports authored by that player                                                                   |

Common `err` values include: `forbidden`, `invalid_id`, `not_found`, `already_claimed`, `hook_blocked`, `cooldown`, `max_active`, `invalid_category`, `invalid_subject`, `invalid_description`, `invalid_onDuty`.

### CreateReport data

`source` is the online author's server ID. Use a category **key** from `Config.Categories`, such as `player_report`, `bug_report`, or `other` with the default configuration.

`subject` and `description` are required strings and are subject to the configured report limits. Optional `involved` and `nearby` arrays contain online server IDs; they do not contain citizen IDs or ESX identifiers. Creating through the export still applies the server creation hook and report limits.

### CloseReport reasons

| Reason               | Equivalent database key |
| -------------------- | ----------------------- |
| `Resolved` (default) | `resolved`              |
| `No Response`        | `no_response`           |
| `Player Offline`     | `player_offline`        |
| `Duplicate`          | `duplicate`             |

The current export accepts only `(staffSource, reportId, reason)`.&#x20;

```lua
-- Server: staffSource is an online staff member's server ID.
local result, err = exports['leno_reports']:CloseReport(staffSource, reportId, 'Resolved')
if not result then
    print('CloseReport failed', err)
end
```

## Server lifecycle events

| Event                           | Arguments                                                                                                       |
| ------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `leno_reports:reportCreated`    | `reportId`, `author { source, id, name }`, `category`, `payload { subject, description, authorId, authorName }` |
| `leno_reports:reportClaimed`    | `reportId`, `staff { source, id, name }`                                                                        |
| `leno_reports:reportClosed`     | `reportId`, `reason`, `staff { source, id, name }` (player withdraw uses the author as actor)                   |
| `leno_reports:reportMessage`    | `reportId`, `meta { id, role, author, authorPlayerId, text, photo, timestamp, senderSource }`                   |
| `leno_reports:staffDutyChanged` | `source`, `identifier`, `onDuty`                                                                                |

## Usage examples

```lua
-- Client: open / close from another resource (pause menu, phone, …)
if exports['leno_reports']:OpenPlayer() then
    -- UI opened
end

local open = exports['leno_reports']:IsOpen()
if open then
    exports['leno_reports']:Close()
end
```

```lua
-- Server: create a report and react when any report is created
local reportId, err = exports['leno_reports']:CreateReport(source, {
    category = 'player_report', -- Config.Categories[].key
    subject = 'Cheating',
    description = 'Suspected aimbot near Legion Square.',
})
if not reportId then
    print('CreateReport failed', err)
end

AddEventHandler('leno_reports:reportCreated', function(reportId, author, category, payload)
    print(('Report #%s by %s [%s]'):format(reportId, author.name, category))
end)
```

## Server hooks (`ReportsHooks`)

Defined in `server/main.lua`. Override these functions to change access or react to lifecycle events **inside** this resource.

| Hook                                             | Purpose                                                                          |
| ------------------------------------------------ | -------------------------------------------------------------------------------- |
| `IsStaff(source)`                                | Whether the player is staff (default: `Bridge.IsAdmin`)                          |
| `CanOpenStaff(source)`                           | May open staff menu (default: `IsStaff`)                                         |
| `CanOpenPlayer(source)`                          | May open player menu (default: `true`)                                           |
| `CanCreateReport(source, data)`                  | Return `false` to block create                                                   |
| `OnReportCreated(source, reportId, data)`        | After successful create                                                          |
| `OnReportClosed(source, reportId, reason, data)` | After successful close                                                           |
| `OnDiscordLog(event, data)`                      | Return `false` to cancel Discord log; table to override embed; `nil` for default |

Example:

```lua
function ReportsHooks.CanOpenPlayer(source)
    -- e.g. block players in certain jobs
    return true
end

function ReportsHooks.OnReportCreated(source, reportId, data)
    print(('Report #%s created by %s'):format(reportId, source))
end
```

## Client hooks (`ReportsClientHooks`)

Defined in `client/main.lua`.

| Hook                                   | Purpose                 |
| -------------------------------------- | ----------------------- |
| `BeforeOpenPlayer` / `BeforeOpenStaff` | Gate UI open            |
| `CanTakeScreenshot`                    | Gate screenshot capture |
| `BeforeCreateReport`                   | Gate client-side create |
| `GetOpenDeniedMessage`                 | Custom deny message     |
| `OnUiOpen` / `OnUiClose`               | UI lifecycle            |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.lenoscripts.com/scripts/lenoreports/exports-and-events.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
