added .clubbanner command
improved userrole slightly
This commit is contained in:
parent
fb658b8189
commit
2b581473c8
15 changed files with 209 additions and 107 deletions
src/EllieBot
Db/Models/club
Migrations
PostgreSql
20250310143026_club-banners.sql20250310143051_init.Designer.cs20250310143051_init.csPostgreSqlContextModelSnapshot.cs
Sqlite
Modules
strings
|
@ -9,7 +9,8 @@ public class ClubInfo : DbEntity
|
|||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string ImageUrl { get; set; } = string.Empty;
|
||||
|
||||
public string BannerUrl { get; set; } = string.Empty;
|
||||
|
||||
public int Xp { get; set; } = 0;
|
||||
public int? OwnerId { get; set; }
|
||||
public DiscordUser Owner { get; set; }
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
START TRANSACTION;
|
||||
ALTER TABLE clubs ADD bannerurl text;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" (migrationid, productversion)
|
||||
VALUES ('20250310143026_club-banners', '9.0.1');
|
||||
|
||||
COMMIT;
|
|
@ -12,7 +12,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|||
namespace EllieBot.Migrations.PostgreSql
|
||||
{
|
||||
[DbContext(typeof(PostgreSqlContext))]
|
||||
[Migration("20250310101144_init")]
|
||||
[Migration("20250310143051_init")]
|
||||
partial class init
|
||||
{
|
||||
/// <inheritdoc />
|
||||
|
@ -572,6 +572,10 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("BannerUrl")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("bannerurl");
|
||||
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("timestamp without time zone")
|
||||
.HasColumnName("dateadded");
|
|
@ -1601,6 +1601,7 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
name = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: true),
|
||||
description = table.Column<string>(type: "text", nullable: true),
|
||||
imageurl = table.Column<string>(type: "text", nullable: true),
|
||||
bannerurl = table.Column<string>(type: "text", nullable: true),
|
||||
xp = table.Column<int>(type: "integer", nullable: false),
|
||||
ownerid = table.Column<int>(type: "integer", nullable: true),
|
||||
dateadded = table.Column<DateTime>(type: "timestamp without time zone", nullable: true)
|
|
@ -569,6 +569,10 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("BannerUrl")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("bannerurl");
|
||||
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("timestamp without time zone")
|
||||
.HasColumnName("dateadded");
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
BEGIN TRANSACTION;
|
||||
ALTER TABLE "Clubs" ADD "BannerUrl" TEXT NULL;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20250310143023_club-banners', '9.0.1');
|
||||
|
||||
COMMIT;
|
|
@ -11,7 +11,7 @@ using EllieBot.Db;
|
|||
namespace EllieBot.Migrations.Sqlite
|
||||
{
|
||||
[DbContext(typeof(SqliteContext))]
|
||||
[Migration("20250310101142_init")]
|
||||
[Migration("20250310143048_init")]
|
||||
partial class init
|
||||
{
|
||||
/// <inheritdoc />
|
||||
|
@ -428,6 +428,9 @@ namespace EllieBot.Migrations.Sqlite
|
|||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("BannerUrl")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("TEXT");
|
||||
|
|
@ -1603,6 +1603,7 @@ namespace EllieBot.Migrations.Sqlite
|
|||
Name = table.Column<string>(type: "TEXT", maxLength: 20, nullable: true),
|
||||
Description = table.Column<string>(type: "TEXT", nullable: true),
|
||||
ImageUrl = table.Column<string>(type: "TEXT", nullable: true),
|
||||
BannerUrl = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Xp = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
OwnerId = table.Column<int>(type: "INTEGER", nullable: true),
|
||||
DateAdded = table.Column<DateTime>(type: "TEXT", nullable: true)
|
|
@ -425,6 +425,9 @@ namespace EllieBot.Migrations.Sqlite
|
|||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("BannerUrl")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using EllieBot.Modules.Utility.UserRole;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
|
||||
namespace EllieBot.Modules.Utility.UserRole;
|
||||
namespace EllieBot.Modules.Utility;
|
||||
|
||||
public partial class Utility
|
||||
{
|
||||
|
@ -27,6 +28,14 @@ public partial class Utility
|
|||
return;
|
||||
}
|
||||
|
||||
var botUser = ((SocketGuild)ctx.Guild).CurrentUser;
|
||||
|
||||
if (botUser.GetRoles().Max(x => x.Position) <= role.Position)
|
||||
{
|
||||
await Response().Error(strs.hierarchy).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
var success = await _urs.AddRoleAsync(ctx.Guild.Id, user.Id, role.Id);
|
||||
|
||||
if (!success)
|
||||
|
|
|
@ -29,13 +29,13 @@ public partial class Xp
|
|||
else
|
||||
{
|
||||
await Response()
|
||||
.Confirm(
|
||||
strs.club_transfered(
|
||||
Format.Bold(club.Name),
|
||||
Format.Bold(newOwner.ToString())
|
||||
)
|
||||
)
|
||||
.SendAsync();
|
||||
.Confirm(
|
||||
strs.club_transfered(
|
||||
Format.Bold(club.Name),
|
||||
Format.Bold(newOwner.ToString())
|
||||
)
|
||||
)
|
||||
.SendAsync();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,57 +108,85 @@ public partial class Xp
|
|||
await Response().Error(strs.club_icon_invalid_filetype).SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
public async Task ClubBanner([Leftover] string url = null)
|
||||
{
|
||||
if ((!Uri.IsWellFormedUriString(url, UriKind.Absolute) && url is not null))
|
||||
{
|
||||
await Response().Error(strs.club_icon_url_format).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
var result = await _service.SetClubBannerAsync(ctx.User.Id, url);
|
||||
if (result == SetClubIconResult.Success)
|
||||
{
|
||||
if (url is null)
|
||||
await Response().Confirm(strs.club_banner_reset).SendAsync();
|
||||
else
|
||||
await Response().Confirm(strs.club_banner_set).SendAsync();
|
||||
}
|
||||
else if (result == SetClubIconResult.NotOwner)
|
||||
await Response().Error(strs.club_owner_only).SendAsync();
|
||||
else if (result == SetClubIconResult.TooLarge)
|
||||
await Response().Error(strs.club_icon_too_large).SendAsync();
|
||||
else if (result == SetClubIconResult.InvalidFileType)
|
||||
await Response().Error(strs.club_icon_invalid_filetype).SendAsync();
|
||||
}
|
||||
|
||||
private async Task InternalClubInfoAsync(ClubInfo club)
|
||||
{
|
||||
var lvl = new LevelStats(club.Xp);
|
||||
var allUsers = club.Members.OrderByDescending(x =>
|
||||
{
|
||||
var l = new LevelStats(x.TotalXp).Level;
|
||||
if (club.OwnerId == x.Id)
|
||||
return int.MaxValue;
|
||||
if (x.IsClubAdmin)
|
||||
return (int.MaxValue / 2) + l;
|
||||
return l;
|
||||
})
|
||||
.ToList();
|
||||
{
|
||||
var l = new LevelStats(x.TotalXp).Level;
|
||||
if (club.OwnerId == x.Id)
|
||||
return int.MaxValue;
|
||||
if (x.IsClubAdmin)
|
||||
return (int.MaxValue / 2) + l;
|
||||
return l;
|
||||
})
|
||||
.ToList();
|
||||
|
||||
var rank = await _service.GetClubRankAsync(club.Id);
|
||||
|
||||
await Response()
|
||||
.Paginated()
|
||||
.Items(allUsers)
|
||||
.PageSize(10)
|
||||
.Page((users, _) =>
|
||||
{
|
||||
var embed = CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle($"{club}")
|
||||
.WithDescription(GetText(strs.level_x(lvl.Level + $" ({club.Xp} xp)")))
|
||||
.AddField(GetText(strs.desc),
|
||||
string.IsNullOrWhiteSpace(club.Description) ? "-" : club.Description)
|
||||
.AddField(GetText(strs.rank), $"#{rank}", true)
|
||||
.AddField(GetText(strs.owner), club.Owner.ToString(), true)
|
||||
// .AddField(GetText(strs.level_req), club.MinimumLevelReq.ToString(), true)
|
||||
.AddField(GetText(strs.members),
|
||||
string.Join("\n",
|
||||
users
|
||||
.Select(x =>
|
||||
{
|
||||
var l = new LevelStats(x.TotalXp);
|
||||
var lvlStr = Format.Bold($" ⟪{l.Level}⟫");
|
||||
if (club.OwnerId == x.Id)
|
||||
return x + "🌟" + lvlStr;
|
||||
if (x.IsClubAdmin)
|
||||
return x + "⭐" + lvlStr;
|
||||
return x + lvlStr;
|
||||
})));
|
||||
.Paginated()
|
||||
.Items(allUsers)
|
||||
.PageSize(10)
|
||||
.Page((users, _) =>
|
||||
{
|
||||
var embed = CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle($"{club}")
|
||||
.WithDescription(GetText(strs.level_x(lvl.Level + $" ({club.Xp} xp)")))
|
||||
.AddField(GetText(strs.desc),
|
||||
string.IsNullOrWhiteSpace(club.Description) ? "-" : club.Description)
|
||||
.AddField(GetText(strs.rank), $"#{rank}", true)
|
||||
.AddField(GetText(strs.owner), club.Owner.ToString(), true)
|
||||
// .AddField(GetText(strs.level_req), club.MinimumLevelReq.ToString(), true)
|
||||
.AddField(GetText(strs.members),
|
||||
string.Join("\n",
|
||||
users
|
||||
.Select(x =>
|
||||
{
|
||||
var l = new LevelStats(x.TotalXp);
|
||||
var lvlStr = Format.Bold($" ⟪{l.Level}⟫");
|
||||
if (club.OwnerId == x.Id)
|
||||
return x + "🌟" + lvlStr;
|
||||
if (x.IsClubAdmin)
|
||||
return x + "⭐" + lvlStr;
|
||||
return x + lvlStr;
|
||||
})));
|
||||
|
||||
if (Uri.IsWellFormedUriString(club.ImageUrl, UriKind.Absolute))
|
||||
return embed.WithThumbnailUrl(club.ImageUrl);
|
||||
if (Uri.IsWellFormedUriString(club.ImageUrl, UriKind.Absolute))
|
||||
embed.WithThumbnailUrl(club.ImageUrl);
|
||||
|
||||
return embed;
|
||||
})
|
||||
.SendAsync();
|
||||
if (Uri.IsWellFormedUriString(club.BannerUrl, UriKind.Absolute))
|
||||
embed.WithImageUrl(club.BannerUrl);
|
||||
|
||||
return embed;
|
||||
})
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
|
@ -208,20 +236,20 @@ public partial class Xp
|
|||
var bans = club.Bans.Select(x => x.User).ToArray();
|
||||
|
||||
return Response()
|
||||
.Paginated()
|
||||
.Items(bans)
|
||||
.PageSize(10)
|
||||
.CurrentPage(page)
|
||||
.Page((items, _) =>
|
||||
{
|
||||
var toShow = string.Join("\n", items.Select(x => x.ToString()));
|
||||
.Paginated()
|
||||
.Items(bans)
|
||||
.PageSize(10)
|
||||
.CurrentPage(page)
|
||||
.Page((items, _) =>
|
||||
{
|
||||
var toShow = string.Join("\n", items.Select(x => x.ToString()));
|
||||
|
||||
return CreateEmbed()
|
||||
.WithTitle(GetText(strs.club_bans_for(club.ToString())))
|
||||
.WithDescription(toShow)
|
||||
.WithOkColor();
|
||||
})
|
||||
.SendAsync();
|
||||
return CreateEmbed()
|
||||
.WithTitle(GetText(strs.club_bans_for(club.ToString())))
|
||||
.WithDescription(toShow)
|
||||
.WithOkColor();
|
||||
})
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
|
@ -237,20 +265,20 @@ public partial class Xp
|
|||
var apps = club.Applicants.Select(x => x.User).ToArray();
|
||||
|
||||
return Response()
|
||||
.Paginated()
|
||||
.Items(apps)
|
||||
.PageSize(10)
|
||||
.CurrentPage(page)
|
||||
.Page((items, _) =>
|
||||
{
|
||||
var toShow = string.Join("\n", items.Select(x => x.ToString()));
|
||||
.Paginated()
|
||||
.Items(apps)
|
||||
.PageSize(10)
|
||||
.CurrentPage(page)
|
||||
.Page((items, _) =>
|
||||
{
|
||||
var toShow = string.Join("\n", items.Select(x => x.ToString()));
|
||||
|
||||
return CreateEmbed()
|
||||
.WithTitle(GetText(strs.club_apps_for(club.ToString())))
|
||||
.WithDescription(toShow)
|
||||
.WithOkColor();
|
||||
})
|
||||
.SendAsync();
|
||||
return CreateEmbed()
|
||||
.WithTitle(GetText(strs.club_apps_for(club.ToString())))
|
||||
.WithDescription(toShow)
|
||||
.WithOkColor();
|
||||
})
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
|
@ -338,9 +366,9 @@ public partial class Xp
|
|||
if (result == ClubKickResult.Success)
|
||||
{
|
||||
return Response()
|
||||
.Confirm(strs.club_user_kick(Format.Bold(userName),
|
||||
Format.Bold(club.ToString())))
|
||||
.SendAsync();
|
||||
.Confirm(strs.club_user_kick(Format.Bold(userName),
|
||||
Format.Bold(club.ToString())))
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
if (result == ClubKickResult.Hierarchy)
|
||||
|
@ -365,9 +393,9 @@ public partial class Xp
|
|||
if (result == ClubBanResult.Success)
|
||||
{
|
||||
return Response()
|
||||
.Confirm(strs.club_user_banned(Format.Bold(userName),
|
||||
Format.Bold(club.ToString())))
|
||||
.SendAsync();
|
||||
.Confirm(strs.club_user_banned(Format.Bold(userName),
|
||||
Format.Bold(club.ToString())))
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
if (result == ClubBanResult.Unbannable)
|
||||
|
@ -393,9 +421,9 @@ public partial class Xp
|
|||
if (result == ClubUnbanResult.Success)
|
||||
{
|
||||
return Response()
|
||||
.Confirm(strs.club_user_unbanned(Format.Bold(userName),
|
||||
Format.Bold(club.ToString())))
|
||||
.SendAsync();
|
||||
.Confirm(strs.club_user_unbanned(Format.Bold(userName),
|
||||
Format.Bold(club.ToString())))
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
if (result == ClubUnbanResult.WrongUser)
|
||||
|
@ -415,11 +443,11 @@ public partial class Xp
|
|||
? "-"
|
||||
: desc;
|
||||
|
||||
var eb = _sender.CreateEmbed()
|
||||
.WithAuthor(ctx.User)
|
||||
.WithTitle(GetText(strs.club_desc_update))
|
||||
.WithOkColor()
|
||||
.WithDescription(desc);
|
||||
var eb = CreateEmbed()
|
||||
.WithAuthor(ctx.User)
|
||||
.WithTitle(GetText(strs.club_desc_update))
|
||||
.WithOkColor()
|
||||
.WithDescription(desc);
|
||||
|
||||
await Response().Embed(eb).SendAsync();
|
||||
}
|
||||
|
|
|
@ -120,6 +120,26 @@ public class ClubService : IEService, IClubService
|
|||
return SetClubIconResult.Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets club banner url
|
||||
/// </summary>
|
||||
/// <param name="ownerUserId">User ID of the club owner</param>
|
||||
/// <param name="url">Banner URL to set</param>
|
||||
/// <returns>Result of the operation</returns>
|
||||
public async Task<SetClubIconResult> SetClubBannerAsync(ulong ownerUserId, string? url)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
var club = uow.Set<ClubInfo>().GetByOwner(ownerUserId);
|
||||
|
||||
if (club is null)
|
||||
return SetClubIconResult.NotOwner;
|
||||
|
||||
club.BannerUrl = url;
|
||||
await uow.SaveChangesAsync();
|
||||
|
||||
return SetClubIconResult.Success;
|
||||
}
|
||||
|
||||
public bool GetClubByName(string clubName, out ClubInfo club)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
|
|
|
@ -10,6 +10,7 @@ public interface IClubService
|
|||
Task<ToggleAdminResult> ToggleAdminAsync(IUser owner, IUser toAdmin);
|
||||
ClubInfo? GetClubByMember(IUser user);
|
||||
Task<SetClubIconResult> SetClubIconAsync(ulong ownerUserId, string? url);
|
||||
Task<SetClubIconResult> SetClubBannerAsync(ulong ownerUserId, string? url);
|
||||
bool GetClubByName(string clubName, out ClubInfo club);
|
||||
ClubApplyResult ApplyToClub(IUser user, ClubInfo club);
|
||||
ClubAcceptResult AcceptApplication(ulong clubOwnerUserId, string userName, out DiscordUser? discordUser);
|
||||
|
|
|
@ -3694,6 +3694,17 @@ clubicon:
|
|||
params:
|
||||
- url:
|
||||
desc: "The URL of an image file to use as the club icon."
|
||||
clubbanner:
|
||||
desc: |-
|
||||
Sets an image as a club banner.
|
||||
The banner will be displayed when club information is shown.
|
||||
ex:
|
||||
- 'https://i.imgur.com/example.png'
|
||||
- ''
|
||||
params:
|
||||
- { }
|
||||
- url:
|
||||
desc: "URL to the image to set as a club banner."
|
||||
clubapps:
|
||||
desc: Shows the list of users who have applied to your club. Paginated. You must be club owner to use this command.
|
||||
ex:
|
||||
|
@ -5034,19 +5045,19 @@ userrolecolor:
|
|||
color:
|
||||
desc: 'The new color for the role in hex format.'
|
||||
userroleicon:
|
||||
desc: |-
|
||||
Changes the icon of your assigned role.
|
||||
ex:
|
||||
- '@Role :thumbsup:'
|
||||
params:
|
||||
- role:
|
||||
desc: 'The assigned role to change the icon of.'
|
||||
icon:
|
||||
desc: 'The new icon for the role.'
|
||||
- role:
|
||||
desc: 'The assigned role to change the icon of.'
|
||||
emote:
|
||||
desc: 'The server emoji for the role.'
|
||||
desc: |-
|
||||
Changes the icon of your assigned role.
|
||||
ex:
|
||||
- '@Role :thumbsup:'
|
||||
params:
|
||||
- role:
|
||||
desc: 'The assigned role to change the icon of.'
|
||||
imageUrl:
|
||||
desc: 'The image url to be used as a new icon for the role.'
|
||||
- role:
|
||||
desc: 'The assigned role to change the icon of.'
|
||||
serverEmoji:
|
||||
desc: 'The server emoji to be used as a new icon for the role.'
|
||||
userrolename:
|
||||
desc: |-
|
||||
Changes the name of your assigned role.
|
||||
|
|
|
@ -887,6 +887,8 @@
|
|||
"club_icon_invalid_filetype": "Specified image has an invalid filetype. Make sure you're specifying a direct image url.",
|
||||
"club_icon_url_format": "You must specify an absolute image url.",
|
||||
"club_icon_set": "New club icon set.",
|
||||
"club_banner_set": "New club banner set.",
|
||||
"club_banner_reset": "Club banner has been reset.",
|
||||
"club_bans_for": "Bans for {0} club",
|
||||
"club_apps_for": "Applicants for {0} club",
|
||||
"club_leaderboard": "Club leaderboard - page {0}",
|
||||
|
@ -1201,6 +1203,6 @@
|
|||
"userrole_icon_success": "The icon for {0} has been saved.",
|
||||
"userrole_icon_fail": "Failed to set the role icon.",
|
||||
"userrole_icon_invalid": "The role icon cannot be empty.",
|
||||
"userrole_hierarchy_error": "You can't assign or modify roles that are higher than or equal to your highest role.",
|
||||
"userrole_hierarchy_error": "You can't assign or modify roles that are higher than or equal to your, or bots highest role.",
|
||||
"userrole_role_not_exists": "That role doesn't exist."
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue