Skip to content

Commit

Permalink
Add soft deletion
Browse files Browse the repository at this point in the history
  • Loading branch information
flaree committed Feb 20, 2025
1 parent 2af8bc7 commit 4e3634a
Show file tree
Hide file tree
Showing 11 changed files with 52 additions and 15 deletions.
2 changes: 1 addition & 1 deletion admin_panel/bd_models/admin/ball_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class BallInstanceAdmin(admin.ModelAdmin):
),
]

list_display = ("description", "ball__country", "player", "health_bonus", "attack_bonus")
list_display = ("description", "ball__country", "player", "health_bonus", "attack_bonus", "deleted")
list_select_related = ("ball", "special", "player")
list_filter = (SpecialFilter, BallFilter, PlayerFilter, "tradeable", "favorite")
show_facets = admin.ShowFacets.NEVER # hide filtered counts (considerable slowdown)
Expand Down
18 changes: 18 additions & 0 deletions admin_panel/bd_models/migrations/0006_ball_deleted.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.1.4 on 2025-02-20 12:05

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('bd_models', '0005_alter_ball_short_name'),
]

operations = [
migrations.AddField(
model_name='ball',
name='deleted',
field=models.BooleanField(default=False),
),
]
1 change: 1 addition & 0 deletions admin_panel/bd_models/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ class Ball(models.Model):
regime_id: int
created_at = models.DateTimeField(blank=True, null=True, auto_now_add=True, editable=False)
translations = models.TextField(blank=True, null=True)
deleted = models.BooleanField(default=False)

def __str__(self) -> str:
return self.country
Expand Down
1 change: 1 addition & 0 deletions ballsdex/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ class BallInstance(models.Model):
null=True,
default=None,
)
deleted = fields.BooleanField(default=False)
extra_data = fields.JSONField(default={})

class Meta:
Expand Down
2 changes: 1 addition & 1 deletion ballsdex/core/utils/transformers.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ async def validate(self, interaction: discord.Interaction["BallsDexBot"], item:
async def get_options(
self, interaction: Interaction["BallsDexBot"], value: str
) -> list[app_commands.Choice[int]]:
balls_queryset = BallInstance.filter(player__discord_id=interaction.user.id)
balls_queryset = BallInstance.filter(player__discord_id=interaction.user.id, deleted=False)

if (special := getattr(interaction.namespace, "special", None)) and special.isdigit():
balls_queryset = balls_queryset.filter(special_id=int(special))
Expand Down
18 changes: 14 additions & 4 deletions ballsdex/packages/admin/balls.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ async def balls_reset(
interaction: discord.Interaction[BallsDexBot],
user: discord.User,
percentage: int | None = None,
hard_delete: bool = False,
):
"""
Reset a player's countryballs.
Expand All @@ -389,6 +390,8 @@ async def balls_reset(
The user you want to reset the countryballs of.
percentage: int | None
The percentage of countryballs to delete, if not all. Used for sanctions.
hard_delete: bool
If true, the countryballs will be permanently deleted.
"""
player = await Player.get_or_none(discord_id=user.id)
if not player:
Expand Down Expand Up @@ -424,13 +427,20 @@ async def balls_reset(
if not view.value:
return
if percentage:
balls = await BallInstance.filter(player=player)
balls = await BallInstance.filter(player=player, deleted=False)
to_delete = random.sample(balls, int(len(balls) * (percentage / 100)))
for ball in to_delete:
await ball.delete()
if hard_delete:
await ball.delete()
else:
ball.deleted = True
await ball.save()
count = len(to_delete)
else:
count = await BallInstance.filter(player=player).delete()
if hard_delete:
count = await BallInstance.filter(player=player).delete()
else:
count = await BallInstance.filter(player=player).update(deleted=True)
await interaction.followup.send(
f"{count} {settings.plural_collectible_name} from {user} have been deleted.",
ephemeral=True,
Expand Down Expand Up @@ -462,7 +472,7 @@ async def balls_count(
"""
if interaction.response.is_done():
return
filters = {}
filters = {"deleted": False}
if countryball:
filters["ball"] = countryball
if special:
Expand Down
4 changes: 3 additions & 1 deletion ballsdex/packages/admin/info.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ async def guild(
total_server_balls = await BallInstance.filter(
catch_date__gte=datetime.datetime.now() - datetime.timedelta(days=days),
server_id=guild.id,
deleted=False,
).prefetch_related("player")
if guild.owner_id:
owner = await interaction.client.fetch_user(guild.owner_id)
Expand Down Expand Up @@ -128,6 +129,7 @@ async def user(
total_user_balls = await BallInstance.filter(
catch_date__gte=datetime.datetime.now() - datetime.timedelta(days=days),
player=player,
deleted=False,
)
embed = discord.Embed(
title=f"{user} ({user.id})",
Expand All @@ -154,7 +156,7 @@ async def user(
)
embed.add_field(
name=f"Total {settings.plural_collectible_name} caught:",
value=await BallInstance.filter(player__discord_id=user.id).count(),
value=await BallInstance.filter(player__discord_id=user.id, deleted=False).count(),
)
embed.add_field(
name=f"Total unique {settings.plural_collectible_name} caught:",
Expand Down
6 changes: 3 additions & 3 deletions ballsdex/packages/balls/cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ async def completion(
bot_countryballs = {x: y.emoji_id for x, y in balls.items() if y.enabled}

# Set of ball IDs owned by the player
filters = {"player__discord_id": user_obj.id, "ball__enabled": True}
filters = {"player__discord_id": user_obj.id, "ball__enabled": True, "deleted": False}
if special:
filters["special"] = special
bot_countryballs = {
Expand Down Expand Up @@ -647,7 +647,7 @@ async def count(
return

assert interaction.guild
filters = {}
filters = {"deleted": False}
if countryball:
filters["ball"] = countryball
if special:
Expand Down Expand Up @@ -687,7 +687,7 @@ async def duplicate(
player, _ = await Player.get_or_create(discord_id=interaction.user.id)
await player.fetch_related("balls")
is_special = type.value == "specials"
queryset = BallInstance.filter(player=player)
queryset = BallInstance.filter(player=player, deleted=False)

if is_special:
queryset = queryset.filter(special_id__isnull=False).prefetch_related("special")
Expand Down
4 changes: 3 additions & 1 deletion ballsdex/packages/countryballs/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,9 @@ async def catch_ball(
# None is added representing the common countryball
special = random.choices(population=population + [None], weights=weights, k=1)[0]

is_new = not await BallInstance.filter(player=player, ball=self.ball.model).exists()
is_new = not await BallInstance.filter(
player=player, ball=self.ball.model, deleted=False
).exists()
ball = await BallInstance.create(
ball=self.ball.model,
player=player,
Expand Down
9 changes: 6 additions & 3 deletions ballsdex/packages/players/cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,8 @@ async def delete(self, interaction: discord.Interaction):
if view.value is None or not view.value:
return
player, _ = await PlayerModel.get_or_create(discord_id=interaction.user.id)
await player.delete()
await BallInstance.filter(player=player, deleted=False).update(deleted=True)
await interaction.followup.send("Your player data has been deleted.", ephemeral=True)

@friend.command(name="add")
async def friend_add(self, interaction: discord.Interaction, user: discord.User):
Expand Down Expand Up @@ -510,7 +511,9 @@ async def info(self, interaction: discord.Interaction):
except DoesNotExist:
await interaction.followup.send("You haven't got any info to show!", ephemeral=True)
return
ball = await BallInstance.filter(player=player).prefetch_related("special", "trade_player")
ball = await BallInstance.filter(player=player, deleted=True).prefetch_related(
"special", "trade_player"
)

user = interaction.user
bot_countryballs = {x: y.emoji_id for x, y in balls.items() if y.enabled}
Expand Down Expand Up @@ -637,7 +640,7 @@ async def get_items_csv(player: PlayerModel) -> BytesIO:
"""
Get a CSV file with all items of the player.
"""
balls = await BallInstance.filter(player=player).prefetch_related(
balls = await BallInstance.filter(player=player, deleted=False).prefetch_related(
"ball", "trade_player", "special"
)
txt = (
Expand Down
2 changes: 1 addition & 1 deletion ballsdex/packages/trade/cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ async def bulk_add(
ephemeral=True,
)
return
query = BallInstance.filter(player__discord_id=interaction.user.id)
query = BallInstance.filter(player__discord_id=interaction.user.id, deleted=False)
if countryball:
query = query.filter(ball=countryball)
if special:
Expand Down

0 comments on commit 4e3634a

Please sign in to comment.