Files
SocialPub/PrivaPub.ClientModels/Admin/Moderation.cs
T

159 lines
7.0 KiB
C#
Raw Normal View History

using PrivaPub.ClientModels.Resources;
using System.ComponentModel.DataAnnotations;
namespace PrivaPub.ClientModels.Admin
{
// The staff's acts on accounts and posts (completion program R6). Moderators silence and suspend personas here and
// accounts elsewhere, remove posts and resolve reports with one of those acts; administrators also change logins
// (roles, bans, deletions, two-factor sign-in). Every act is kept in the staff's log.
public static class ModerationActions
{
public const string None = "none";
public const string Silence = "silence";
public const string Unsilence = "unsilence";
public const string Suspend = "suspend";
public const string Unsuspend = "unsuspend";
public const string RemovePosts = "remove_posts";//a report's resolution only: the posts it names
public static bool IsAccountAction(string action) => action is Silence or Unsilence or Suspend or Unsuspend;
public static bool IsResolution(string action) => action is None or Silence or Suspend or RemovePosts;
}
// POST /clientapi/moderator/accounts/moderate: a persona here (its id) or an account elsewhere (its id here)
public class ModerateAccountForm
{
[Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(ErrorsResource)),
StringLength(64, ErrorMessageResourceName = "MaxLengthString", ErrorMessageResourceType = typeof(ErrorsResource))]
public string AccountId { get; set; }
[Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(ErrorsResource)),
StringLength(16, ErrorMessageResourceName = "MaxLengthString", ErrorMessageResourceType = typeof(ErrorsResource))]
public string Action { get; set; }//ModerationActions: silence, unsilence, suspend, unsuspend
// the staff's own words: kept in the log and on the account, never shown to it
[StringLength(1000, ErrorMessageResourceName = "MaxLengthString", ErrorMessageResourceType = typeof(ErrorsResource))]
public string Note { get; set; }
// what a persona here is told with its warning (Mastodon's moderation_warning); nothing reaches an account elsewhere
[StringLength(1000, ErrorMessageResourceName = "MaxLengthString", ErrorMessageResourceType = typeof(ErrorsResource))]
public string Warning { get; set; }
}
// POST /clientapi/moderator/posts/remove: a post here is deleted as its author would (the deletion federates), a copy of
// a post elsewhere is taken down here only
public class RemovePostForm
{
[Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(ErrorsResource)),
StringLength(64, ErrorMessageResourceName = "MaxLengthString", ErrorMessageResourceType = typeof(ErrorsResource))]
public string PostId { get; set; }
[StringLength(1000, ErrorMessageResourceName = "MaxLengthString", ErrorMessageResourceType = typeof(ErrorsResource))]
public string Note { get; set; }
[StringLength(1000, ErrorMessageResourceName = "MaxLengthString", ErrorMessageResourceType = typeof(ErrorsResource))]
public string Warning { get; set; }
}
// POST /clientapi/moderator/reports/{id}/resolve: the body is optional; without one, or with action none, the report is
// only marked resolved
public class ResolveReportForm
{
[StringLength(16, ErrorMessageResourceName = "MaxLengthString", ErrorMessageResourceType = typeof(ErrorsResource))]
public string Action { get; set; } = ModerationActions.None;//none, silence, suspend, remove_posts
[StringLength(1000, ErrorMessageResourceName = "MaxLengthString", ErrorMessageResourceType = typeof(ErrorsResource))]
public string Note { get; set; }
[StringLength(1000, ErrorMessageResourceName = "MaxLengthString", ErrorMessageResourceType = typeof(ErrorsResource))]
public string Warning { get; set; }
}
// an account as moderators see it: a persona here (never its login) or an account elsewhere, and what the staff did to it
public class ViewModeratedAccount
{
public string Id { get; set; }
public bool IsLocal { get; set; } = false;
public string UserName { get; set; }
public string DisplayName { get; set; }
public string Handle { get; set; }//user@host
public string Url { get; set; }//its actor's id
public string Domain { get; set; }
public DateTime? SilencedAt { get; set; }
public DateTime? SuspendedAt { get; set; }
public bool DomainSilenced { get; set; } = false;//an account elsewhere whose server is silenced: limited without its own silence
public bool DomainSuspended { get; set; } = false;
public string Note { get; set; }//the staff's last note on it
}
// GET /clientapi/moderator/accounts?q= and /clientapi/moderator/accounts/moderated?offset=&limit=: Next is the offset of
// the next page, null on the last
public class ViewModeratedAccountsPage
{
public List<ViewModeratedAccount> Items { get; set; } = [];
public int? Next { get; set; }
}
// a login as administrators see it (GET /clientapi/admin/roots), with its personas: only administrators ever read a login
// next to its personas
public class ViewAdminRoot
{
public string Id { get; set; }
public string UserName { get; set; }
public string Role { get; set; }//user, moderator, admin
public bool IsBanned { get; set; } = false;
public bool HasEmail { get; set; } = false;
public bool IsEmailValidated { get; set; } = false;
public bool HasTotp { get; set; } = false;
public bool IsYou { get; set; } = false;
public DateTime CreatedAt { get; set; }
public List<ViewAdminPersona> Personas { get; set; } = [];
}
public class ViewAdminPersona
{
public string Id { get; set; }
public string UserName { get; set; }
public string DisplayName { get; set; }
public string Handle { get; set; }
public DateTime? SilencedAt { get; set; }
public DateTime? SuspendedAt { get; set; }
public List<ViewAdminGroup> Groups { get; set; } = [];//the groups it owns
}
public class ViewAdminGroup
{
public string Id { get; set; }
public string UserName { get; set; }
public string Name { get; set; }
public bool IsCommunity { get; set; } = false;
public int MembersCount { get; set; } = 0;
}
// newest first; Next is the `before` of the next page, null on the last
public class ViewAdminRootsPage
{
public List<ViewAdminRoot> Items { get; set; } = [];
public string Next { get; set; }
}
// POST /clientapi/admin/roots/{id}/role
public class RootRoleForm
{
[Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(ErrorsResource)),
StringLength(16, ErrorMessageResourceName = "MaxLengthString", ErrorMessageResourceType = typeof(ErrorsResource))]
public string Role { get; set; }//user, moderator, admin
}
// what can't be undone asks for the administrator's own password: deleting a persona or a group
public class AdminPasswordForm
{
[Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(ErrorsResource)),
Display(Name = "Password", ResourceType = typeof(FieldsNameResource))]
public string Password { get; set; }
[StringLength(1000, ErrorMessageResourceName = "MaxLengthString", ErrorMessageResourceType = typeof(ErrorsResource))]
public string Note { get; set; }
}
}