Update dashboard and Docker compose
Some checks failed
CI/CD Pipeline / Security Scanning (push) Has been cancelled
CI/CD Pipeline / Tests (3.11) (push) Has been cancelled
CI/CD Pipeline / Tests (3.12) (push) Has been cancelled
CI/CD Pipeline / Build Docker Image (push) Has been cancelled
CI/CD Pipeline / Code Quality Checks (push) Has been cancelled
Some checks failed
CI/CD Pipeline / Security Scanning (push) Has been cancelled
CI/CD Pipeline / Tests (3.11) (push) Has been cancelled
CI/CD Pipeline / Tests (3.12) (push) Has been cancelled
CI/CD Pipeline / Build Docker Image (push) Has been cancelled
CI/CD Pipeline / Code Quality Checks (push) Has been cancelled
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
from collections.abc import AsyncIterator
|
||||
|
||||
from fastapi import APIRouter, Depends, Query, Request
|
||||
from sqlalchemy import func, select
|
||||
from sqlalchemy import func, or_, select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from guardden.dashboard.auth import require_owner
|
||||
@@ -27,7 +27,9 @@ def create_api_router(
|
||||
def require_owner_dep(request: Request) -> None:
|
||||
require_owner(settings, request)
|
||||
|
||||
@router.get("/guilds", response_model=list[GuildSummary], dependencies=[Depends(require_owner_dep)])
|
||||
@router.get(
|
||||
"/guilds", response_model=list[GuildSummary], dependencies=[Depends(require_owner_dep)]
|
||||
)
|
||||
async def list_guilds(
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> list[GuildSummary]:
|
||||
@@ -47,6 +49,9 @@ def create_api_router(
|
||||
guild_id: int | None = Query(default=None),
|
||||
limit: int = Query(default=50, ge=1, le=200),
|
||||
offset: int = Query(default=0, ge=0),
|
||||
action: str | None = Query(default=None),
|
||||
message_only: bool = Query(default=False),
|
||||
search: str | None = Query(default=None),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> PaginatedLogs:
|
||||
query = select(ModerationLog)
|
||||
@@ -55,6 +60,25 @@ def create_api_router(
|
||||
query = query.where(ModerationLog.guild_id == guild_id)
|
||||
count_query = count_query.where(ModerationLog.guild_id == guild_id)
|
||||
|
||||
if action:
|
||||
query = query.where(ModerationLog.action == action)
|
||||
count_query = count_query.where(ModerationLog.action == action)
|
||||
|
||||
if message_only:
|
||||
query = query.where(ModerationLog.message_content.is_not(None))
|
||||
count_query = count_query.where(ModerationLog.message_content.is_not(None))
|
||||
|
||||
if search:
|
||||
like = f"%{search}%"
|
||||
search_filter = or_(
|
||||
ModerationLog.target_name.ilike(like),
|
||||
ModerationLog.moderator_name.ilike(like),
|
||||
ModerationLog.reason.ilike(like),
|
||||
ModerationLog.message_content.ilike(like),
|
||||
)
|
||||
query = query.where(search_filter)
|
||||
count_query = count_query.where(search_filter)
|
||||
|
||||
query = query.order_by(ModerationLog.created_at.desc()).offset(offset).limit(limit)
|
||||
total_result = await session.execute(count_query)
|
||||
total = int(total_result.scalar() or 0)
|
||||
|
||||
@@ -71,6 +71,8 @@ class AnalyticsSummary(BaseModel):
|
||||
|
||||
# User Management Schemas
|
||||
class UserProfile(BaseModel):
|
||||
guild_id: int
|
||||
guild_name: str
|
||||
user_id: int
|
||||
username: str
|
||||
strike_count: int
|
||||
|
||||
@@ -11,7 +11,7 @@ from guardden.dashboard.auth import require_owner
|
||||
from guardden.dashboard.config import DashboardSettings
|
||||
from guardden.dashboard.db import DashboardDatabase
|
||||
from guardden.dashboard.schemas import CreateUserNote, UserNote, UserProfile
|
||||
from guardden.models import ModerationLog, UserActivity
|
||||
from guardden.models import Guild, ModerationLog, UserActivity
|
||||
from guardden.models import UserNote as UserNoteModel
|
||||
|
||||
|
||||
@@ -35,14 +35,16 @@ def create_users_router(
|
||||
dependencies=[Depends(require_owner_dep)],
|
||||
)
|
||||
async def search_users(
|
||||
guild_id: int = Query(...),
|
||||
guild_id: int | None = Query(default=None),
|
||||
username: str | None = Query(default=None),
|
||||
min_strikes: int | None = Query(default=None, ge=0),
|
||||
limit: int = Query(default=50, ge=1, le=200),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> list[UserProfile]:
|
||||
"""Search for users in a guild with optional filters."""
|
||||
query = select(UserActivity).where(UserActivity.guild_id == guild_id)
|
||||
"""Search for users with optional guild and filter parameters."""
|
||||
query = select(UserActivity, Guild.name).join(Guild, Guild.id == UserActivity.guild_id)
|
||||
if guild_id:
|
||||
query = query.where(UserActivity.guild_id == guild_id)
|
||||
|
||||
if username:
|
||||
query = query.where(UserActivity.username.ilike(f"%{username}%"))
|
||||
@@ -53,14 +55,14 @@ def create_users_router(
|
||||
query = query.order_by(UserActivity.last_seen.desc()).limit(limit)
|
||||
|
||||
result = await session.execute(query)
|
||||
users = result.scalars().all()
|
||||
users = result.all()
|
||||
|
||||
# Get last moderation action for each user
|
||||
profiles = []
|
||||
for user in users:
|
||||
for user, guild_name in users:
|
||||
last_action_query = (
|
||||
select(ModerationLog.created_at)
|
||||
.where(ModerationLog.guild_id == guild_id)
|
||||
.where(ModerationLog.guild_id == user.guild_id)
|
||||
.where(ModerationLog.target_id == user.user_id)
|
||||
.order_by(ModerationLog.created_at.desc())
|
||||
.limit(1)
|
||||
@@ -70,6 +72,8 @@ def create_users_router(
|
||||
|
||||
profiles.append(
|
||||
UserProfile(
|
||||
guild_id=user.guild_id,
|
||||
guild_name=guild_name,
|
||||
user_id=user.user_id,
|
||||
username=user.username,
|
||||
strike_count=user.strike_count,
|
||||
@@ -96,19 +100,21 @@ def create_users_router(
|
||||
) -> UserProfile:
|
||||
"""Get detailed profile for a specific user."""
|
||||
query = (
|
||||
select(UserActivity)
|
||||
select(UserActivity, Guild.name)
|
||||
.join(Guild, Guild.id == UserActivity.guild_id)
|
||||
.where(UserActivity.guild_id == guild_id)
|
||||
.where(UserActivity.user_id == user_id)
|
||||
)
|
||||
|
||||
result = await session.execute(query)
|
||||
user = result.scalar_one_or_none()
|
||||
row = result.one_or_none()
|
||||
|
||||
if not user:
|
||||
if not row:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="User not found in this guild",
|
||||
)
|
||||
user, guild_name = row
|
||||
|
||||
# Get last moderation action
|
||||
last_action_query = (
|
||||
@@ -122,6 +128,8 @@ def create_users_router(
|
||||
last_action = last_action_result.scalar()
|
||||
|
||||
return UserProfile(
|
||||
guild_id=user.guild_id,
|
||||
guild_name=guild_name,
|
||||
user_id=user.user_id,
|
||||
username=user.username,
|
||||
strike_count=user.strike_count,
|
||||
|
||||
Reference in New Issue
Block a user