Иконка ресурса

FREE Tickets : 1.1.0 1.1.0

Нет прав для скачивания
C#:
using Oxide.Core;
using Oxide.Core.Libraries;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using UnityEngine;

namespace Oxide.Plugins
{
    static class Extension
    {
        public static void TicketReply(this IPlayer player, string msg, bool noPrefix = false)
        {
            if (!player.IsServer)
            {
                if (!noPrefix) if (!msg.StartsWith("[Tickets]")) msg = "[Tickets] " + msg;
                msg = msg.Replace("[Tickets]", "<color=#C4FF00>[Tickets]</color>");
                msg = msg.Replace("[OPEN]", "<color=#C4FF00>[OPEN]</color>");
                msg = msg.Replace("[CLOSED]", "<color=red>[CLOSED]</color>");
            }
            else msg = Tickets.instance.RemoveTags(msg);
            player.Reply(msg);
        }
    }

    [Info("Tickets", "MBR", "1.1.0")]
    class Tickets : RustPlugin
    {
        [PluginReference] private readonly Plugin DiscordAPI2, Compilation, PRISMID;

        private const string base_url = "https://prismrust.com";
        public List<Ticket> tickets = new List<Ticket>();
        public static Tickets instance;
        private readonly Dictionary<IPlayer, float> cooldown = new Dictionary<IPlayer, float>();

        private static string ServerId
        {
            get
            {
                if (!(instance.PRISMID?.IsLoaded ?? false))
                {
                    throw new Exception("PRISMID is not loaded");
                }

                return instance.PRISMID.Call<string>("GetServerTypeString");
            }
        }

        private static int ServerIdInt
        {
            get
            {
                if (!(instance.PRISMID?.IsLoaded ?? false))
                {
                    throw new Exception("PRISMID is not loaded");
                }

                return instance.PRISMID.Call<int>("GetServerTypeInt");
            }
        }

        #region Hooks

        private void OnServerInitialized()
        {
            instance = this;

            AddCovalenceCommand(new string[] { "ticket" }, nameof(TicketCMD));
            AddCovalenceCommand(new string[] { "report" }, nameof(ReportCMD));

            timer.Once(2f, Update);
            timer.Every(3600f, Update);
        }

        private void Unload()
        {
            instance = null;
        }

        private void OnUserConnected(IPlayer player)
        {
            if (player.IsAdmin)
            {
                player.TicketReply("Welcome, there are " + tickets.Where(x => x.Open).Count() + " open tickets");
            }
        }

        void OnPlayerReported(BasePlayer reporter, string targetName, string targetId, string subject, string message, string type)
        {
            if (type == "name" || type == "abusive") return;

            var player = reporter.IPlayer;

            if (cooldown.ContainsKey(player))
            {
                if (UnityEngine.Time.realtimeSinceStartup < cooldown[player] && !player.IsAdmin)
                {
                    player.TicketReply("You are creating tickets too fast, try again in " + System.Math.Round((cooldown[player] - UnityEngine.Time.realtimeSinceStartup), 2) + "s");
                    return;
                }

                cooldown.Remove(player);
            }

            cooldown.Add(player, UnityEngine.Time.realtimeSinceStartup + 10);

            var target = covalence.Players.FindPlayerById(targetId) ?? null;

            if (target != null)
            {
                if (target.Id == "76561198865536053" || target.Id == "76561198886960011")
                {
                    Puts("Ignoring report by " + player + " for PRISM account");
                    player.TicketReply("Ticket creation failed: \"PRISM\" cannot be reported");
                    return;
                }
            }

            CreateTicket(player, (subject + "\n\n" + message).Replace("[" + type + "]", "").Trim(), target);
        }

        #endregion

        #region Methods

        private void CloseOnBan(string id)
        {
            if (!id.StartsWith("765611") || id.Length < 15) return;

            var tickets1 = tickets.Where(x => (x.reported?.id ?? "") == id && x.Open);
            var tickets2 = tickets.Where(x => x.creator.id == id && x.Open);

            if (tickets1.Count() > 0)
            {
                if (tickets1.Count() == 1)
                {
                    tickets1.First().Close(Ticket.TicketUser.server, "Reported person was banned");
                    return;
                }

                BulkDelete(tickets1.ToList(), "Reported person was banned", Ticket.TicketUser.server);
            }

            if (tickets2.Count() > 0)
            {
                BulkDelete(tickets2.ToList(), "Ticket creator was banned", Ticket.TicketUser.server);
            }
        }

        private void CreateTicket(IPlayer player, string command, string[] args)
        {
            if (player.IsServer)
            {
                player.TicketReply("Server Console cannot create tickets!");
                return;
            }

            if (args.Length > 0 && args[0].ToLower().Trim() == "create") args = args.Skip(1).ToArray();
            if (args.Length < 1)
            {
                player.TicketReply("Please specify your reason for creating a ticket.");    
                return;
            }

            if (cooldown.ContainsKey(player))
            {
                if (UnityEngine.Time.realtimeSinceStartup < cooldown[player] && !player.IsAdmin)
                {
                    player.TicketReply("You are creating tickets too fast, try again in " + System.Math.Round((cooldown[player] - UnityEngine.Time.realtimeSinceStartup), 2) + "s");
                    return;
                }

                cooldown.Remove(player);
            }

            CreateTicket(player, string.Join(" ", args), (IPlayer)null);
        }

        public Ticket Find(int ID)
        {
            foreach (var ticket in tickets)
            {
                if (ticket.id == ID) return ticket;
            }

            return null;
        }

        public int ReportsForPlayer(string id)
        {
            return tickets.Where(x => x.Open && (x.reported?.id ?? "") == id).Count();
        }

        public void BulkDelete(List<Ticket> tickets, string reason, Ticket.TicketUser issuer)
        {
            BulkDelete(tickets.Select(x => x._id).ToList(), reason, issuer);
        }

        public void BulkDelete(List<string> unique_ids, string reason, Ticket.TicketUser issuer)
        {
            var data = new
            {
                tickets = unique_ids,
                by = issuer,
                reason,
            };

            CreateInternalRequest(base_url + "/api/tickets/bulk-close", Utility.ConvertToJson(data, true), RequestMethod.POST);
        }

        public void Update()
        {
            CreateInternalRequest(base_url + "/api/tickets", null, RequestMethod.GET, (code, response) =>
            {
                if (code >= 400 || string.IsNullOrEmpty(response))
                {
                    SendToMothership("Failed to update ticket list, code: " + code + ", response: " + response);
                    return;
                }

                List<Ticket> list = null;

                try { list = Utility.ConvertFromJson<List<Ticket>>(response); }
                catch (Exception e)
                {
                    instance.PrintWarning("Exception while fetching ticket list!\n" + e);
                    return;
                }

                tickets = list.Where(x => x.server == ServerIdInt).ToList();
            });
        }

        #endregion

        #region Commands

        [ConsoleCommand("ticketlist.json")]
        private void TicketJSONCMD(ConsoleSystem.Arg arg)
        {
            if (arg.Connection != null) return;
            arg.ReplyWith(Utility.ConvertToJson(instance.tickets));
        }

        private void TicketCMD(IPlayer player, string command, string[] args)
        {
            if (args.Length < 1)
            {
                var cases = new List<string> {
                    "/" + command + " create <i>text</i>",
                    "/" + command + " close <i>ticket ID</i>",
                    "/" + command + " reply <i>ticket ID</i> <i>text</i>",
                    "/" + command + " view <i>ticket ID</i>",
                    "/" + command + " list" + (player.IsAdmin ? " <i>all</i>" : ""),
                    player.IsAdmin ? "/" + command + " teleport <i>ticket ID</i>" : "",
                };

                player.TicketReply("Please supply a player name & reason to report them, or otherwise specify your reason for making a report/ticket.");
                player.TicketReply("Invalid syntax!\n" + string.Join("\n", cases));
                return;
            }

            switch (args[0].ToLower())
            {
                case "close":
                    {
                        args = args.Skip(1).ToArray();

                        if (args.Length < 1)
                        {
                            player.TicketReply("You did not provide ticket ID!");
                            return;
                        }

                        var ID_str = args[0];
                        var ID = -1;
                        if (!int.TryParse(ID_str, out ID))
                        {
                            player.TicketReply(ID_str + " is not a number!");
                            return;
                        }

                        if (ID == -1)
                        {
                            player.TicketReply("Invalid ticket ID (" + ID + ")");
                            return;
                        }

                        var ticket = Find(ID);
                        if (ticket == null)
                        {
                            player.TicketReply("Couldn't find a ticket with ID " + ID);
                            return;
                        }

                        if (ticket.creator.id != player.Id && !player.IsAdmin)
                        {
                            player.TicketReply("You can only close your own tickets!");
                            return;
                        }

                        if (!ticket.Open)
                        {
                            player.TicketReply("This ticket is already closed.");
                            return;
                        }

                        if (args.Length < 2) ticket.Close(player);
                        else ticket.Close(player, string.Join(" ", args.Skip(1)));

                        return;
                    }

                case "teleport":
                    {
                        if (!player.IsAdmin) return;

                        if (player.IsServer)
                        {
                            player.Reply("Server Console cannot teleport!");
                            return;
                        }

                        args = args.Skip(1).ToArray();

                        if (args.Length < 1)
                        {
                            player.TicketReply("You did not provide ticket ID!");
                            return;
                        }

                        var ID_str = args[0];
                        var ID = -1;
                        if (!int.TryParse(ID_str, out ID))
                        {
                            player.TicketReply(ID_str + " is not a number!");
                            return;
                        }

                        if (ID == -1)
                        {
                            player.TicketReply("Invalid ticket ID (" + ID + ")");
                            return;
                        }

                        var ticket = Find(ID);
                        if (ticket == null)
                        {
                            player.Reply("Couldn't find a ticket with ID " + ID);
                            return;
                        }

                        TeleportPlayer(player.Object as BasePlayer, new Vector3(ticket.position[0], ticket.position[1], ticket.position[2]));
                        player.Reply("You were teleported to " + ticket.position.ToString());
                        return;
                    }

                case "view":
                    {
                        args = args.Skip(1).ToArray();

                        if (args.Length < 1)
                        {
                            player.TicketReply("You did not provide ticket ID!");
                            return;
                        }

                        var ID_str = args[0];
                        var ID = -1;
                        if (!int.TryParse(ID_str, out ID))
                        {
                            player.TicketReply(ID_str + " is not a number!");
                            return;
                        }

                        if (ID == -1)
                        {
                            player.TicketReply("Invalid ticket ID (" + ID + ")");
                            return;
                        }

                        var ticket = Find(ID);
                        if (ticket == null)
                        {
                            player.Reply("Couldn't find a ticket with ID " + ID);
                            return;
                        }

                        if (ticket.creator.id != player.Id && !player.IsAdmin) return;

                        var replySB = new StringBuilder();
                        var replyList = new List<StringBuilder>();

                        var msg = "[Tickets] [" + (ticket.Open ? "OPEN" : "CLOSED") + "] Viewing Ticket #" + ticket.id + " by " + ticket.creator + "\n" + (ticket.reported == null ? "" : "\nReported person: " + ticket.reported + "\n");

                        var replies = ticket.replies.Where(x => x.content != "Automated Report").Select(x => x.ToString()).ToList();

                        if (!ticket.Open) replies.Add("Closed by <color=#C4FF00>" + ticket.closed.by.name + "</color> at " + ticket.closed.at.ToString() + " UTC" + (string.IsNullOrEmpty(ticket.closed.reason) ? "" : " - " + ticket.closed.reason));

                        if (replies.Count() > 0) msg += string.Join("\n", replies);

                        for (int i = 0; i < msg.Length; i++)
                        {
                            var chr = msg[i];
                            if (replySB.Length >= 768)
                            {
                                replyList.Add(replySB);
                                replySB = new StringBuilder();
                            }
                            replySB.Append(chr);
                        }

                        if (replyList.Count > 0) for (int i = 0; i < replyList.Count; i++) player.TicketReply(replyList[i].ToString());
                        if (replySB.Length > 0) player.TicketReply(replySB.ToString());
                        return;
                    }

                case "list":
                    {
                        bool all = false;
                        if (args.Length > 1 && args[1].ToLower() == "all" && (player.IsAdmin || player.IsServer)) all = true;
                        var list = tickets.Where(x => (all || x.Open) && (player.IsAdmin || x.creator.id == player.Id)).Select(x => "[" + (x.Open ? "OPEN" : "CLOSED") + "] Ticket #" + x.id + " by " + x.creator.name).ToList();
                        var ticketSBF = new StringBuilder();
                        var finishSB = new List<StringBuilder>();
                        var isServer = player.IsServer;

                        for (int i = 0; i < list.Count; i++)
                        {
                            var ticketStr = list[i];
                            if (string.IsNullOrEmpty(ticketStr)) continue;
                            var removeTagsStr = RemoveTags(ticketStr);
                            if (!isServer && (ticketSBF.Length + removeTagsStr.Length) > 700)
                            {
                                finishSB.Add(ticketSBF);
                                ticketSBF = new StringBuilder();
                            }
                            ticketSBF.AppendLine(removeTagsStr);
                        }

                        if (ticketSBF.Length < 1) player.TicketReply("No tickets!");
                        else
                        {
                            player.TicketReply("List of " + (all ? "all" : "open") + " tickets");
                            if (finishSB.Count > 0) for (int i = 0; i < finishSB.Count; i++) player.TicketReply(finishSB[i].ToString().TrimEnd(), true);
                            player.TicketReply(ticketSBF.ToString().TrimEnd(), true);
                        }

                        return;
                    }

                case "reply":
                    {
                        args = args.Skip(1).ToArray();

                        if (args.Length < 2)
                        {
                            player.TicketReply("You did not provide ticket ID/text to reply with!");
                            return;
                        }

                        var ID_str = args[0];
                        var ID = -1;
                        if (!int.TryParse(ID_str, out ID))
                        {
                            player.TicketReply(ID_str + " is not a number!");
                            return;
                        }

                        if (ID == -1)
                        {
                            player.TicketReply("Invalid ticket ID (" + ID + ")");
                            return;
                        }

                        var ticket = Find(ID);
                        if (ticket == null)
                        {
                            player.TicketReply("Couldn't find a ticket with ID " + ID);
                            return;
                        }

                        if (!ticket.Open)
                        {
                            player.TicketReply("This ticket is closed.");
                            return;
                        }

                        if (ticket.creator.id != player.Id && !player.IsAdmin)
                        {
                            player.TicketReply("You cannot reply to a ticket that is not created by you.");
                            return;
                        }

                        args = args.Skip(1).ToArray();
                        var text = string.Join(" ", args);

                        ticket.Reply(player, text);
                        return;
                    }

                case "create":
                default:
                    {
                        CreateTicket(player, command, args);
                        return;
                    }
            }
        }

        private void ReportCMD(IPlayer player, string command, string[] args)
        {
            player.Reply("Please use the report menu <color=green>(F7 key)</color> if you want to report someone, for bugs use the <color=#C4FF00>/ticket</color> command");
        }

        #endregion

        #region Ticket class

        public class Ticket
        {
            public string _id;
            public int id = -1;
            public DateTime created_at = DateTime.UtcNow;
            public TicketUser creator;
            public List<TicketReply> replies = new List<TicketReply>();
            public TicketUser reported;
            public CloseInfo closed;
            public int server;
            public List<int> position;

            public bool Open
            {
                get
                {
                    return closed == null;
                }
            }

            public Ticket() { }

            public Ticket(IPlayer creator, string text, IPlayer reported)
            {
                server = ServerIdInt;
                id = instance.tickets.Count == 0 ? 1 : instance.tickets.Select(x => x.id).Max() + 1;

                this.creator = new TicketUser(creator);
 
                var bp = creator.Object as BasePlayer;

                replies = new List<TicketReply> { new TicketReply(creator, text) };
                this.reported = reported == null ? null : new TicketUser(reported);

                if (bp == null) position = new List<int> { 0, 0, 0 };
                else
                {
                    var temp = Vector3Int.RoundToInt(bp.transform.position);
                    position = new List<int> { temp.x, temp.y, temp.z };
                }

                CreateInternalRequest(base_url + "/api/tickets", Utility.ConvertToJson(this, true), RequestMethod.POST, (code, response) =>
                {
                    if (code < 400) return;

                    if (code == 429)
                    {
                        creator.TicketReply("You already reported this person recently.");
                        return;
                    }

                    instance.Puts("Failed to create ticket #" + id + ": " + code + " (" + response + ")");
                    instance.SendToMothership("Failed to create ticket #" + id + ": " + code + " (" + response + ")");
                });
            }

            public void Reply(IPlayer player, string text)
            {
                if (!player.IsAdmin && !Open)
                {
                    player.TicketReply("You cannot reply to a closed ticket");
                    return;
                }

                var reply = new TicketReply(player, text);

                CreateInternalRequest(base_url + "/api/tickets/" + _id, Utility.ConvertToJson(reply, true), RequestMethod.PATCH);
            }

            public void BroadcastToAdminsAndCreator(string msg)
            {
                //msg = msg.Replace("[Tickets]", "<color=#C4FF00>[Tickets]</color>");
                //msg = msg.Replace("[OPEN]", "<color=#C4FF00>[OPEN]</color>");
                //msg = msg.Replace("[CLOSED]", "<color=red>[CLOSED]</color>");

                //https://stackoverflow.com/a/60103725
                foreach (var player in BasePlayer.activePlayerList.ToArray())
                {
                    if (creator.id == player.UserIDString || player.IsAdmin)
                    {
                        instance.Puts("sending msg to " + player);
                        player.IPlayer.TicketReply(msg);
                    }
                }
            }

            public void Close(TicketUser user, string text = null)
            {
                if (!Open) return;

                CreateInternalRequest(base_url + "/api/tickets/" + _id, Utility.ConvertToJson(new
                {
                    by = user,
                    reason = text
                }, true), RequestMethod.DELETE);
            }

            public void Close(IPlayer player, string text = null)
            {
                if (!Open) return;

                Close(new TicketUser(player), text);
            }

            public class TicketUser
            {
                public static TicketUser server = new TicketUser { id = "0", name = "Server Console" };

                public string id;
                public string name;

                public TicketUser() { }

                public TicketUser(IPlayer player)
                {
                    id = player.Id;
                    name = player.Name;
                }

                public override string ToString()
                {
                    if (id == "0") return name;
                    return name + "/" + id;
                }
            }

            public class CloseInfo
            {
                public DateTime at;
                public TicketUser by;
                public string reason;
            }

            public class TicketReply
            {
                public string content;
                public DateTime date;
                public TicketUser replier;
                

                public TicketReply() { }

                public TicketReply(IPlayer player, string text)
                {
                    replier = new TicketUser(player);
                    content = text;
                }

                public override string ToString()
                {
                    return "<color=#C4FF00>" + this.replier.name + "</color> - " + date.ToString() + " UTC\n" + content;
                }
            }
        }

        #endregion

        #region WS

        private void WSTicketClose(string json)
        {
            var ticket = Utility.ConvertFromJson<Ticket>(json);
            tickets[tickets.IndexOf(tickets.Find(x => x._id == ticket._id))] = ticket;

            var msg = "[Tickets] Ticket #" + ticket.id + " was closed by " + ticket.closed.by.name + (!string.IsNullOrEmpty(ticket.closed.reason) ? ", reason: " + ticket.closed.reason : "");
            msg = RemoveTags(msg);
            Puts(msg);
            ticket.BroadcastToAdminsAndCreator(msg);
        }

        private void WSTicketCreate(string json)
        {
            var ticket = Utility.ConvertFromJson<Ticket>(json);
            tickets.Add(ticket);

            var msg = "[Tickets] New Ticket #" + ticket.id + ":\n" + (ticket.reported == null ? "" : "Reported person: " + ticket.reported + "\n") + ticket.replies.First().ToString();
            msg = RemoveTags(msg);
            Puts(msg);
            ticket.BroadcastToAdminsAndCreator(msg);
        }

        private void WSTicketReply(string json)
        {
            var ticket = Utility.ConvertFromJson<Ticket>(json);
            var e = tickets.Find(x => x._id == ticket._id);

            if (e == null)
            {
                tickets.Add(e);
            }
            else tickets[tickets.IndexOf(e)] = ticket;

            var last_reply = ticket.replies.Last();
            var msg = "[Tickets] New reply to Ticket #" + ticket.id + ":\n" + last_reply.replier.name + " - " + last_reply.date.ToString("HH:mm:ss") + " UTC\n" + last_reply.content;
            msg = RemoveTags(msg);
            Puts(msg);
            ticket.BroadcastToAdminsAndCreator(msg);
        }

        private void WSTicketBulkClose(List<string> ticket_ids, string reason, string id, string name)
        {
            if (ticket_ids == null || ticket_ids.Count < 1)
            {
                PrintWarning("Got a TICKET_BULK_CLOSE with missing ticket list");
                return;
            }

            if (string.IsNullOrEmpty(reason))
            {
                PrintWarning("Got a TICKET_BULK_CLOSE with missing reason");
                return;
            }

            if (string.IsNullOrEmpty(id) || string.IsNullOrEmpty(name))
            {
                PrintWarning("Got a TICKET_BULK_CLOSE with missing name/id");
                return;
            }

            var tickets = new List<Ticket>();

            foreach (var ticket in this.tickets)
            {
                if (ticket_ids.Contains(ticket._id))
                {
                    tickets.Add(ticket);
                    ticket.closed = new Ticket.CloseInfo
                    {
                        at = DateTime.UtcNow,
                        by = new Ticket.TicketUser
                        {
                            id = id,
                            name = name
                        },
                        reason = reason
                    };
                }
            }

            if (tickets.Count > 0)
            {
                var message = tickets.Count + " tickets were closed by " + tickets[0].closed.by.name + ", reason: \"" + reason + "\"" + (tickets.Count < 20 ? "\n(" + string.Join(", ", tickets.Select(x => x.id)) + ")" : "");
                Puts(message);
            }
        }

        #endregion

        #region Helpers

        public string RemoveTags(string phrase)
        {
            if (string.IsNullOrEmpty(phrase)) return phrase;
            //	Forbidden formatting tags
            var forbiddenTags = new List<string> {
                "</color>",
                "</size>",
                "<b>",
                "</b>",
                "<i>",
                "</i>"
            };

            //	Replace Color Tags
            phrase = new Regex("(<color=.+?>)").Replace(phrase, string.Empty);
            //	Replace Size Tags
            phrase = new Regex("(<size=.+?>)").Replace(phrase, string.Empty);
            var phraseSB = new StringBuilder(phrase);
            for (int i = 0; i < forbiddenTags.Count; i++)
            {
                var tag = forbiddenTags[i];
                phraseSB.Replace(tag, string.Empty);
            }

            return phraseSB.ToString();
        }

        private void SendToMothership(string text)
        {
            DiscordAPI2.Call<bool>("SendToMothership", text);
        }

        private void TeleportPlayer(BasePlayer player, Vector3 pos)
        {
            if (Compilation == null || !Compilation.IsLoaded) return;
            Compilation.Call("TeleportPlayer", player, pos);
        }

        private static void CreateInternalRequest(string URL, string body, RequestMethod method, Action<int, string> callback = null)
        {
            if (string.IsNullOrEmpty(URL)) return;

            var token = instance.DiscordAPI2.Call<string>("GenerateToken", "", "prism_" + ServerId);

            var headers = new Dictionary<string, string>
            {
                { "User-Agent", "PRISM " + ServerId + (instance.Version.ToString()) },
                { "Authorization", token }
            };

            if (method != RequestMethod.GET && !string.IsNullOrEmpty(body)) headers.Add("Content-Type", "application/json");

            instance.webrequest.Enqueue(URL, body, (c, response) =>
            {
                if (c >= 400) instance.Puts("Failed to send a " + method.ToString() + " request to " + URL + " (" + response + " |" + c + ")");
                if (callback != null) callback.Invoke(c, response);
            }, instance, method, headers, 10);
        }

        private bool CreateTicket(IPlayer player, string text, IPlayer reported)
        {
            if (string.IsNullOrEmpty(text))
            {
                PrintError("CreateTicket called but not text??");
                return false;
            }

            var ticket = new Ticket(player, text, reported);
            return ticket != null;
        }

        #endregion
    }
}

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху