Barebones, untested sort/filtering
This commit is contained in:
		| @@ -100,7 +100,7 @@ namespace PluralKit.Bot | ||||
|             if (ctx.Match("list", "l", "members")) | ||||
|                 return ctx.Execute<SystemList>(SystemList, m => m.MemberList(ctx, ctx.System)); | ||||
|             if (ctx.Match("f", "find", "search", "query", "fd")) | ||||
|                 return ctx.Execute<SystemList>(SystemFind, m => m.MemberFind(ctx, ctx.System)); | ||||
|                 return ctx.Execute<SystemList>(SystemFind, m => m.MemberList(ctx, ctx.System)); | ||||
|             if (ctx.Match("link")) | ||||
|                 return ctx.Execute<SystemLink>(Link, m => m.LinkSystem(ctx)); | ||||
|             if (ctx.Match("unlink")) | ||||
| @@ -188,7 +188,7 @@ namespace PluralKit.Bot | ||||
|             else if (ctx.Match("list", "l", "members")) | ||||
|                 await ctx.Execute<SystemList>(SystemList, m => m.MemberList(ctx, ctx.System)); | ||||
|             else if (ctx.Match("find", "search", "query", "fd", "s")) | ||||
|                 await ctx.Execute<SystemList>(SystemFind, m => m.MemberFind(ctx, ctx.System)); | ||||
|                 await ctx.Execute<SystemList>(SystemFind, m => m.MemberList(ctx, ctx.System)); | ||||
|             else if (ctx.Match("f", "front", "fronter", "fronters")) | ||||
|             { | ||||
|                 if (ctx.Match("h", "history")) | ||||
| @@ -225,7 +225,7 @@ namespace PluralKit.Bot | ||||
|             else if (ctx.Match("list", "l", "members")) | ||||
|                 await ctx.Execute<SystemList>(SystemList, m => m.MemberList(ctx, target)); | ||||
|             else if (ctx.Match("find", "search", "query", "fd", "s")) | ||||
|                 await ctx.Execute<SystemList>(SystemFind, m => m.MemberFind(ctx, target)); | ||||
|                 await ctx.Execute<SystemList>(SystemFind, m => m.MemberList(ctx, target)); | ||||
|             else if (ctx.Match("f", "front", "fronter", "fronters")) | ||||
|             { | ||||
|                 if (ctx.Match("h", "history")) | ||||
|   | ||||
| @@ -1,11 +1,9 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Text; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| using DSharpPlus.Entities; | ||||
|  | ||||
| using Humanizer; | ||||
| using Dapper; | ||||
|  | ||||
| using PluralKit.Core; | ||||
|  | ||||
| @@ -13,124 +11,70 @@ namespace PluralKit.Bot | ||||
| { | ||||
|     public class SystemList | ||||
|     { | ||||
|         private IDataStore _data; | ||||
|  | ||||
|         public SystemList(IDataStore data) | ||||
|         private readonly DbConnectionFactory _db; | ||||
|          | ||||
|         public SystemList(DbConnectionFactory db) | ||||
|         { | ||||
|             _data = data; | ||||
|             _db = db; | ||||
|         } | ||||
|  | ||||
|         private async Task RenderMemberList(Context ctx, PKSystem system, bool canShowPrivate, int membersPerPage, string embedTitle, Func<PKMember, bool> filter, | ||||
|                                             Func<DiscordEmbedBuilder, IEnumerable<PKMember>, Task> | ||||
|                                                 renderer) | ||||
|         public async Task MemberList(Context ctx, PKSystem target) | ||||
|         { | ||||
|             var authCtx = ctx.LookupContextFor(system); | ||||
|             var shouldShowPrivate = authCtx == LookupContext.ByOwner && canShowPrivate; | ||||
|  | ||||
|             var membersToShow = await _data.GetSystemMembers(system) | ||||
|                 .Where(filter) | ||||
|                 .OrderBy(m => m.Name, StringComparer.InvariantCultureIgnoreCase) | ||||
|                 .ToListAsync(); | ||||
|  | ||||
|             var membersToShowWithPrivacy = membersToShow | ||||
|                 .Where(m => m.MemberPrivacy == PrivacyLevel.Public || shouldShowPrivate) | ||||
|                 .ToList(); | ||||
|              | ||||
|             var anyMembersHidden = !shouldShowPrivate && membersToShowWithPrivacy.Count != membersToShow.Count; | ||||
|             if (target == null) throw Errors.NoSystemError; | ||||
|             ctx.CheckSystemPrivacy(target, target.MemberListPrivacy); | ||||
|  | ||||
|             // GetRendererFor must be called before GetOptions as it consumes a potential positional full argument that'd otherwise land in the filter | ||||
|             var renderer = GetRendererFor(ctx); | ||||
|             var opts = GetOptions(ctx, target); | ||||
|             var members = await GetMemberList(target, opts); | ||||
|             await ctx.Paginate( | ||||
|                 membersToShowWithPrivacy.ToAsyncEnumerable(), | ||||
|                 membersToShowWithPrivacy.Count, | ||||
|                 membersPerPage, | ||||
|                 embedTitle, | ||||
|                 members.ToAsyncEnumerable(), | ||||
|                 members.Count, | ||||
|                 renderer.MembersPerPage, | ||||
|                 GetEmbedTitle(target, opts), | ||||
|                 (eb, ms) => | ||||
|                 { | ||||
|                     var footer = $"{membersToShowWithPrivacy.Count} total."; | ||||
|                     if (anyMembersHidden && authCtx == LookupContext.ByOwner) | ||||
|                         footer += " Private members have been hidden. Add \"all\" to the command to include them."; | ||||
|                     eb.WithFooter(footer); | ||||
|                      | ||||
|                     return renderer(eb, ms); | ||||
|                     eb.WithFooter($"{members.Count} total."); | ||||
|                     renderer.RenderPage(eb, ms); | ||||
|                     return Task.CompletedTask; | ||||
|                 }); | ||||
|         } | ||||
|  | ||||
|         private Task ShortRenderer(DiscordEmbedBuilder eb, IEnumerable<PKMember> members) | ||||
|         private async Task<IReadOnlyList<PKListMember>> GetMemberList(PKSystem target, SortFilterOptions opts) | ||||
|         { | ||||
|             eb.Description = string.Join("\n", members.Select((m) => | ||||
|             { | ||||
|                 if (m.HasProxyTags) | ||||
|                 { | ||||
|                     var proxyTagsString = m.ProxyTagsString().SanitizeMentions(); | ||||
|                     if (proxyTagsString.Length > 100) // arbitrary threshold for now, tweak? | ||||
|                         proxyTagsString = "tags too long, see member card"; | ||||
|  | ||||
|                     return $"[`{m.Hid}`] **{m.Name.SanitizeMentions()}** *({proxyTagsString})*"; | ||||
|                 } | ||||
|  | ||||
|                 return $"[`{m.Hid}`] **{m.Name.SanitizeMentions()}**"; | ||||
|             })); | ||||
|              | ||||
|             return Task.CompletedTask; | ||||
|             using var conn = await _db.Obtain(); | ||||
|             var args = new {System = target.Id, opts.Filter}; | ||||
|             return (await conn.QueryAsync<PKListMember>(opts.BuildQuery(), args)).ToList(); | ||||
|         } | ||||
|  | ||||
|         private Task LongRenderer(DiscordEmbedBuilder eb, IEnumerable<PKMember> members) | ||||
|         private string GetEmbedTitle(PKSystem target, SortFilterOptions opts) | ||||
|         { | ||||
|             foreach (var m in members) | ||||
|             { | ||||
|                 var profile = $"**ID**: {m.Hid}"; | ||||
|                 if (m.DisplayName != null) profile += $"\n**Display name**: {m.DisplayName}"; | ||||
|                 if (m.Pronouns != null) profile += $"\n**Pronouns**: {m.Pronouns}"; | ||||
|                 if (m.Birthday != null) profile += $"\n**Birthdate**: {m.BirthdayString}"; | ||||
|                 if (m.ProxyTags.Count > 0) profile += $"\n**Proxy tags:** {m.ProxyTagsString()}"; | ||||
|                 if (m.Description != null) profile += $"\n\n{m.Description}"; | ||||
|                 if (m.MemberPrivacy == PrivacyLevel.Private) | ||||
|                     profile += "\n*(this member is private)*"; | ||||
|  | ||||
|                 eb.AddField(m.Name, profile.Truncate(1024)); | ||||
|             } | ||||
|  | ||||
|             return Task.CompletedTask; | ||||
|             var title = new StringBuilder("Members of "); | ||||
|              | ||||
|             if (target.Name != null) title.Append($"{target.Name.SanitizeMentions()} (`{target.Hid}`)"); | ||||
|             else title.Append($"`{target.Hid}`"); | ||||
|   | ||||
|             if (opts.Filter != null) title.Append($"matching **{opts.Filter.SanitizeMentions()}**"); | ||||
|              | ||||
|             return title.ToString(); | ||||
|         } | ||||
|  | ||||
|         public async Task MemberList(Context ctx, PKSystem system) | ||||
|         private SortFilterOptions GetOptions(Context ctx, PKSystem target) | ||||
|         { | ||||
|             if (system == null) throw Errors.NoSystemError; | ||||
|             ctx.CheckSystemPrivacy(system, system.MemberListPrivacy); | ||||
|  | ||||
|             var embedTitle = system.Name != null | ||||
|                 ? $"Members of {system.Name.SanitizeMentions()} (`{system.Hid}`)" | ||||
|                 : $"Members of `{system.Hid}`"; | ||||
|  | ||||
|             var shouldShowLongList = ctx.Match("f", "full", "big", "details", "long"); | ||||
|             var canShowPrivate = ctx.Match("a", "all", "everyone", "private"); | ||||
|             if (shouldShowLongList) | ||||
|                 await RenderMemberList(ctx, system,  canShowPrivate, 5, embedTitle, _ => true, LongRenderer); | ||||
|             else  | ||||
|                 await RenderMemberList(ctx, system,  canShowPrivate, 25, embedTitle, _ => true, ShortRenderer); | ||||
|             var opts = SortFilterOptions.FromFlags(ctx); | ||||
|             opts.Filter = ctx.RemainderOrNull(); | ||||
|             // If we're *explicitly* trying to access non-public members of another system, error | ||||
|             if (opts.PrivacyFilter != PrivacyFilter.PublicOnly && ctx.LookupContextFor(target) != LookupContext.ByOwner) | ||||
|                 throw new PKError("You cannot look up private members of another system."); | ||||
|             return opts; | ||||
|         } | ||||
|  | ||||
|         public async Task MemberFind(Context ctx, PKSystem system) | ||||
|         private IListRenderer GetRendererFor(Context ctx) | ||||
|         { | ||||
|             if (system == null) throw Errors.NoSystemError; | ||||
|             ctx.CheckSystemPrivacy(system, system.MemberListPrivacy); | ||||
|  | ||||
|             var shouldShowLongList = ctx.Match("full", "big", "details", "long") || ctx.MatchFlag("f", "full"); | ||||
|             var canShowPrivate = ctx.Match("all", "everyone", "private") || ctx.MatchFlag("a", "all"); | ||||
|  | ||||
|             var searchTerm = ctx.RemainderOrNull() ?? throw new PKSyntaxError("You must specify a search term."); | ||||
|              | ||||
|             var embedTitle = system.Name != null | ||||
|                 ? $"Members of {system.Name.SanitizeMentions()} (`{system.Hid}`) matching **{searchTerm.SanitizeMentions()}**" | ||||
|                 : $"Members of `{system.Hid}` matching **{searchTerm.SanitizeMentions()}**"; | ||||
|  | ||||
|             bool Filter(PKMember member) => | ||||
|                 member.Name.Contains(searchTerm, StringComparison.InvariantCultureIgnoreCase) || | ||||
|                 (member.DisplayName?.Contains(searchTerm, StringComparison.InvariantCultureIgnoreCase) ?? false); | ||||
|              | ||||
|             if (shouldShowLongList) | ||||
|                 await RenderMemberList(ctx, system,  canShowPrivate, 5, embedTitle, Filter, LongRenderer); | ||||
|             else  | ||||
|                 await RenderMemberList(ctx, system,  canShowPrivate, 25, embedTitle, Filter, ShortRenderer); | ||||
|             var longList = ctx.Match("f", "full", "big", "details", "long") || ctx.MatchFlag("f", "full"); | ||||
|             if (longList) | ||||
|                 return new LongRenderer(LongRenderer.MemberFields.FromFlags(ctx)); | ||||
|             return new ShortRenderer(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										12
									
								
								PluralKit.Bot/Lists/IListRenderer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								PluralKit.Bot/Lists/IListRenderer.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| using DSharpPlus.Entities; | ||||
|  | ||||
| namespace PluralKit.Bot | ||||
| { | ||||
|     public interface IListRenderer | ||||
|     { | ||||
|         int MembersPerPage { get; } | ||||
|         void RenderPage(DiscordEmbedBuilder eb, IEnumerable<PKListMember> members); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										62
									
								
								PluralKit.Bot/Lists/LongRenderer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								PluralKit.Bot/Lists/LongRenderer.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| using DSharpPlus.Entities; | ||||
|  | ||||
| using Humanizer; | ||||
|  | ||||
| using PluralKit.Core; | ||||
|  | ||||
| namespace PluralKit.Bot | ||||
| { | ||||
|     public class LongRenderer: IListRenderer | ||||
|     { | ||||
|         public int MembersPerPage => 5; | ||||
|  | ||||
|         private readonly MemberFields _fields; | ||||
|         public LongRenderer(MemberFields fields) | ||||
|         { | ||||
|             _fields = fields; | ||||
|         } | ||||
|  | ||||
|         public void RenderPage(DiscordEmbedBuilder eb, IEnumerable<PKListMember> members) | ||||
|         { | ||||
|             foreach (var m in members) | ||||
|             { | ||||
|                 var profile = $"**ID**: {m.Hid}"; | ||||
|                 if (_fields.ShowDisplayName && m.DisplayName != null) profile += $"\n**Display name**: {m.DisplayName}"; | ||||
|                 if (_fields.ShowPronouns && m.Pronouns != null) profile += $"\n**Pronouns**: {m.Pronouns}"; | ||||
|                 if (_fields.ShowBirthday && m.Birthday != null) profile += $"\n**Birthdate**: {m.BirthdayString}"; | ||||
|                 if (_fields.ShowPronouns && m.ProxyTags.Count > 0) profile += $"\n**Proxy tags:** {m.ProxyTagsString()}"; | ||||
|                 if (_fields.ShowMessageCount && m.MessageCount > 0) profile += $"\n**Message count:** {m.MessageCount}"; | ||||
|                 if (_fields.ShowDescription && m.Description != null) profile += $"\n\n{m.Description}"; | ||||
|                 if (_fields.ShowPrivacy && m.MemberPrivacy == PrivacyLevel.Private) | ||||
|                     profile += "\n*(this member is private)*"; | ||||
|  | ||||
|                 eb.AddField(m.Name, profile.Truncate(1024)); | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         public class MemberFields | ||||
|         { | ||||
|             public bool ShowDisplayName = true; | ||||
|             public bool ShowCreated = true; | ||||
|             public bool ShowMessageCount = true; | ||||
|             public bool ShowPronouns = true; | ||||
|             public bool ShowBirthday = true; | ||||
|             public bool ShowProxyTags = true; | ||||
|             public bool ShowDescription = true; | ||||
|             public bool ShowPrivacy = true; | ||||
|              | ||||
|             public static MemberFields FromFlags(Context ctx) | ||||
|             { | ||||
|                 // TODO | ||||
|                 return new MemberFields | ||||
|                 { | ||||
|                     ShowMessageCount = false, | ||||
|                     ShowCreated = false | ||||
|                 }; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										9
									
								
								PluralKit.Bot/Lists/PKListMember.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								PluralKit.Bot/Lists/PKListMember.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| using PluralKit.Core; | ||||
|  | ||||
| namespace PluralKit.Bot | ||||
| { | ||||
|     public class PKListMember: PKMember | ||||
|     { | ||||
|         public int MessageCount { get; set; } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										30
									
								
								PluralKit.Bot/Lists/ShortRenderer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								PluralKit.Bot/Lists/ShortRenderer.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
|  | ||||
| using DSharpPlus.Entities; | ||||
|  | ||||
| namespace PluralKit.Bot | ||||
| { | ||||
|     public class ShortRenderer: IListRenderer | ||||
|     { | ||||
|         public int MembersPerPage => 25; | ||||
|          | ||||
|         public void RenderPage(DiscordEmbedBuilder eb, IEnumerable<PKListMember> members) | ||||
|         { | ||||
|             eb.Description = string.Join("\n", members.Select(m => | ||||
|             { | ||||
|                 if (m.HasProxyTags) | ||||
|                 { | ||||
|                     var proxyTagsString = m.ProxyTagsString().SanitizeMentions(); | ||||
|                     if (proxyTagsString.Length > 100) // arbitrary threshold for now, tweak? | ||||
|                         proxyTagsString = "tags too long, see member card"; | ||||
|  | ||||
|                     return $"[`{m.Hid}`] **{m.Name.SanitizeMentions()}** *({proxyTagsString})*"; | ||||
|                 } | ||||
|  | ||||
|                 return $"[`{m.Hid}`] **{m.Name.SanitizeMentions()}**"; | ||||
|             })); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										154
									
								
								PluralKit.Bot/Lists/SortFilterOptions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								PluralKit.Bot/Lists/SortFilterOptions.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,154 @@ | ||||
| using System.Text; | ||||
|  | ||||
| using PluralKit.Core; | ||||
|  | ||||
| namespace PluralKit.Bot | ||||
| { | ||||
|     public class SortFilterOptions | ||||
|     { | ||||
|         public SortProperty SortProperty = SortProperty.Name; | ||||
|         public SortDirection Direction = SortDirection.Ascending; | ||||
|         public PrivacyFilter PrivacyFilter = PrivacyFilter.PublicOnly; | ||||
|         public string Filter = null; | ||||
|         public bool SearchInDescription = false; | ||||
|  | ||||
|         public string CreateFilterString() | ||||
|         { | ||||
|             // TODO | ||||
|             return "uwu"; | ||||
|         } | ||||
|  | ||||
|         public string BuildQuery() | ||||
|         { | ||||
|             // Select clause | ||||
|             StringBuilder query = new StringBuilder(); | ||||
|             query.Append(SortProperty switch | ||||
|             { | ||||
|                 SortProperty.MessageCount => | ||||
|                 "select members.*, count(messages.*) as message_count, max(messages.mid) as last_message from members", | ||||
|                 SortProperty.LastMessage => | ||||
|                 "select members.*, count(messages.*) as message_count, max(messages.mid) as last_message from members", | ||||
|                 SortProperty.LastSwitch => "select members.*, max(switches.timestamp) as last_switch_time from members", | ||||
|                 _ => "select members.* from members" | ||||
|             }); | ||||
|  | ||||
|             // Join clauses | ||||
|             query.Append(SortProperty switch | ||||
|             { | ||||
|                 SortProperty.MessageCount => " left join messages on messages.member = members.id", | ||||
|                 SortProperty.LastMessage => " left join messages on messages.member = members.id", | ||||
|                 SortProperty.LastSwitch => | ||||
|                 " left join switch_members on switch_members.member = members.id left join switches on switch_members.switch = switches.id", | ||||
|                 _ => "" | ||||
|             }); | ||||
|  | ||||
|             // Where clauses | ||||
|             query.Append(" where members.system = @System"); | ||||
|  | ||||
|             // Privacy filter | ||||
|             query.Append(PrivacyFilter switch | ||||
|             { | ||||
|                 PrivacyFilter.PrivateOnly => $" and members.member_privacy = {(int) PrivacyLevel.Private}", | ||||
|                 PrivacyFilter.PublicOnly => $" and members.member_privacy = {(int) PrivacyLevel.Public}", | ||||
|                 _ => "" | ||||
|             }); | ||||
|  | ||||
|             // String filter | ||||
|             if (Filter != null) | ||||
|             { | ||||
|                 // Use position rather than ilike to not bother with escaping and such | ||||
|                 query.Append(" and ("); | ||||
|                 query.Append( | ||||
|                     "position(lower(@Filter) in lower(members.name)) > 0 or position(lower(@Filter) in lower(coalesce(members.display_name, ''))) > 0"); | ||||
|                 if (SearchInDescription) | ||||
|                     query.Append(" or position(lower(@Filter) in lower(coalesce(members.description, ''))) > 0"); | ||||
|                 query.Append(")"); | ||||
|             } | ||||
|  | ||||
|             // Group clause | ||||
|             query.Append(SortProperty switch | ||||
|             { | ||||
|                 SortProperty.MessageCount => " group by members.id", | ||||
|                 SortProperty.LastMessage => " group by members.id", | ||||
|                 SortProperty.LastSwitch => " group by members.id", | ||||
|                 _ => "" | ||||
|             }); | ||||
|  | ||||
|             // Order clause | ||||
|             query.Append(SortProperty switch | ||||
|             { | ||||
|                 SortProperty.Hid => " order by members.hid", | ||||
|                 SortProperty.CreationDate => " order by members.created", | ||||
|                 SortProperty.Birthdate => | ||||
|                 " order by extract(month from members.birthday), extract(day from members.birthday)", | ||||
|                 SortProperty.MessageCount => " order by count(messages.mid)", | ||||
|                 SortProperty.LastMessage => " order by max(messages.mid)", | ||||
|                 SortProperty.LastSwitch => " order by max(switches.timestamp)", | ||||
|                 _ => " order by members.name" | ||||
|             }); | ||||
|  | ||||
|             // Order direction | ||||
|             if (Direction == SortDirection.Descending) | ||||
|                 query.Append(" desc"); | ||||
|  | ||||
|             return query.ToString(); | ||||
|         } | ||||
|  | ||||
|         public static SortFilterOptions FromFlags(Context ctx) | ||||
|         { | ||||
|             var p = new SortFilterOptions(); | ||||
|              | ||||
|             // Direction | ||||
|             if (ctx.MatchFlag("r", "rev", "reverse", "desc", "descending")) | ||||
|                 p.Direction = SortDirection.Descending; | ||||
|              | ||||
|             // Sort | ||||
|             if (ctx.MatchFlag("by-id", "bi")) | ||||
|                 p.SortProperty = SortProperty.Hid; | ||||
|             else if (ctx.MatchFlag("by-msgcount", "by-mc", "by-msgs", "bm")) | ||||
|                 p.SortProperty = SortProperty.MessageCount; | ||||
|             else if (ctx.MatchFlag("by-date", "by-time", "by-created", "bc")) | ||||
|                 p.SortProperty = SortProperty.CreationDate; | ||||
|             else if (ctx.MatchFlag("by-switch")) | ||||
|                 p.SortProperty = SortProperty.LastSwitch; | ||||
|             else if (ctx.MatchFlag("by-last-message")) | ||||
|                 p.SortProperty = SortProperty.LastMessage; | ||||
|              | ||||
|             // Description | ||||
|             if (ctx.MatchFlag("desc")) | ||||
|                 p.SearchInDescription = true; | ||||
|              | ||||
|             // Privacy | ||||
|             if (ctx.MatchFlag("a", "all")) | ||||
|                 p.PrivacyFilter = PrivacyFilter.All; | ||||
|             else if (ctx.MatchFlag("po", "private", "private-only", "only-private", "priv")) | ||||
|                 p.PrivacyFilter = PrivacyFilter.PrivateOnly; | ||||
|              | ||||
|             return p; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public enum SortProperty | ||||
|     { | ||||
|         Name, | ||||
|         Hid, | ||||
|         MessageCount, | ||||
|         CreationDate, | ||||
|         LastSwitch, | ||||
|         LastMessage, | ||||
|         Birthdate | ||||
|     } | ||||
|  | ||||
|     public enum SortDirection | ||||
|     { | ||||
|         Ascending, | ||||
|         Descending | ||||
|     } | ||||
|  | ||||
|     public enum PrivacyFilter | ||||
|     { | ||||
|         All, | ||||
|         PublicOnly, | ||||
|         PrivateOnly | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user