Compare commits

..

2 Commits

Author SHA1 Message Date
SkyJoshua
f9a45ac980 Merge pull request #2 from SkyJoshua/Dev
readme and privacy
2026-03-11 01:45:05 +00:00
SkyJoshua
56cb78c854 Merge pull request #1 from SkyJoshua/Dev
Dev
2026-03-11 01:24:57 +00:00
4 changed files with 240 additions and 126 deletions

View File

@@ -8,7 +8,7 @@ public static class SourceCommand
{ {
if (channelCache.TryGetValue(channelId, out var channel)) if (channelCache.TryGetValue(channelId, out var channel))
{ {
await channel.SendMessageAsync($"{memberPing} You can see my source code here: https://git.skyjoshua.xyz/SkyJoshua/Reactor"); await channel.SendMessageAsync($"{memberPing} You can see my source code here: https://github.com/SkyJoshua/Reactor");
} }
} }
} }

View File

@@ -1,101 +1,151 @@
# Privacy Policy <!DOCTYPE html>
<html lang="en">
<body>
**Effective Date:** March 11, 2026 <h1>Privacy Policy</h1>
This Privacy Policy describes how Reactor collects, uses, and stores information when used within a Valour server. <p><strong>Effective Date:</strong> March 11, 2026</p>
--- <p>
This Privacy Policy describes how Reactor collects, uses,
and stores information when used within a Valour server.
</p>
## 1. Information Collected <hr>
<h2>1. Information Collected</h2>
<p>
Reactor collects only the minimum data required to function. Reactor collects only the minimum data required to function.
</p>
### Information Stored (Persisted to Disk) <h3>Information Stored (Persisted to Disk)</h3>
<ul>
<li>Planet IDs</li>
<li>Channel IDs</li>
<li>Message IDs of reaction role messages</li>
<li>Emoji-to-role mappings</li>
<li>Confirmation message delete delay settings</li>
</ul>
- Planet IDs <h3>Information Not Stored</h3>
- Channel IDs <ul>
- Message IDs of reaction role messages <li>Message content (beyond the initial reaction message text provided by the administrator)</li>
- Emoji-to-role mappings <li>User IDs (beyond what is transiently used to assign or remove roles during a reaction event)</li>
- Confirmation message delete delay settings <li>Direct Messages (DMs)</li>
<li>User credentials</li>
<li>Email addresses</li>
<li>Passwords</li>
<li>IP addresses</li>
<li>Analytics or tracking data</li>
</ul>
### Information Not Stored <hr>
- Message content (beyond the initial reaction message text provided by the administrator) <h2>2. Purpose of Data Collection</h2>
- User IDs (beyond what is transiently used to assign or remove roles during a reaction event)
- Direct Messages (DMs)
- User credentials
- Email addresses
- Passwords
- IP addresses
- Analytics or tracking data
--- <p>Stored information is used exclusively to:</p>
## 2. Purpose of Data Collection <ol>
<li>Track which messages are configured as reaction role messages</li>
Stored information is used exclusively to: <li>Map emoji reactions to planet roles</li>
<li>Assign or remove roles from members when they react or unreact to a tracked message</li>
1. Track which messages are configured as reaction role messages <li>Automatically clean up stale data when messages are deleted</li>
2. Map emoji reactions to planet roles </ol>
3. Assign or remove roles from members when they react or unreact to a tracked message
4. Automatically clean up stale data when messages are deleted
<p>
Data is not used for marketing, advertising, profiling, or analytics. Data is not used for marketing, advertising, profiling, or analytics.
</p>
--- <hr>
## 3. Data Storage and Security <h2>3. Data Storage and Security</h2>
All data is stored in a local SQLite database file (`reactor.db`) on the hosting server. <p>
All data is stored in a local SQLite database file (<code>reactor.db</code>) on the hosting server.
</p>
The operator of the self-hosted instance is responsible for securing the hosting environment and the database file. <p>
The operator of the self-hosted instance is responsible for securing the hosting environment
and the database file.
</p>
<p>
Stale or deleted reaction messages are automatically removed from the database on bot startup. Stale or deleted reaction messages are automatically removed from the database on bot startup.
</p>
--- <hr>
## 4. Third-Party Processing <h2>4. Third-Party Processing</h2>
Reactor does not transmit any data to external services beyond the Valour.gg API, which is required for core bot functionality such as assigning roles and sending messages. <p>
Reactor does not transmit any data to external services beyond the Valour.gg API,
which is required for core bot functionality such as assigning roles and sending messages.
</p>
<p>
Reactor does not use any external AI providers, analytics services, or cloud storage. Reactor does not use any external AI providers, analytics services, or cloud storage.
</p>
--- <hr>
## 5. Data Retention <h2>5. Data Retention</h2>
<p>
Reaction role message data is retained in the SQLite database until: Reaction role message data is retained in the SQLite database until:
</p>
- The reaction message is deleted from Valour (automatic cleanup on bot startup) <ul>
- An administrator runs the `r.delete` command <li>The reaction message is deleted from Valour (automatic cleanup on bot startup)</li>
- The database file is manually deleted by the host operator <li>An administrator runs the <code>r.delete</code> command</li>
<li>The database file is manually deleted by the host operator</li>
</ul>
--- <hr>
## 6. Self-Hosted Responsibility <h2>6. Self-Hosted Responsibility</h2>
<p>
Reactor is designed for self-hosting. Reactor is designed for self-hosting.
</p>
<p>
The hosting operator is responsible for: The hosting operator is responsible for:
</p>
- Server security <ul>
- Network configuration <li>Server security</li>
- Bot token protection <li>Network configuration</li>
- Database file security <li>Bot token protection</li>
- Compliance with applicable laws <li>Database file security</li>
<li>Compliance with applicable laws</li>
</ul>
--- <hr>
## 7. Changes to This Policy <h2>7. Changes to This Policy</h2>
If data collection practices change in future versions, this Privacy Policy will be updated prior to implementation. <p>
If data collection practices change in future versions,
this Privacy Policy will be updated prior to implementation.
</p>
Continued use of the Bot after updates constitutes acceptance of the revised policy. <p>
Continued use of the Bot after updates constitutes acceptance
of the revised policy.
</p>
--- <hr>
## 8. Contact Information <h2>8. Contact Information</h2>
<p>
For privacy-related inquiries: For privacy-related inquiries:
</p>
<p>
Email: contact@skyjoshua.xyz Email: contact@skyjoshua.xyz
</p>
</body>
</html>

200
README.md
View File

@@ -1,102 +1,166 @@
# Reactor <!DOCTYPE html>
<html lang="en">
<body>
Reactor is a Valour.gg bot that enables server administrators to create reaction role messages. Users can react to a message with an emoji to automatically be assigned or removed from a role. <h1>Reactor</h1>
--- <p>
Reactor is a Valour.gg bot that enables server administrators to create reaction role messages.
Users can react to a message with an emoji to automatically be assigned or removed from a role.
</p>
## Features <hr>
- Create reaction role messages in any planet channel <h2>Features</h2>
- Map emojis to roles — reacting adds the role, removing the reaction removes it <ul>
- Automatic cleanup of deleted reaction messages from the database <li>Create reaction role messages in any planet channel</li>
- Persistent storage via SQLite — survives bot restarts <li>Map emojis to roles — reacting adds the role, removing the reaction removes it</li>
- Permission-based command access (Manage Roles or Full Control required) <li>Automatic cleanup of deleted reaction messages from the database</li>
- Built with .NET and the Valour SDK <li>Persistent storage via SQLite — survives bot restarts</li>
- Open-source under AGPL-3.0 <li>Permission-based command access (Manage Roles or Full Control required)</li>
<li>Built with .NET and the Valour SDK</li>
<li>Open-source under AGPL-3.0</li>
</ul>
--- <hr>
## How It Works <h2>How It Works</h2>
<p>Reactor connects to the Valour.gg API and listens for reactions on configured messages.</p>
<ul>
<li>Reaction role messages and their emoji-to-role mappings are stored in a local SQLite database</li>
<li>When a user reacts to a tracked message, Reactor assigns the mapped role</li>
<li>When a user removes their reaction, Reactor removes the mapped role</li>
<li>Stale messages (deleted from Valour) are automatically pruned from the database on startup</li>
</ul>
Reactor connects to the Valour.gg API and listens for reactions on configured messages. <hr>
- Reaction role messages and their emoji-to-role mappings are stored in a local SQLite database <h2>Requirements</h2>
- When a user reacts to a tracked message, Reactor assigns the mapped role <ul>
- When a user removes their reaction, Reactor removes the mapped role <li>.NET 10+</li>
- Stale messages (deleted from Valour) are automatically pruned from the database on startup <li>Valid Valour bot token</li>
</ul>
--- <hr>
## Requirements <h2>Installation</h2>
- .NET 10+ <pre><code>fork the project
- Valid Valour bot token git clone https://github.com/YOUR_USERNAME/Reactor.git
---
## Installation
```bash
git clone https://git.skyjoshua.xyz/SkyJoshua/Reactor.git
cd Reactor cd Reactor
dotnet restore dotnet restore</code></pre>
```
All required NuGet packages are installed automatically via the `.csproj` file. <p>
All required NuGet packages are installed automatically via the <code>.csproj</code> file.
</p>
--- <hr>
## Configuration <h2>Configuration</h2>
Create a `.env` file in the root directory: <p>Create a <code>.env</code> file in the root directory:</p>
```
TOKEN=your-valour-bot-token
```
<pre><code>TOKEN=your-valour-bot-token</code></pre>
<p>
Do not commit this file to version control. Do not commit this file to version control.
</p>
--- <hr>
## Running the Bot <h2>Running the Bot</h2>
```bash
dotnet run
```
--- <pre><code>dotnet run</code></pre>
## Commands <hr>
All commands require **Manage Roles** or **Full Control** permissions, except `r.help` and `r.source`. <h2>Commands</h2>
| Command | Description | <p>All commands require <strong>Manage Roles</strong> or <strong>Full Control</strong> permissions, except <code>r.help</code> and <code>r.source</code>.</p>
|---|---|
| `r.help` | Shows the list of available commands |
| `r.source` | Shows the source code of the bot |
| `r.create <message text>` | Creates a new reaction role message in the current channel |
| `r.add <messageId> <emoji> <roleId>` | Maps an emoji to a role on a reaction message |
| `r.remove <messageId> <emoji>` | Removes an emoji-to-role mapping from a reaction message |
| `r.delete <messageId>` | Deletes a reaction message and all its role mappings |
--- <table border="1" cellpadding="6">
<tr>
<th>Command</th>
<th>Description</th>
</tr>
<tr>
<td><code>r.help</code></td>
<td>Shows the list of available commands</td>
</tr>
<tr>
<td><code>r.source</code></td>
<td>Shows the source code of the bot</td>
</tr>
<tr>
<td><code>r.create &lt;message text&gt;</code></td>
<td>Creates a new reaction role message in the current channel</td>
</tr>
<tr>
<td><code>r.add &lt;messageId&gt; &lt;emoji&gt; &lt;roleId&gt;</code></td>
<td>Maps an emoji to a role on a reaction message</td>
</tr>
<tr>
<td><code>r.remove &lt;messageId&gt; &lt;emoji&gt;</code></td>
<td>Removes an emoji-to-role mapping from a reaction message</td>
</tr>
<tr>
<td><code>r.delete &lt;messageId&gt;</code></td>
<td>Deletes a reaction message and all its role mappings</td>
</tr>
</table>
## Data Storage <hr>
Reactor stores the following data in a local SQLite database (`reactor.db`): <h2>Data Storage</h2>
- Reaction message IDs, channel IDs, and planet IDs <p>Reactor stores the following data in a local SQLite database (<code>reactor.db</code>):</p>
- Emoji-to-role mappings per reaction message <ul>
- Configurable delete delay for confirmation messages (default: 5 seconds) <li>Reaction message IDs, channel IDs, and planet IDs</li>
<li>Emoji-to-role mappings per reaction message</li>
<li>Configurable delete delay for confirmation messages (default: 5 seconds)</li>
</ul>
Full privacy policy: <p>
https://git.skyjoshua.xyz/SkyJoshua/Reactor/blob/main/PRIVACY.md Full privacy policy:<br>
<a href="https://github.com/SkyJoshua/Reactor/blob/main/PRIVACY.md">
https://github.com/SkyJoshua/Reactor/blob/main/PRIVACY.md
</a>
</p>
--- <hr>
## License <h2>License</h2>
<p>
This project is licensed under the
<strong>GNU Affero General Public License v3.0 (AGPL-3.0)</strong>.
</p>
This project is licensed under the **GNU Affero General Public License v3.0 (AGPL-3.0)**. <p>
See the LICENSE file for details:<br>
<a href="https://github.com/SkyJoshua/Reactor/blob/main/LICENSE">
https://github.com/SkyJoshua/Reactor/blob/main/LICENSE
</a>
</p>
See the LICENSE file for details: <p>
https://git.skyjoshua.xyz/SkyJoshua/Reactor/blob/main/LICENSE If you modify and deploy this project publicly (including as a hosted service),
you must make your source code available under the same AGPL-3.0 license.
</p>
If you modify and deploy this project publicly (including as a hosted service), you must make your source code available under the same AGPL-3.0 license. <hr>
<h2>Contributing</h2>
<p>
Contributions are welcome. By submitting a contribution, you agree that your
contributions will be licensed under AGPL-3.0.
</p>
<ol>
<li>Fork the repository</li>
<li>Create a feature branch</li>
<li>Submit a pull request</li>
</ol>
</body>
</html>

View File

@@ -25,7 +25,7 @@ namespace Reactor.Services
var member = await message.FetchAuthorMemberAsync(); var member = await message.FetchAuthorMemberAsync();
string memberPing = member != null ? $"«@m-{member.Id}»" : ""; string memberPing = member != null ? $"«@m-{member.Id}»" : "";
bool hasPermission = await HasPermissionAsync(member); bool hasPermission = await HasPermissionAsync(member, channelCache[channelId]);
string withoutPrefix = content.Substring(prefix.Length); string withoutPrefix = content.Substring(prefix.Length);
@@ -150,7 +150,7 @@ namespace Reactor.Services
} }
} }
private static async Task<bool> HasPermissionAsync(PlanetMember member) private static async Task<bool> HasPermissionAsync(PlanetMember member, Channel channel)
{ {
if (member == null) return false; if (member == null) return false;