838 lines
30 KiB
C#
838 lines
30 KiB
C#
using LiteDB;
|
|
using Vanadium.Classes;
|
|
using Vanadium.Classes.DBs.DBClasses;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using static Vanadium.Classes.DBs.DBClasses.ClubsDBClasses;
|
|
|
|
namespace Vanadium.Classes.DBs
|
|
{
|
|
public class ClubsDB
|
|
{
|
|
public static LiteDatabase ClubsDBFile = new LiteDatabase("Filename=" + Path.Join(Program.dataDir, "DBs", "Clubs.db") + ";Connection=shared");
|
|
|
|
public static readonly ILiteCollection<Club> Clubs =
|
|
ClubsDBFile.GetCollection<Club>("Clubs");
|
|
|
|
private static readonly ILiteCollection<ClubDbCounters> Counters =
|
|
ClubsDBFile.GetCollection<ClubDbCounters>("Counters");
|
|
|
|
public static readonly ILiteCollection<ClubAnnouncement> Announcements =
|
|
ClubsDBFile.GetCollection<ClubAnnouncement>("ClubAnnouncements");
|
|
|
|
|
|
public static void Setup()
|
|
{
|
|
Clubs.EnsureIndex(x => x.ClubId);
|
|
Clubs.EnsureIndex(x => x.CreatorAccountId);
|
|
Clubs.EnsureIndex(x => x.Name);
|
|
Clubs.EnsureIndex(x => x.IsDeleted);
|
|
Announcements.EnsureIndex(x => x.ClubId);
|
|
Announcements.EnsureIndex(x => x.AnnouncementId);
|
|
}
|
|
|
|
|
|
public static long GetNextClubId()
|
|
{
|
|
var counter = Counters.FindById("club");
|
|
if (counter == null)
|
|
{
|
|
counter = new ClubDbCounters { Key = "club", Value = 1 };
|
|
Counters.Insert(counter);
|
|
return 1;
|
|
}
|
|
counter.Value++;
|
|
Counters.Update(counter);
|
|
return counter.Value;
|
|
}
|
|
|
|
private static long GetNextPermissionsId()
|
|
{
|
|
var counter = Counters.FindById("clubperms");
|
|
if (counter == null)
|
|
{
|
|
counter = new ClubDbCounters { Key = "clubperms", Value = 1 };
|
|
Counters.Insert(counter);
|
|
return 1;
|
|
}
|
|
counter.Value++;
|
|
Counters.Update(counter);
|
|
return counter.Value;
|
|
}
|
|
|
|
private static string GeneratePlayerClubHandle()
|
|
{
|
|
const string chars = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
var rng = new Random();
|
|
return new string(Enumerable.Range(0, 16).Select(_ => chars[rng.Next(chars.Length)]).ToArray());
|
|
}
|
|
|
|
private static List<ClubPermissions> CreateDefaultPermissions(long clubId)
|
|
{
|
|
return new List<ClubPermissions>
|
|
{
|
|
new ClubPermissions
|
|
{
|
|
ClubPermissionsId = GetNextPermissionsId(),
|
|
ClubId = clubId,
|
|
Type = 30,
|
|
ApproveMember = true,
|
|
BanUnban = true,
|
|
CreateEvent = true,
|
|
EditDetails = true,
|
|
EditPermissionSettings = true,
|
|
PostAnnouncement = true
|
|
},
|
|
new ClubPermissions
|
|
{
|
|
ClubPermissionsId = GetNextPermissionsId(),
|
|
ClubId = clubId,
|
|
Type = 20,
|
|
ApproveMember = true,
|
|
BanUnban = true,
|
|
CreateEvent = false,
|
|
EditDetails = false,
|
|
EditPermissionSettings = false,
|
|
PostAnnouncement = false
|
|
},
|
|
new ClubPermissions
|
|
{
|
|
ClubPermissionsId = GetNextPermissionsId(),
|
|
ClubId = clubId,
|
|
Type = 10,
|
|
ApproveMember = false,
|
|
BanUnban = false,
|
|
CreateEvent = false,
|
|
EditDetails = false,
|
|
EditPermissionSettings = false,
|
|
PostAnnouncement = false
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
public static Club CreateClub(
|
|
long creatorId,
|
|
string name,
|
|
string description,
|
|
string category)
|
|
{
|
|
long clubId = GetNextClubId();
|
|
|
|
var club = new Club
|
|
{
|
|
ClubId = clubId,
|
|
Name = name,
|
|
Description = description,
|
|
Category = category,
|
|
CreatorAccountId = creatorId,
|
|
MemberCount = 1,
|
|
Visibility = (int)ClubVisibility.Public,
|
|
Joinability = (int)ClubJoinability.Open,
|
|
AllowJuniors = true,
|
|
MainImageName = "DefaultRoomImage.png",
|
|
CreatedAt = DateTime.UtcNow,
|
|
Members = new List<ClubMember>
|
|
{
|
|
new ClubMember
|
|
{
|
|
MemberId = GetNextMemberId(),
|
|
AccountId = creatorId,
|
|
MemberType = (int)ClubMemberType.Owner,
|
|
JoinedAt = DateTime.UtcNow
|
|
}
|
|
}
|
|
};
|
|
|
|
club.Permissions = CreateDefaultPermissions(clubId);
|
|
|
|
Clubs.Insert(club);
|
|
return club;
|
|
}
|
|
|
|
private static long GetNextMemberId()
|
|
{
|
|
var counter = Counters.FindById("clubmember");
|
|
if (counter == null)
|
|
{
|
|
counter = new ClubDbCounters { Key = "clubmember", Value = 1 };
|
|
Counters.Insert(counter);
|
|
return 1;
|
|
}
|
|
counter.Value++;
|
|
Counters.Update(counter);
|
|
return counter.Value;
|
|
}
|
|
|
|
public static Club CreatePlayerClub(long creatorId)
|
|
{
|
|
long clubId = GetNextClubId();
|
|
string handle = GeneratePlayerClubHandle();
|
|
|
|
var club = new Club
|
|
{
|
|
ClubId = clubId,
|
|
Name = handle,
|
|
Description = "",
|
|
Category = "Social",
|
|
CreatorAccountId = creatorId,
|
|
MemberCount = 1,
|
|
Visibility = (int)ClubVisibility.Unlisted,
|
|
Joinability = (int)ClubJoinability.Open,
|
|
AllowJuniors = true,
|
|
MainImageName = "DefaultRoomImage.png",
|
|
CreatedAt = DateTime.UtcNow,
|
|
Members = new List<ClubMember>
|
|
{
|
|
new ClubMember
|
|
{
|
|
MemberId = GetNextMemberId(),
|
|
AccountId = creatorId,
|
|
MemberType = (int)ClubMemberType.Owner,
|
|
JoinedAt = DateTime.UtcNow
|
|
}
|
|
}
|
|
};
|
|
|
|
club.Permissions = CreateDefaultPermissions(clubId);
|
|
|
|
Clubs.Insert(club);
|
|
return club;
|
|
}
|
|
|
|
public static Club? GetClub(long clubId)
|
|
{
|
|
var club = Clubs.FindById(clubId);
|
|
return (club == null || club.IsDeleted) ? null : club;
|
|
}
|
|
|
|
public static bool DeleteClub(long clubId)
|
|
{
|
|
var club = Clubs.FindById(clubId);
|
|
if (club == null || club.IsDeleted) return false;
|
|
club.IsDeleted = true;
|
|
Clubs.Update(club);
|
|
return true;
|
|
}
|
|
|
|
public static List<Club> GetClubsCreatedBy(long playerId)
|
|
=> Clubs.Find(c => c.CreatorAccountId == playerId && !c.IsDeleted).ToList();
|
|
|
|
public static List<Club> GetClubsJoinedBy(long playerId)
|
|
{
|
|
return Clubs.FindAll()
|
|
.Where(c => !c.IsDeleted &&
|
|
c.Members.Any(m => m.AccountId == playerId))
|
|
.ToList();
|
|
}
|
|
|
|
public static int GetSubscriberCount(long playerClubId)
|
|
{
|
|
var club = GetClub(playerClubId);
|
|
if (club == null) return 0;
|
|
return Math.Max(0, club.MemberCount - 1);
|
|
}
|
|
|
|
public static ClubSearchResult Search(
|
|
string? query,
|
|
string? category,
|
|
int sort,
|
|
int count,
|
|
int skip = 0)
|
|
{
|
|
IEnumerable<Club> all = Clubs.FindAll()
|
|
.Where(c => !c.IsDeleted && c.Visibility == (int)ClubVisibility.Public);
|
|
|
|
if (!string.IsNullOrWhiteSpace(category))
|
|
all = all.Where(c =>
|
|
string.Equals(c.Category, category, StringComparison.OrdinalIgnoreCase));
|
|
|
|
if (!string.IsNullOrWhiteSpace(query))
|
|
{
|
|
string q = query.ToLowerInvariant();
|
|
|
|
all = all
|
|
.Select(c =>
|
|
{
|
|
string nameLower = (c.Name ?? "").ToLowerInvariant();
|
|
string descLower = (c.Description ?? "").ToLowerInvariant();
|
|
|
|
int score = 0;
|
|
|
|
if (nameLower == q || descLower == q)
|
|
score += 200;
|
|
|
|
if (nameLower.StartsWith(q))
|
|
score += 100;
|
|
|
|
if (nameLower.Contains(q))
|
|
score += 50;
|
|
|
|
if (descLower.Contains(q))
|
|
score += 20;
|
|
|
|
if (c.CustomTags.Any(t => t.ToLowerInvariant().Contains(q)))
|
|
score += 30;
|
|
|
|
score -= Math.Min(nameLower.Length, 50);
|
|
|
|
return new { Club = c, Score = score };
|
|
})
|
|
.Where(x => x.Score > 0)
|
|
.OrderByDescending(x => x.Score)
|
|
.Select(x => x.Club);
|
|
}
|
|
|
|
IEnumerable<Club> sorted = sort switch
|
|
{
|
|
1 => all.OrderByDescending(c => c.CreatedAt),
|
|
2 => all.OrderBy(c => c.CreatedAt),
|
|
_ => all.OrderByDescending(c => c.MemberCount)
|
|
};
|
|
|
|
var list = sorted.ToList();
|
|
int total = list.Count;
|
|
|
|
var page = list.Skip(skip).Take(count).ToList();
|
|
|
|
return new ClubSearchResult
|
|
{
|
|
Clubs = page.Select(ToSummary).ToList(),
|
|
ContinuationToken = null,
|
|
TotalClubs = total
|
|
};
|
|
}
|
|
|
|
public static ClubMember? GetMember(long clubId, long playerId)
|
|
{
|
|
var club = GetClub(clubId);
|
|
return club?.Members.FirstOrDefault(m => m.AccountId == playerId);
|
|
}
|
|
|
|
public static bool IsMember(long clubId, long playerId)
|
|
=> GetMember(clubId, playerId) != null;
|
|
|
|
public static List<ClubMemberDTO> GetClubMembers(long clubId)
|
|
{
|
|
var club = GetClub(clubId);
|
|
if (club == null)
|
|
return new List<ClubMemberDTO>();
|
|
|
|
return club.Members
|
|
.Select(m => new ClubMemberDTO
|
|
{
|
|
MemberId = m.MemberId,
|
|
AccountId = m.AccountId,
|
|
ClubId = club.ClubId,
|
|
MembershipType = m.MemberType,
|
|
CreatedAt = m.JoinedAt
|
|
})
|
|
.OrderByDescending(m => m.CreatedAt)
|
|
.ToList();
|
|
}
|
|
|
|
public static bool IsOwnerOrCoOwner(long clubId, long playerId)
|
|
{
|
|
var m = GetMember(clubId, playerId);
|
|
return m != null && m.MemberType >= (int)ClubMemberType.CoOwner;
|
|
}
|
|
|
|
public static bool CanEditDetails(long clubId, long playerId)
|
|
{
|
|
var club = GetClub(clubId);
|
|
if (club == null) return false;
|
|
if (club.CreatorAccountId == playerId) return true;
|
|
|
|
var member = club.Members.FirstOrDefault(m => m.AccountId == playerId);
|
|
if (member == null) return false;
|
|
|
|
var perms = club.Permissions.FirstOrDefault(p => p.Type == member.MemberType);
|
|
return perms?.EditDetails == true || member.MemberType >= (int)ClubMemberType.CoOwner;
|
|
}
|
|
|
|
public static Club? JoinClub(long clubId, long playerId)
|
|
{
|
|
var club = GetClub(clubId);
|
|
if (club == null) return null;
|
|
if (club.BannedMemberIds.Contains(playerId)) return null;
|
|
if (IsMember(clubId, playerId)) return club;
|
|
|
|
bool needsApproval = club.Joinability == (int)ClubJoinability.ApprovalRequired;
|
|
|
|
club.Members.Add(new ClubMember
|
|
{
|
|
MemberId = GetNextMemberId(),
|
|
AccountId = playerId,
|
|
MemberType = (int)ClubMemberType.Member,
|
|
JoinedAt = DateTime.UtcNow,
|
|
IsPendingApproval = needsApproval
|
|
});
|
|
|
|
if (!needsApproval)
|
|
club.MemberCount++;
|
|
|
|
Clubs.Update(club);
|
|
return club;
|
|
}
|
|
|
|
public static Club LeaveClub(long clubId, long playerId)
|
|
{
|
|
var club = GetClub(clubId);
|
|
if (club == null) return null;
|
|
|
|
var member = club.Members.FirstOrDefault(m => m.AccountId == playerId);
|
|
if (member == null) return null;
|
|
|
|
if (member.MemberType == (int)ClubMemberType.Owner) return null;
|
|
|
|
club.Members.Remove(member);
|
|
if (!member.IsPendingApproval)
|
|
club.MemberCount = Math.Max(0, club.MemberCount - 1);
|
|
|
|
Clubs.Update(club);
|
|
return club;
|
|
}
|
|
|
|
public static Club KickMember(long clubId, long targetId, long requesterId)
|
|
{
|
|
var club = GetClub(clubId);
|
|
if (club == null) return null;
|
|
|
|
var requester = club.Members.FirstOrDefault(m => m.AccountId == requesterId);
|
|
var target = club.Members.FirstOrDefault(m => m.AccountId == targetId);
|
|
|
|
if (requester == null || target == null) return null;
|
|
if (requester.MemberType <= target.MemberType && club.CreatorAccountId != requesterId)
|
|
return null;
|
|
|
|
club.Members.Remove(target);
|
|
if (!target.IsPendingApproval)
|
|
club.MemberCount = Math.Max(0, club.MemberCount - 1);
|
|
|
|
Clubs.Update(club);
|
|
return club;
|
|
}
|
|
|
|
public static Club ApproveMember(long clubId, long targetId, long requesterId)
|
|
{
|
|
var club = GetClub(clubId);
|
|
if (club == null) return null;
|
|
|
|
var requester = club.Members.FirstOrDefault(m => m.AccountId == requesterId);
|
|
if (requester == null) return null;
|
|
|
|
var perms = club.Permissions.FirstOrDefault(p => p.Type == requester.MemberType);
|
|
bool canApprove = club.CreatorAccountId == requesterId ||
|
|
requester.MemberType >= (int)ClubMemberType.CoOwner ||
|
|
(perms?.ApproveMember == true);
|
|
|
|
if (!canApprove) return null;
|
|
|
|
var target = club.Members.FirstOrDefault(m => m.AccountId == targetId && m.IsPendingApproval);
|
|
if (target == null) return null;
|
|
|
|
target.IsPendingApproval = false;
|
|
club.MemberCount++;
|
|
Clubs.Update(club);
|
|
return club;
|
|
}
|
|
|
|
public static bool SetMemberRole(long clubId, long targetId, int newRole, long requesterId)
|
|
{
|
|
var club = GetClub(clubId);
|
|
if (club == null) return false;
|
|
|
|
var requester = club.Members.FirstOrDefault(m => m.AccountId == requesterId);
|
|
if (requester == null && club.CreatorAccountId != requesterId) return false;
|
|
|
|
var target = club.Members.FirstOrDefault(m => m.AccountId == targetId);
|
|
if (target == null) return false;
|
|
|
|
target.MemberType = newRole;
|
|
Clubs.Update(club);
|
|
return true;
|
|
}
|
|
|
|
public static bool BanMember(long clubId, long targetId, long requesterId)
|
|
{
|
|
var club = GetClub(clubId);
|
|
if (club == null) return false;
|
|
|
|
if (!IsOwnerOrCoOwner(clubId, requesterId) && club.CreatorAccountId != requesterId)
|
|
return false;
|
|
|
|
var target = club.Members.FirstOrDefault(m => m.AccountId == targetId);
|
|
if (target != null)
|
|
{
|
|
club.Members.Remove(target);
|
|
if (!target.IsPendingApproval)
|
|
club.MemberCount = Math.Max(0, club.MemberCount - 1);
|
|
}
|
|
|
|
if (!club.BannedMemberIds.Contains(targetId))
|
|
club.BannedMemberIds.Add(targetId);
|
|
|
|
Clubs.Update(club);
|
|
return true;
|
|
}
|
|
|
|
public static bool UnbanMember(long clubId, long targetId, long requesterId)
|
|
{
|
|
var club = GetClub(clubId);
|
|
if (club == null) return false;
|
|
|
|
if (!IsOwnerOrCoOwner(clubId, requesterId) && club.CreatorAccountId != requesterId)
|
|
return false;
|
|
|
|
club.BannedMemberIds.Remove(targetId);
|
|
Clubs.Update(club);
|
|
return true;
|
|
}
|
|
|
|
public static Club? SetMainImage(long clubId, string imageName, long requesterId)
|
|
{
|
|
var club = GetClub(clubId);
|
|
if (club == null || !CanEditDetails(clubId, requesterId)) return null;
|
|
club.MainImageName = imageName;
|
|
Clubs.Update(club);
|
|
return club;
|
|
}
|
|
|
|
public static Club? DeleteMainImage(long clubId, long requesterId)
|
|
{
|
|
var club = GetClub(clubId);
|
|
if (club == null || !CanEditDetails(clubId, requesterId)) return null;
|
|
if (club.AdditionalImages.Count == 0) return null;
|
|
club.MainImageName = club.AdditionalImages[0].ImageName;
|
|
club.AdditionalImages.RemoveAt(0);
|
|
Clubs.Update(club);
|
|
return club;
|
|
}
|
|
|
|
public static Club? SetAdditionalImage(long clubId, int index, string imageName, long requesterId)
|
|
{
|
|
var club = GetClub(clubId);
|
|
if (club == null || !CanEditDetails(clubId, requesterId)) return null;
|
|
|
|
var existing = club.AdditionalImages.FirstOrDefault(i => i.Index == index);
|
|
if (existing != null)
|
|
existing.ImageName = imageName;
|
|
else
|
|
club.AdditionalImages.Add(new ClubAdditionalImage { Index = index, ImageName = imageName });
|
|
|
|
Clubs.Update(club);
|
|
return club;
|
|
}
|
|
|
|
public static Club? DeleteAdditionalImage(long clubId, int index, long requesterId)
|
|
{
|
|
var club = GetClub(clubId);
|
|
if (club == null || !CanEditDetails(clubId, requesterId)) return null;
|
|
|
|
var img = club.AdditionalImages.FirstOrDefault(i => i.Index == index);
|
|
if (img != null)
|
|
club.AdditionalImages.Remove(img);
|
|
|
|
Clubs.Update(club);
|
|
return club;
|
|
}
|
|
|
|
public static Club? SetClubhouse(long clubId, long roomId, long requesterId)
|
|
{
|
|
var club = GetClub(clubId);
|
|
if (club == null || !IsOwnerOrCoOwner(clubId, requesterId) && club.CreatorAccountId != requesterId)
|
|
return null;
|
|
club.ClubhouseRoomId = roomId;
|
|
Clubs.Update(club);
|
|
return club;
|
|
}
|
|
|
|
public static Club? RemoveClubhouse(long clubId, long requesterId)
|
|
{
|
|
var club = GetClub(clubId);
|
|
if (club == null || !IsOwnerOrCoOwner(clubId, requesterId) && club.CreatorAccountId != requesterId)
|
|
return null;
|
|
club.ClubhouseRoomId = null;
|
|
Clubs.Update(club);
|
|
return club;
|
|
}
|
|
|
|
public static Club? SetPermissions(
|
|
long clubId,
|
|
int membershipType,
|
|
bool approveMember,
|
|
bool banUnban,
|
|
bool createEvent,
|
|
bool editDetails,
|
|
bool editPermissionSettings,
|
|
bool postAnnouncement)
|
|
{
|
|
var club = GetClub(clubId);
|
|
if (club == null) return null;
|
|
|
|
int normalizedType = membershipType switch
|
|
{
|
|
0 => (int)ClubMemberType.Member,
|
|
1 => (int)ClubMemberType.Moderator,
|
|
2 => (int)ClubMemberType.CoOwner,
|
|
(int)ClubMemberType.Member or (int)ClubMemberType.Moderator or (int)ClubMemberType.CoOwner => membershipType,
|
|
_ => -1
|
|
};
|
|
|
|
if (normalizedType == -1) return null;
|
|
|
|
var existing = club.Permissions.FirstOrDefault(p => p.Type == normalizedType);
|
|
if (existing == null)
|
|
{
|
|
existing = new ClubPermissions
|
|
{
|
|
ClubPermissionsId = GetNextPermissionsId(),
|
|
ClubId = clubId,
|
|
Type = normalizedType
|
|
};
|
|
club.Permissions.Add(existing);
|
|
}
|
|
|
|
existing.ApproveMember = approveMember;
|
|
existing.BanUnban = banUnban;
|
|
existing.CreateEvent = createEvent;
|
|
existing.EditDetails = editDetails;
|
|
existing.EditPermissionSettings = editPermissionSettings;
|
|
existing.PostAnnouncement = postAnnouncement;
|
|
|
|
Clubs.Update(club);
|
|
return club;
|
|
}
|
|
|
|
public static Club? Modify(
|
|
long clubId,
|
|
string name,
|
|
string description,
|
|
string category,
|
|
long requesterId)
|
|
{
|
|
var club = GetClub(clubId);
|
|
if (club == null || !CanEditDetails(clubId, requesterId)) return null;
|
|
club.Name = name;
|
|
club.Description = description;
|
|
club.Category = category;
|
|
Clubs.Update(club);
|
|
return club;
|
|
}
|
|
|
|
public static Club? SetMinLevel(long clubId, int minLevel, long requesterId)
|
|
{
|
|
var club = GetClub(clubId);
|
|
if (club == null || !CanEditDetails(clubId, requesterId)) return null;
|
|
club.MinLevel = minLevel;
|
|
Clubs.Update(club);
|
|
return club;
|
|
}
|
|
|
|
public static Club? ModifyDetails(
|
|
long clubId,
|
|
int? visibility,
|
|
int? joinability,
|
|
bool? allowJuniors,
|
|
List<string>? customTags,
|
|
long requesterId)
|
|
{
|
|
var club = GetClub(clubId);
|
|
if (club == null || !CanEditDetails(clubId, requesterId)) return null;
|
|
|
|
if (visibility.HasValue) club.Visibility = visibility.Value;
|
|
if (joinability.HasValue) club.Joinability = joinability.Value;
|
|
if (allowJuniors.HasValue) club.AllowJuniors = allowJuniors.Value;
|
|
if (customTags != null)
|
|
{
|
|
club.CustomTags = customTags
|
|
.Select(t => t.Trim())
|
|
.Where(t => !string.IsNullOrEmpty(t))
|
|
.Distinct()
|
|
.ToList();
|
|
}
|
|
|
|
Clubs.Update(club);
|
|
return club;
|
|
}
|
|
|
|
public static ClubSummaryDTO ToSummary(Club club) => new ClubSummaryDTO
|
|
{
|
|
ClubId = club.ClubId,
|
|
Name = club.Name,
|
|
Description = club.Description,
|
|
Category = club.Category,
|
|
Joinability = club.Joinability,
|
|
Visibility = club.Visibility,
|
|
AllowJuniors = club.AllowJuniors,
|
|
MinLevel = club.MinLevel,
|
|
ClubType = club.ClubType,
|
|
IsRRO = club.IsRRO,
|
|
State = club.State,
|
|
CreatorAccountId = club.CreatorAccountId,
|
|
ClubhouseRoomId = club.ClubhouseRoomId,
|
|
MainImageName = club.MainImageName,
|
|
MemberCount = club.MemberCount
|
|
};
|
|
|
|
public static ClubDetailsDTO ToDetails(Club club, long requesterId) => new ClubDetailsDTO
|
|
{
|
|
ClubId = club.ClubId,
|
|
Club = ToSummary(club),
|
|
AdditionalImages = club.AdditionalImages ?? new(),
|
|
CustomTags = club.CustomTags ?? new(),
|
|
CoownerPermissions = club.Permissions.FirstOrDefault(p => p.Type == 30),
|
|
ModeratorPermissions = club.Permissions.FirstOrDefault(p => p.Type == 20),
|
|
MemberPermissions = club.Permissions.FirstOrDefault(p => p.Type == 10),
|
|
MyMembershipType = club.Members
|
|
.FirstOrDefault(m => m.AccountId == requesterId)?.MemberType ?? 0
|
|
};
|
|
|
|
private static long GetNextAnnouncementId()
|
|
{
|
|
var counter = Counters.FindById("announcement");
|
|
if (counter == null)
|
|
{
|
|
counter = new ClubDbCounters { Key = "announcement", Value = 1 };
|
|
Counters.Insert(counter);
|
|
return 1;
|
|
}
|
|
counter.Value++;
|
|
Counters.Update(counter);
|
|
return counter.Value;
|
|
}
|
|
|
|
public static bool CanPostAnnouncement(long clubId, long playerId)
|
|
{
|
|
var club = GetClub(clubId);
|
|
if (club == null) return false;
|
|
if (club.CreatorAccountId == playerId) return true;
|
|
|
|
var member = club.Members.FirstOrDefault(m => m.AccountId == playerId);
|
|
if (member == null) return false;
|
|
|
|
var perms = club.Permissions.FirstOrDefault(p => p.Type == member.MemberType);
|
|
return member.MemberType >= (int)ClubMemberType.CoOwner || perms?.PostAnnouncement == true;
|
|
}
|
|
|
|
public static ClubAnnouncement? CreateAnnouncement(long clubId, long creatorAccountId, string title, string body, string? imageName, string? meta)
|
|
{
|
|
if (!CanPostAnnouncement(clubId, creatorAccountId)) return null;
|
|
|
|
var announcement = new ClubAnnouncement
|
|
{
|
|
AnnouncementId = GetNextAnnouncementId(),
|
|
ClubId = clubId,
|
|
CreatorAccountId = creatorAccountId,
|
|
Title = title.Trim(),
|
|
Body = body.Trim(),
|
|
ImageName = string.IsNullOrWhiteSpace(imageName) ? null : imageName.Trim(),
|
|
Meta = string.IsNullOrWhiteSpace(meta) ? null : meta,
|
|
CreatedAt = DateTime.UtcNow
|
|
};
|
|
|
|
Announcements.Insert(announcement);
|
|
return announcement;
|
|
}
|
|
|
|
public static ClubAnnouncement? EditAnnouncement(long clubId, long announcementId, long requesterId, string title, string body, string? imageName, string? meta)
|
|
{
|
|
var announcement = Announcements.FindOne(a => a.AnnouncementId == announcementId && a.ClubId == clubId);
|
|
if (announcement == null) return null;
|
|
|
|
if (announcement.CreatorAccountId != requesterId && !CanPostAnnouncement(clubId, requesterId))
|
|
return null;
|
|
|
|
announcement.Title = title.Trim();
|
|
announcement.Body = body.Trim();
|
|
announcement.ImageName = string.IsNullOrWhiteSpace(imageName) ? null : imageName.Trim();
|
|
announcement.Meta = string.IsNullOrWhiteSpace(meta) ? null : meta;
|
|
|
|
Announcements.Update(announcement);
|
|
return announcement;
|
|
}
|
|
|
|
public static bool DeleteAnnouncement(long clubId, long announcementId, long requesterId)
|
|
{
|
|
var announcement = Announcements.FindOne(a => a.AnnouncementId == announcementId && a.ClubId == clubId);
|
|
if (announcement == null) return false;
|
|
|
|
if (announcement.CreatorAccountId != requesterId && !CanPostAnnouncement(clubId, requesterId))
|
|
return false;
|
|
|
|
Announcements.Delete(announcementId);
|
|
return true;
|
|
}
|
|
|
|
public static bool MarkAnnouncementRead(long clubId, long announcementId, long accountId)
|
|
{
|
|
var announcement = Announcements.FindOne(a => a.AnnouncementId == announcementId && a.ClubId == clubId);
|
|
if (announcement == null) return false;
|
|
|
|
var allForClub = Announcements.Find(a => a.ClubId == clubId).ToList();
|
|
|
|
foreach (var a in allForClub)
|
|
{
|
|
if (!a.LastReadAnnouncementIdByAccount.ContainsKey(accountId) ||
|
|
a.LastReadAnnouncementIdByAccount[accountId] < announcementId)
|
|
{
|
|
a.LastReadAnnouncementIdByAccount[accountId] = announcementId;
|
|
Announcements.Update(a);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static ClubAnnouncementListDTO? GetClubAnnouncements(long clubId, long requesterId)
|
|
{
|
|
var club = GetClub(clubId);
|
|
if (club == null) return null;
|
|
|
|
var allAnnouncements = Announcements
|
|
.Find(a => a.ClubId == clubId)
|
|
.OrderByDescending(a => a.CreatedAt)
|
|
.ToList();
|
|
|
|
long? lastAnnouncementId = allAnnouncements.Count > 0
|
|
? allAnnouncements.Max(a => a.AnnouncementId)
|
|
: (long?)null;
|
|
|
|
long lastReadAnnouncementId = 0;
|
|
foreach (var a in allAnnouncements)
|
|
{
|
|
if (a.LastReadAnnouncementIdByAccount.TryGetValue(requesterId, out long readId))
|
|
lastReadAnnouncementId = Math.Max(lastReadAnnouncementId, readId);
|
|
}
|
|
|
|
return new ClubAnnouncementListDTO
|
|
{
|
|
ClubId = clubId,
|
|
Announcements = allAnnouncements.Select(ToAnnouncementDTO).ToList(),
|
|
LastAnnouncementId = lastAnnouncementId,
|
|
LastReadAnnouncementId = lastReadAnnouncementId
|
|
};
|
|
}
|
|
|
|
public static List<ClubAnnouncementListDTO> GetAnnouncementsForMyClubs(long accountId)
|
|
{
|
|
return GetClubsJoinedBy(accountId)
|
|
.Select(c => GetClubAnnouncements(c.ClubId, accountId))
|
|
.Where(dto => dto != null && dto.Announcements.Count > 0)
|
|
.ToList()!;
|
|
}
|
|
|
|
public static ClubAnnouncementDTO ToAnnouncementDTO(ClubAnnouncement a) => new ClubAnnouncementDTO
|
|
{
|
|
AnnouncementId = a.AnnouncementId,
|
|
ClubId = a.ClubId,
|
|
CreatorAccountId = a.CreatorAccountId,
|
|
Title = a.Title,
|
|
Body = a.Body,
|
|
ImageName = a.ImageName,
|
|
Meta = a.Meta,
|
|
CreatedAt = a.CreatedAt
|
|
};
|
|
}
|
|
} |