ckt1031 / one-api

OpenAI 接口管理 & 分发系统,支持多种渠道包括 Azure,可用于二次分发管理 key,仅单可执行文件,已打包好 Docker 镜像,一键部署,开箱即用. OpenAI key management & redistribution system, supports English UI.
https://openai.justsong.cn/
MIT License
29 stars 15 forks source link

Adding whitelists based on discord community roles #5

Closed neurogen-dev closed 8 months ago

neurogen-dev commented 9 months ago

例行检查

功能描述

It would be great to add support for whitelisting via discord based on roles in the community.

Such a system is actively used in game servers and works well. In our case, whitelists would allow us to filter out unwanted registrations (multi-accounts) thanks to various discord tools like Doble Counter, and in theory implement synchronization with groups within one-api.

Unfortunately, current oauth2 implementations do not prevent users from creating multi-accounts in any way.

Examples:

https://github.com/FAXES/DiscordWhitelist

https://github.com/Stuyk/altv-discord-auth

应用场景 The introduction of whitelists via Discord will allow for better moderation of registered users.

Stronger protection against abuse of registrations, compared to oauth2.

It will be possible to manage groups through synchronization with Discord community roles

ckt1031 commented 8 months ago

Role whitelisting? If so, this will require an actual discord bot for watching the server.

neurogen-dev commented 8 months ago

Role whitelisting? If so, this will require an actual discord bot for watching the server.

Yes, I understand, we would need to create a Discord Bot, invite it to the server, give it the right permissions and get its token.

With support ChatGPT I wrote a simple Python script that implements something like this by just making edits to the MySQL database, but I think native support would be more efficient.

import discord
import mysql.connector
import os
from collections import Counter
from discord.ext import commands, tasks
from dotenv import load_dotenv

load_dotenv()

# Загрузка переменных окружения
DISCORD_BOT_TOKEN = os.getenv('DISCORD_BOT_TOKEN', '')
DB_HOST = os.getenv('DB_HOST', '')
DB_USER = os.getenv('DB_USER', '')
DB_PASSWORD = os.getenv('DB_PASSWORD', '')
DB_NAME = os.getenv('DB_NAME', '')

# Сопоставление ролей Discord с группами в базе данных
ROLE_GROUP_MAPPING = {
    'Resident': 'verified',
    'Booster / Tier 1': 'tier_1',
    'Booster / Tier 2': 'tier_2',
    'Booster / Tier 3': 'tier_3'
}

# Настройка Discord клиента
intents = discord.Intents.default()
intents.members = True

bot = commands.Bot(command_prefix='!', intents=intents)

@tasks.loop(seconds=30)
async def sync_user_groups():
    print("Starting user group sync...")
    total_users_updated = 0
    role_counter = Counter()

    for guild in bot.guilds:
        print(f"Syncing for guild: {guild.name}")
        async for member in guild.fetch_members():
            # Пропускаем ботов
            if member.bot:
                print(f"Skipping bot: {member.name}")
                continue

            # Получаем наивысшую роль пользователя
            highest_role = next((role.name for role in sorted(member.roles, key=lambda r: r.position, reverse=True) if role.name in ROLE_GROUP_MAPPING), None)

            # Если роль найдена, обновляем группу пользователя в базе данных
            if highest_role:
                print(f"Updating user: {member.name} to group: {ROLE_GROUP_MAPPING[highest_role]}")
                total_users_updated += 1
                role_counter[highest_role] += 1
                await update_user_group(member.id, ROLE_GROUP_MAPPING[highest_role])
    print("Finished user group sync.")
    print(f"Total users updated: {total_users_updated}")
    print("Role update statistics:")
    for role, count in role_counter.items():
        print(f"{role}: {count}")

async def update_user_group(discord_id, new_group):
    connection = mysql.connector.connect(
        host=DB_HOST,
        user=DB_USER,
        password=DB_PASSWORD,
        database=DB_NAME
    )
    cursor = connection.cursor()
    query = "UPDATE users SET `group` = %s WHERE discord_id = %s"

    try:
        print(f"Executing update for user: {discord_id} with group: {new_group}")
        cursor.execute(query, (new_group, str(discord_id)))
        connection.commit()
        print(f"Update successful for user: {discord_id}")
    except mysql.connector.Error as err:
        print(f"Error: {err}")
    finally:
        cursor.close()
        connection.close()

@bot.event
async def on_ready():
    print(f'Bot has started with username: {bot.user.name}')
    print("Loop task 'sync_user_groups' is starting...")
    await sync_user_groups.start()

if __name__ == "__main__":
    print("Bot is connecting...")
    bot.run(DISCORD_BOT_TOKEN)
ckt1031 commented 8 months ago

Completed.