Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0837a879c9 | ||
|
|
53f8a821cd | ||
|
|
1d25195316 | ||
|
|
18846e1e1c |
91
CLAUDE.md
Normal file
91
CLAUDE.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# SNMP Scanner - Claude Code Instructions
|
||||
|
||||
## Project Overview
|
||||
|
||||
Repository for SNMP-based Zabbix templates and network device monitoring tools. Templates created here integrate with the ShopDB application for displaying supply levels.
|
||||
|
||||
## Repository Location
|
||||
|
||||
- **Local**: `/home/camp/projects/python/snmp-scanner/`
|
||||
- **Gitea**: `http://localhost:3000/cproudlock/snmp-scanner`
|
||||
|
||||
## Key Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `zabbix_template_*.yaml` | Zabbix monitoring templates |
|
||||
| `README.md` | Template guidelines for ShopDB integration |
|
||||
|
||||
## Zabbix Template Requirements
|
||||
|
||||
### For displayprinter.asp Compatibility
|
||||
|
||||
Supply level items MUST follow these rules to appear in ShopDB:
|
||||
|
||||
1. **Item name must contain "Level"**
|
||||
```yaml
|
||||
name: Ribbon Level # Good - will appear
|
||||
name: Ribbon Remaining # Bad - filtered out
|
||||
```
|
||||
|
||||
2. **Value must be percentage (0-100)**
|
||||
- Add preprocessing if SNMP returns raw counts
|
||||
- Use JavaScript to convert: `(remaining / capacity) * 100`
|
||||
|
||||
3. **Use `units: '%'`** for percentage values
|
||||
|
||||
### Zabbix YAML Structure
|
||||
|
||||
```yaml
|
||||
# UUIDs: 32 hex chars, no dashes
|
||||
uuid: 97f742974686406aa8be1394d18dcb5f
|
||||
|
||||
# Triggers go INSIDE items, not at template level
|
||||
items:
|
||||
- uuid: abc123...
|
||||
name: Some Item
|
||||
triggers: # Nested under the item
|
||||
- uuid: def456...
|
||||
expression: '...'
|
||||
```
|
||||
|
||||
### Generating Valid UUIDs
|
||||
|
||||
```bash
|
||||
python3 -c "import uuid; print(uuid.uuid4().hex)"
|
||||
```
|
||||
|
||||
## Related Projects
|
||||
|
||||
- **ShopDB**: `/home/camp/projects/windows/shopdb/`
|
||||
- `includes/zabbix_all_supplies.asp` - Zabbix API integration
|
||||
- `displayprinter.asp` - Displays supply levels from Zabbix
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Creating a New Template
|
||||
|
||||
1. Get SNMP walk data from the device
|
||||
2. Identify relevant OIDs for monitoring
|
||||
3. Create YAML template following structure in existing templates
|
||||
4. Ensure supply items have "Level" in name and return percentages
|
||||
5. Generate valid UUIDv4 for all uuid fields
|
||||
6. Place triggers inside their related items
|
||||
|
||||
### Testing Template Import
|
||||
|
||||
1. Import into Zabbix via Configuration > Templates > Import
|
||||
2. Common errors:
|
||||
- "unexpected tag triggers" = triggers at wrong level (move inside items)
|
||||
- "invalid parameter uuid" = UUID not valid UUIDv4 format
|
||||
|
||||
## Device-Specific Notes
|
||||
|
||||
### HID Fargo DTC4500e Card Printer
|
||||
|
||||
- **MIB**: HID Enterprise MIB (1.3.6.1.4.1.28959)
|
||||
- **Ribbon**: YMCKO 500-print capacity
|
||||
- **OID for ribbon**: 1.3.6.1.4.1.28959.3.255.1.16.0 (returns raw count)
|
||||
- **Status flags OID**: 1.3.6.1.4.1.28959.3.255.1.10.0
|
||||
- Format: `DH:0 IH:0 LM:0 FL:1 MG:0 SM:0 SC:0 PE:0`
|
||||
- DH=Door/Hopper, IH=Input Hopper, FL=Film loaded, etc.
|
||||
267
README.md
267
README.md
@@ -1,237 +1,64 @@
|
||||
# Zabbix Printer Monitoring Templates
|
||||
# SNMP Scanner / Zabbix Templates
|
||||
|
||||
## Overview
|
||||
This repository contains SNMP-based Zabbix templates and related tooling for monitoring network devices.
|
||||
|
||||
This project provides comprehensive Zabbix 7.4 templates for monitoring HP and Xerox network printers via SNMP v2. Five specialized templates have been created to handle the different OID index mappings used by various printer models.
|
||||
## Zabbix Template Requirements for ShopDB Integration
|
||||
|
||||
## Template Files
|
||||
Templates created here are used with the ShopDB `displayprinter.asp` page, which pulls supply data from Zabbix via API. To ensure compatibility:
|
||||
|
||||
All templates are available in both YAML and JSON formats:
|
||||
### Supply Level Items
|
||||
|
||||
1. **HP LaserJet - Monochrome** (`zabbix_template_hp_mono.*`)
|
||||
- 10 monitoring items
|
||||
- Covers: HP LaserJet Pro 4xxx, M4xx, M6xx (B&W models)
|
||||
- Monitors: Black toner, Maintenance kit
|
||||
For supply items to appear in displayprinter.asp, they **must**:
|
||||
|
||||
2. **HP LaserJet - Color** (`zabbix_template_hp_color.*`)
|
||||
- 20 monitoring items
|
||||
- Covers: HP Color LaserJet Pro, M4xx, M2xx (Color models)
|
||||
- Monitors: Black/Cyan/Magenta/Yellow toners
|
||||
1. **Include "Level" in the item name** - The page filters for items containing "Level"
|
||||
- Good: `Ribbon Level`, `Toner Level Black`, `Ink Level Cyan`
|
||||
- Bad: `Ribbon Remaining`, `Toner Count`, `Ink Status`
|
||||
|
||||
3. **Xerox VersaLink - Color** (`zabbix_template_xerox_color.*`)
|
||||
- 41 monitoring items
|
||||
- Covers: Xerox VersaLink C7xxx, C4xxx (Color MFPs)
|
||||
- Monitors: 4 toners, 4 drums, waste, transfer components, fuser
|
||||
2. **Return a percentage value (0-100)** - The page displays items as progress bars
|
||||
- If the SNMP OID returns a raw count, add preprocessing to convert to percentage
|
||||
- Example: For a 500-print ribbon, use JavaScript preprocessing:
|
||||
```javascript
|
||||
var remaining = parseInt(value, 10);
|
||||
var percent = (remaining / 500) * 100;
|
||||
return Math.min(100, Math.max(0, percent.toFixed(1)));
|
||||
```
|
||||
|
||||
4. **Xerox VersaLink - Monochrome** (`zabbix_template_xerox_mono.*`)
|
||||
- 14 monitoring items
|
||||
- Covers: Xerox VersaLink B7xxx, B4xxx (B&W MFPs)
|
||||
- Monitors: Toner, drum, transfer roller, fuser
|
||||
3. **Use appropriate units** - Set `units: '%'` for percentage values
|
||||
|
||||
5. **Xerox Enterprise - Color** (`zabbix_template_xerox_enterprise.*`)
|
||||
- 28 monitoring items
|
||||
- Covers: Xerox EC8036, AltaLink C8xxx (Enterprise Color MFPs)
|
||||
- Monitors: 4 toners, 4 drums, fuser, waste, 2 transfer components (percentage-based)
|
||||
### Example Item Structure
|
||||
|
||||
## Network Coverage
|
||||
|
||||
Total printers: 27
|
||||
|
||||
- HP Monochrome: 13 printers
|
||||
- HP Color: 3 printers
|
||||
- Xerox VersaLink Color: 4 printers
|
||||
- Xerox VersaLink Mono: 3 printers
|
||||
- Xerox Enterprise: 4 printers
|
||||
|
||||
Full IP-to-template mapping available in `printer_template_mapping.py` output.
|
||||
|
||||
## Import Instructions
|
||||
|
||||
### Method 1: Zabbix Web UI
|
||||
|
||||
1. Login to Zabbix web interface
|
||||
2. Navigate to: **Configuration → Templates → Import**
|
||||
3. Select the appropriate YAML or JSON file for each printer type
|
||||
4. Click **Import**
|
||||
5. Repeat for each template file
|
||||
|
||||
### Method 2: Zabbix API
|
||||
|
||||
Use the Zabbix API to import templates programmatically. See Zabbix documentation for details.
|
||||
|
||||
## Configuring Printers
|
||||
|
||||
For each printer host in Zabbix:
|
||||
|
||||
1. **Link Template**: Assign the appropriate template based on model (see IP mapping below)
|
||||
2. **Configure SNMP Interface**:
|
||||
- IP Address: Printer IP
|
||||
- Port: 161
|
||||
- SNMP version: SNMPv2
|
||||
- SNMP community: `WestJeff2025`
|
||||
|
||||
## Template to IP Mapping
|
||||
|
||||
### HP LaserJet - Monochrome (zabbix_template_hp_mono)
|
||||
```
|
||||
10.80.92.23, 10.80.92.24, 10.80.92.26, 10.80.92.28, 10.80.92.46, 10.80.92.53,
|
||||
10.80.92.54, 10.80.92.55, 10.80.92.56, 10.80.92.57, 10.80.92.61, 10.80.92.65, 10.80.92.71
|
||||
```yaml
|
||||
- uuid: <valid-uuidv4>
|
||||
name: Ribbon Level # Must contain "Level"
|
||||
type: SNMP_AGENT
|
||||
snmp_oid: 'get[1.3.6.1.4.1.xxx]'
|
||||
key: device.ribbon.level
|
||||
value_type: FLOAT
|
||||
units: '%' # Percentage
|
||||
preprocessing:
|
||||
- type: JAVASCRIPT
|
||||
parameters:
|
||||
- |
|
||||
// Convert raw count to percentage
|
||||
var remaining = parseInt(value, 10);
|
||||
var capacity = 500; // Adjust per consumable
|
||||
return Math.min(100, Math.max(0, (remaining / capacity) * 100));
|
||||
```
|
||||
|
||||
### HP LaserJet - Color (zabbix_template_hp_color)
|
||||
```
|
||||
10.80.92.51, 10.80.92.52, 10.80.92.67
|
||||
```
|
||||
### Zabbix Import Requirements
|
||||
|
||||
### Xerox VersaLink - Color (zabbix_template_xerox_color)
|
||||
```
|
||||
10.80.92.20, 10.80.92.25, 10.80.92.69, 10.80.92.70
|
||||
```
|
||||
- **UUIDs must be valid UUIDv4** - 32 hex characters without dashes
|
||||
- **Triggers must be nested inside items** - Not at the template level
|
||||
- Generate UUIDs with: `python3 -c "import uuid; print(uuid.uuid4().hex)"`
|
||||
|
||||
### Xerox VersaLink - Monochrome (zabbix_template_xerox_mono)
|
||||
```
|
||||
10.80.92.251, 10.80.92.45, 10.80.92.48
|
||||
```
|
||||
## Templates
|
||||
|
||||
### Xerox Enterprise - Color (zabbix_template_xerox_enterprise)
|
||||
```
|
||||
10.80.92.252, 10.80.92.253, 10.80.92.49, 10.80.92.62
|
||||
```
|
||||
| Template | Device | Notes |
|
||||
|----------|--------|-------|
|
||||
| `zabbix_template_hid_dtc4500e.yaml` | HID Fargo DTC4500e Card Printer | YMCKO 500-print ribbon |
|
||||
|
||||
## Technical Details
|
||||
## Related
|
||||
|
||||
### SNMP OIDs Used
|
||||
|
||||
**Standard Printer MIB (RFC 3805):**
|
||||
- Model: `1.3.6.1.2.1.25.3.2.1.3.1`
|
||||
- Supply Description: `1.3.6.1.2.1.43.11.1.1.6.1.X`
|
||||
- Supply Max Capacity: `1.3.6.1.2.1.43.11.1.1.8.1.X`
|
||||
- Supply Current Level: `1.3.6.1.2.1.43.11.1.1.9.1.X`
|
||||
|
||||
**HP Vendor-specific MIB:**
|
||||
- Maintenance Kit: `1.3.6.1.4.1.11.2.3.9.4.2.1.4.1.2.1.X`
|
||||
|
||||
### Alert Thresholds
|
||||
|
||||
- **Warning**: 20% remaining
|
||||
- **High**: 10% remaining
|
||||
|
||||
### Features
|
||||
|
||||
- JavaScript preprocessing for hex-encoded SNMP strings
|
||||
- Calculated items for percentage calculations
|
||||
- Trigger expressions with part number validation
|
||||
- Support for both capacity-based and percentage-based supply levels
|
||||
- Supply compatibility notes in trigger messages for ordering alternatives
|
||||
|
||||
## Scripts
|
||||
|
||||
### analyze_all_printers.py
|
||||
Analyzes all printer CSV files to identify OID patterns and categorize printer models.
|
||||
|
||||
### generate_printer_templates.py
|
||||
Generates all Zabbix templates in YAML and JSON formats. Run this script to regenerate templates if modifications are needed.
|
||||
|
||||
### printer_template_mapping.py
|
||||
Maps each printer IP to its correct template based on model detection. Provides detailed output for manual configuration.
|
||||
|
||||
### check_unknown_printers.py
|
||||
Utility script to analyze printers that don't match existing template patterns.
|
||||
|
||||
## Maintenance
|
||||
|
||||
To update templates:
|
||||
|
||||
1. Modify template configurations in `generate_printer_templates.py`
|
||||
2. Run: `python3 generate_printer_templates.py`
|
||||
3. Re-import updated templates to Zabbix
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### No data from printer
|
||||
|
||||
1. Verify SNMP is enabled on printer
|
||||
2. Check SNMP community string matches `WestJeff2025`
|
||||
3. Verify network connectivity and firewall rules (UDP 161)
|
||||
4. Test with snmpwalk: `snmpwalk -v2c -c WestJeff2025 <printer-ip> 1.3.6.1.2.1.43`
|
||||
|
||||
### Wrong supply levels
|
||||
|
||||
1. Verify correct template is assigned for printer model
|
||||
2. Check OID indices match your printer model
|
||||
3. Export SNMP data: `python3 snmp_export.py <printer-ip>`
|
||||
4. Analyze with: `python3 analyze_all_printers.py`
|
||||
|
||||
### Missing supplies
|
||||
|
||||
Some printer models may have additional supplies not covered by templates. Add custom items based on SNMP export analysis.
|
||||
|
||||
## Supply Compatibility Reference
|
||||
|
||||
When Zabbix triggers alert for low supplies, the trigger message includes a note to check compatibility alternatives. The following consolidations have been verified:
|
||||
|
||||
### HP LaserJet Toner Compatibility
|
||||
|
||||
**CF258A/CF258X (58A/58X)** - HP LaserJet Pro M404n/M406
|
||||
- Both standard (CF258A) and high-yield (CF258X) versions are compatible
|
||||
- Models share identical toner and fuser components
|
||||
|
||||
**CF500A/CF501A/CF502A/CF503A (202A Series)** - HP Color LaserJet M254dw
|
||||
- Black: CF500A (202A Black) - NOT W2020A (414A)
|
||||
- Cyan: CF501A (202A Cyan) - NOT W2021A
|
||||
- Yellow: CF502A (202A Yellow) - NOT W2022A
|
||||
- Magenta: CF503A (202A Magenta) - NOT W2023A
|
||||
|
||||
**CE390A/CE390X (90A/90X)** - HP LaserJet M4555/M602/M603
|
||||
- Standard and high-yield versions compatible across all three models
|
||||
- High consolidation value for fleet management
|
||||
|
||||
**Q5942A/Q5942X (42A/42X)** - HP LaserJet 4250/4350
|
||||
- Both capacities work across model range
|
||||
- Legacy models still in service
|
||||
|
||||
**CE255X (55X)** - HP LaserJet P3015/P3010
|
||||
- Single part number for both models
|
||||
|
||||
### Xerox Toner Compatibility
|
||||
|
||||
**106R03536-39 Series** - Xerox VersaLink C405/C400
|
||||
- Black: 106R03536 (10.5K pages)
|
||||
- Cyan: 106R03537 (10.5K pages)
|
||||
- Magenta: 106R03538 (10.5K pages)
|
||||
- Yellow: 106R03539 (10.5K pages)
|
||||
|
||||
**106R03580-82 Series** - Xerox VersaLink B405/B400
|
||||
- Standard: 106R03580 (5.9K pages)
|
||||
- High-yield: 106R03582 (13.9K pages)
|
||||
- Extra high-yield: 106R03581 (24.6K pages)
|
||||
|
||||
For complete compatibility details and part-specific notes, refer to the `SUPPLY_COMPATIBILITY` dictionary in `generate_printer_templates.py`.
|
||||
|
||||
## Files Structure
|
||||
|
||||
```
|
||||
/home/camp/snmp-scanner/
|
||||
├── README.md # This file
|
||||
├── generate_printer_templates.py # Template generator
|
||||
├── printer_template_mapping.py # IP to template mapper
|
||||
├── analyze_all_printers.py # OID pattern analyzer
|
||||
├── check_unknown_printers.py # Unknown printer analyzer
|
||||
├── zabbix_template_hp_mono.yaml # HP mono template (YAML)
|
||||
├── zabbix_template_hp_mono.json # HP mono template (JSON)
|
||||
├── zabbix_template_hp_color.yaml # HP color template (YAML)
|
||||
├── zabbix_template_hp_color.json # HP color template (JSON)
|
||||
├── zabbix_template_xerox_color.yaml # Xerox VersaLink color (YAML)
|
||||
├── zabbix_template_xerox_color.json # Xerox VersaLink color (JSON)
|
||||
├── zabbix_template_xerox_mono.yaml # Xerox VersaLink mono (YAML)
|
||||
├── zabbix_template_xerox_mono.json # Xerox VersaLink mono (JSON)
|
||||
├── zabbix_template_xerox_enterprise.yaml # Xerox Enterprise (YAML)
|
||||
└── zabbix_template_xerox_enterprise.json # Xerox Enterprise (JSON)
|
||||
|
||||
/home/camp/output/
|
||||
└── printer-*.csv # SNMP exports from printers
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions, review the SNMP exports in `/home/camp/output/` and analyze with the provided Python scripts.
|
||||
- **ShopDB**: `/home/camp/projects/windows/shopdb/`
|
||||
- **Zabbix API integration**: `shopdb/includes/zabbix_all_supplies.asp`
|
||||
- **Display page**: `shopdb/displayprinter.asp`
|
||||
|
||||
@@ -311,35 +311,45 @@ zabbix_export:
|
||||
value: performance
|
||||
|
||||
- uuid: cc5821dc024f47b49ea1a75062d8a479
|
||||
name: Ribbon Remaining
|
||||
name: Ribbon Level
|
||||
type: SNMP_AGENT
|
||||
snmp_oid: 'get[1.3.6.1.4.1.28959.3.255.1.16.0]'
|
||||
key: hid.ribbon.remaining
|
||||
key: hid.ribbon.level
|
||||
delay: 5m
|
||||
history: 90d
|
||||
trends: 365d
|
||||
value_type: UNSIGNED
|
||||
units: prints
|
||||
description: 'Ribbon remaining count (estimated prints left)'
|
||||
value_type: FLOAT
|
||||
units: '%'
|
||||
description: 'Ribbon level as percentage (based on 500-print YMCKO ribbon capacity)'
|
||||
tags:
|
||||
- tag: component
|
||||
value: supplies
|
||||
- tag: type
|
||||
value: consumable
|
||||
preprocessing:
|
||||
- type: JAVASCRIPT
|
||||
parameters:
|
||||
- |
|
||||
// Convert raw print count to percentage
|
||||
// YMCKO ribbon capacity: 500 prints
|
||||
var remaining = parseInt(value, 10);
|
||||
if (isNaN(remaining)) return 0;
|
||||
var percent = (remaining / 500) * 100;
|
||||
return Math.min(100, Math.max(0, percent.toFixed(1)));
|
||||
triggers:
|
||||
- uuid: 0b6570b2126544579ca5e3bfd3569574
|
||||
expression: 'last(/HID Fargo DTC4500e Card Printer/hid.ribbon.remaining)<75'
|
||||
name: 'HID DTC4500e: Ribbon low on {HOST.NAME} (less than 75 prints remaining)'
|
||||
expression: 'last(/HID Fargo DTC4500e Card Printer/hid.ribbon.level)<15'
|
||||
name: 'HID DTC4500e: Ribbon low on {HOST.NAME}'
|
||||
priority: WARNING
|
||||
description: 'Ribbon is running low, less than 75 prints remaining'
|
||||
description: 'Ribbon is running low (less than 15%)'
|
||||
tags:
|
||||
- tag: scope
|
||||
value: capacity
|
||||
- uuid: 7e580066c3cd4a42bfe90092e7485f8c
|
||||
expression: 'last(/HID Fargo DTC4500e Card Printer/hid.ribbon.remaining)<25'
|
||||
name: 'HID DTC4500e: Ribbon critically low on {HOST.NAME} (less than 25 prints remaining)'
|
||||
expression: 'last(/HID Fargo DTC4500e Card Printer/hid.ribbon.level)<5'
|
||||
name: 'HID DTC4500e: Ribbon critically low on {HOST.NAME}'
|
||||
priority: HIGH
|
||||
description: 'Ribbon is critically low, less than 25 prints remaining'
|
||||
description: 'Ribbon is critically low (less than 5%)'
|
||||
tags:
|
||||
- tag: scope
|
||||
value: capacity
|
||||
@@ -361,58 +371,7 @@ zabbix_export:
|
||||
- tag: type
|
||||
value: error
|
||||
|
||||
- uuid: 28697e8eae8c4264a5eca54ce37b2fe3
|
||||
name: Card Count in Hopper
|
||||
type: SNMP_AGENT
|
||||
snmp_oid: 'get[1.3.6.1.4.1.28959.3.255.1.13.0]'
|
||||
key: hid.hopper.count
|
||||
delay: 5m
|
||||
history: 90d
|
||||
trends: 365d
|
||||
value_type: UNSIGNED
|
||||
units: cards
|
||||
description: 'Estimated cards remaining in input hopper'
|
||||
tags:
|
||||
- tag: component
|
||||
value: supplies
|
||||
- tag: type
|
||||
value: consumable
|
||||
|
||||
# === Derived Items from Status Flags ===
|
||||
- uuid: fd33474b04714f3db64ea94930ba8593
|
||||
name: Door/Hopper Status
|
||||
type: DEPENDENT
|
||||
key: hid.status.door
|
||||
delay: '0'
|
||||
history: 90d
|
||||
trends: '0'
|
||||
value_type: UNSIGNED
|
||||
description: 'Door/Hopper status extracted from flags (0=Closed/OK, 1=Open/Warning)'
|
||||
master_item:
|
||||
key: hid.status.flags
|
||||
tags:
|
||||
- tag: component
|
||||
value: printer
|
||||
- tag: type
|
||||
value: status
|
||||
preprocessing:
|
||||
- type: JAVASCRIPT
|
||||
parameters:
|
||||
- |
|
||||
var match = value.match(/DH:(\d)/);
|
||||
return match ? match[1] : '0';
|
||||
valuemap:
|
||||
name: HID Door Status
|
||||
triggers:
|
||||
- uuid: eaddab3ea34e443fbce891ca79ec9c34
|
||||
expression: 'last(/HID Fargo DTC4500e Card Printer/hid.status.door)=1'
|
||||
name: 'HID DTC4500e: Door/Hopper open on {HOST.NAME}'
|
||||
priority: WARNING
|
||||
description: 'Printer door or hopper is open'
|
||||
tags:
|
||||
- tag: scope
|
||||
value: notice
|
||||
|
||||
- uuid: 9b4cd42ecb274382b8e6092f9d8b18f5
|
||||
name: Film/Ribbon Loaded
|
||||
type: DEPENDENT
|
||||
@@ -499,14 +458,6 @@ zabbix_export:
|
||||
- value: '5'
|
||||
newvalue: Error
|
||||
|
||||
- uuid: d17dea90ecae4ecba0e5bbc4ac3e9b51
|
||||
name: HID Door Status
|
||||
mappings:
|
||||
- value: '0'
|
||||
newvalue: Closed
|
||||
- value: '1'
|
||||
newvalue: Open
|
||||
|
||||
- uuid: 6ec97e9591b64510a0b65e27b7c5c601
|
||||
name: HID Film Status
|
||||
mappings:
|
||||
|
||||
Reference in New Issue
Block a user