initial ctrl-z working
This commit is contained in:
parent
d40d9aee58
commit
565ab9489d
@ -9,6 +9,7 @@ using System.Windows.Forms;
|
|||||||
namespace EduNetworkBuilder
|
namespace EduNetworkBuilder
|
||||||
{
|
{
|
||||||
//Holds a little bit of information pertaining to the current animation.
|
//Holds a little bit of information pertaining to the current animation.
|
||||||
|
[Serializable]
|
||||||
public class AnimationClass
|
public class AnimationClass
|
||||||
{
|
{
|
||||||
Point ImageStartPoint = new Point();
|
Point ImageStartPoint = new Point();
|
||||||
|
@ -8,6 +8,7 @@ using System.Text.RegularExpressions;
|
|||||||
|
|
||||||
namespace EduNetworkBuilder
|
namespace EduNetworkBuilder
|
||||||
{
|
{
|
||||||
|
[Serializable]
|
||||||
public class LanguageString
|
public class LanguageString
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -58,6 +59,7 @@ namespace EduNetworkBuilder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
public class LanguageStrings
|
public class LanguageStrings
|
||||||
{
|
{
|
||||||
List<LanguageString> TheStrings = new List<LanguageString>();
|
List<LanguageString> TheStrings = new List<LanguageString>();
|
||||||
|
@ -189,7 +189,7 @@ namespace EduNetworkBuilder
|
|||||||
internalIP = internal_ip;
|
internalIP = internal_ip;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
[Serializable]
|
||||||
public class PingTestStatus
|
public class PingTestStatus
|
||||||
{
|
{
|
||||||
public string Source;
|
public string Source;
|
||||||
@ -211,6 +211,7 @@ namespace EduNetworkBuilder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
public class PuzzleInfo
|
public class PuzzleInfo
|
||||||
{
|
{
|
||||||
public string PuzzleName;
|
public string PuzzleName;
|
||||||
@ -320,6 +321,7 @@ namespace EduNetworkBuilder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
public class HelpURL
|
public class HelpURL
|
||||||
{
|
{
|
||||||
public string URL = "";
|
public string URL = "";
|
||||||
|
@ -11,6 +11,7 @@ namespace EduNetworkBuilder
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// For drawing shapes on a network. Rectangles, circles. Filled or not
|
/// For drawing shapes on a network. Rectangles, circles. Filled or not
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
public class NetShape
|
public class NetShape
|
||||||
{
|
{
|
||||||
public NetShapeType MyShape = NetShapeType.none;
|
public NetShapeType MyShape = NetShapeType.none;
|
||||||
|
@ -45,6 +45,7 @@ namespace EduNetworkBuilder
|
|||||||
Image TheNetImage = new Bitmap(1024, 1024);
|
Image TheNetImage = new Bitmap(1024, 1024);
|
||||||
Image TheNetImageBackground = new Bitmap(1024, 1024);
|
Image TheNetImageBackground = new Bitmap(1024, 1024);
|
||||||
public int itemsize = 100; //The size of network components
|
public int itemsize = 100; //The size of network components
|
||||||
|
[NonSerialized]
|
||||||
PictureBox myPBox = null;
|
PictureBox myPBox = null;
|
||||||
private int UniqueIdentifier = 100; //This gets used for all sorts of things. is auto-incremented every time someone asks for one
|
private int UniqueIdentifier = 100; //This gets used for all sorts of things. is auto-incremented every time someone asks for one
|
||||||
private List<Packet> myPackets = new List<Packet>();
|
private List<Packet> myPackets = new List<Packet>();
|
||||||
|
@ -61,6 +61,7 @@ namespace EduNetworkBuilder
|
|||||||
public PersonClass CurrentUser;
|
public PersonClass CurrentUser;
|
||||||
|
|
||||||
private List<HelpURL> HelpURLs = new List<HelpURL>();
|
private List<HelpURL> HelpURLs = new List<HelpURL>();
|
||||||
|
private List<Network> storedNetworkStates = new List<Network>(); //for ctrl-z going back in time to past state
|
||||||
|
|
||||||
public BuilderWindow(string FirstArg="")
|
public BuilderWindow(string FirstArg="")
|
||||||
{
|
{
|
||||||
@ -231,11 +232,55 @@ namespace EduNetworkBuilder
|
|||||||
}
|
}
|
||||||
if (e.KeyCode == Keys.Z && e.Modifiers == Keys.Control)
|
if (e.KeyCode == Keys.Z && e.Modifiers == Keys.Control)
|
||||||
{
|
{
|
||||||
//ctrl-z
|
if(storedNetworkStates.Count > 0)
|
||||||
|
{
|
||||||
|
ChangeToPastState(storedNetworkStates[0]);
|
||||||
|
storedNetworkStates.RemoveAt(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//MessageBox.Show(e.KeyCode.ToString());
|
//MessageBox.Show(e.KeyCode.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void StoreNetworkState(Network toStore)
|
||||||
|
{
|
||||||
|
//We should verify something has changed before storing it. Oh well...
|
||||||
|
storedNetworkStates.Insert(0,Network.DeepClone(toStore));
|
||||||
|
int maxCount = 30;
|
||||||
|
if(storedNetworkStates.Count > maxCount)
|
||||||
|
{
|
||||||
|
storedNetworkStates.RemoveRange(maxCount, storedNetworkStates.Count - maxCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// We do this every time we load a new network or create a network from scratch
|
||||||
|
/// </summary>
|
||||||
|
public void ClearStoredNetworkStates()
|
||||||
|
{
|
||||||
|
storedNetworkStates.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Store the new state after a change has been made.
|
||||||
|
/// Do this before every change (add, delete, move)
|
||||||
|
/// </summary>
|
||||||
|
public void ProcessChange()
|
||||||
|
{
|
||||||
|
StoreNetworkState(myNetwork);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ChangeToPastState(Network OldNet)
|
||||||
|
{
|
||||||
|
if (OldNet != null)
|
||||||
|
{
|
||||||
|
myNetwork = OldNet;
|
||||||
|
myNetwork.RegisterDisplayArea(pbNetworkView);
|
||||||
|
UpdateMenu();
|
||||||
|
UpdateForm();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Return the control with the given name. Used primarily to color help buttons
|
/// Return the control with the given name. Used primarily to color help buttons
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -1059,6 +1104,8 @@ namespace EduNetworkBuilder
|
|||||||
{
|
{
|
||||||
if (ItemClickedOn != null)
|
if (ItemClickedOn != null)
|
||||||
{
|
{
|
||||||
|
ProcessChange();
|
||||||
|
|
||||||
ItemClickedOn.Hide();
|
ItemClickedOn.Hide();
|
||||||
UpdateLinks();
|
UpdateLinks();
|
||||||
UpdateVisuals();
|
UpdateVisuals();
|
||||||
@ -1069,6 +1116,7 @@ namespace EduNetworkBuilder
|
|||||||
{
|
{
|
||||||
if (ItemClickedOn != null)
|
if (ItemClickedOn != null)
|
||||||
{
|
{
|
||||||
|
ProcessChange();
|
||||||
ItemClickedOn.PowerOff = false;
|
ItemClickedOn.PowerOff = false;
|
||||||
bool BlowUpOnce = myNetwork.ItemHasTest(ItemClickedOn.hostname, NetTestType.DeviceBlowsUpWithPower) && !myNetwork.ItemTestIsComplete(ItemClickedOn.hostname, NetTestType.DeviceBlowsUpWithPower);
|
bool BlowUpOnce = myNetwork.ItemHasTest(ItemClickedOn.hostname, NetTestType.DeviceBlowsUpWithPower) && !myNetwork.ItemTestIsComplete(ItemClickedOn.hostname, NetTestType.DeviceBlowsUpWithPower);
|
||||||
bool BlowUpMultiple = myNetwork.ItemHasTest(ItemClickedOn.hostname, NetTestType.DeviceNeedsUPS) && !myNetwork.ItemTestIsComplete(ItemClickedOn.hostname, NetTestType.DeviceNeedsUPS);
|
bool BlowUpMultiple = myNetwork.ItemHasTest(ItemClickedOn.hostname, NetTestType.DeviceNeedsUPS) && !myNetwork.ItemTestIsComplete(ItemClickedOn.hostname, NetTestType.DeviceNeedsUPS);
|
||||||
@ -1106,6 +1154,7 @@ namespace EduNetworkBuilder
|
|||||||
{
|
{
|
||||||
if (ItemClickedOn != null)
|
if (ItemClickedOn != null)
|
||||||
{
|
{
|
||||||
|
ProcessChange();
|
||||||
ItemClickedOn.PowerOff = true;
|
ItemClickedOn.PowerOff = true;
|
||||||
//Mark the replace test as "done"
|
//Mark the replace test as "done"
|
||||||
myNetwork.RegisterDeviceReset(ItemClickedOn.hostname);
|
myNetwork.RegisterDeviceReset(ItemClickedOn.hostname);
|
||||||
@ -1117,6 +1166,7 @@ namespace EduNetworkBuilder
|
|||||||
//We will still do this for devices that are spraying the network
|
//We will still do this for devices that are spraying the network
|
||||||
private void pbNetworkView_Replace_Click(object sender, EventArgs e)
|
private void pbNetworkView_Replace_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
ProcessChange();
|
||||||
if (ItemClickedOn != null)
|
if (ItemClickedOn != null)
|
||||||
{
|
{
|
||||||
if (ItemClickedOn == null) return;
|
if (ItemClickedOn == null) return;
|
||||||
@ -1135,6 +1185,8 @@ namespace EduNetworkBuilder
|
|||||||
{
|
{
|
||||||
if (ItemClickedOn != null)
|
if (ItemClickedOn != null)
|
||||||
{
|
{
|
||||||
|
ProcessChange();
|
||||||
|
|
||||||
if (ItemClickedOn == null) return;
|
if (ItemClickedOn == null) return;
|
||||||
//Changing a UPS makes sure the power is off when done.
|
//Changing a UPS makes sure the power is off when done.
|
||||||
ItemClickedOn.PowerOff = true;
|
ItemClickedOn.PowerOff = true;
|
||||||
@ -1182,6 +1234,7 @@ namespace EduNetworkBuilder
|
|||||||
|
|
||||||
private void pbNetworkView_RemoveLink_Click(object sender, EventArgs e)
|
private void pbNetworkView_RemoveLink_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
ProcessChange();
|
||||||
ToolStripItem thing = (ToolStripItem)sender;
|
ToolStripItem thing = (ToolStripItem)sender;
|
||||||
string released = thing.Text;
|
string released = thing.Text;
|
||||||
released = Regex.Replace(released, ".* ", "");
|
released = Regex.Replace(released, ".* ", "");
|
||||||
@ -1200,6 +1253,8 @@ namespace EduNetworkBuilder
|
|||||||
ToolStripItem thing = (ToolStripItem)sender;
|
ToolStripItem thing = (ToolStripItem)sender;
|
||||||
if (thing.Tag != null)
|
if (thing.Tag != null)
|
||||||
{
|
{
|
||||||
|
ProcessChange();
|
||||||
|
|
||||||
NetworkLink NL = (NetworkLink)thing.Tag;
|
NetworkLink NL = (NetworkLink)thing.Tag;
|
||||||
//This may delete the old link and make a new one
|
//This may delete the old link and make a new one
|
||||||
LinkEditor LE = new LinkEditor(NL);
|
LinkEditor LE = new LinkEditor(NL);
|
||||||
@ -1212,6 +1267,7 @@ namespace EduNetworkBuilder
|
|||||||
|
|
||||||
private void pbNetworkView_ReplaceNetLink_Click(object sender, EventArgs e)
|
private void pbNetworkView_ReplaceNetLink_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
ProcessChange();
|
||||||
ToolStripItem thing = (ToolStripItem)sender;
|
ToolStripItem thing = (ToolStripItem)sender;
|
||||||
if (thing.Tag != null)
|
if (thing.Tag != null)
|
||||||
{
|
{
|
||||||
@ -1234,6 +1290,7 @@ namespace EduNetworkBuilder
|
|||||||
|
|
||||||
private void pbNetworkView_RemoveNetLink_Click(object sender, EventArgs e)
|
private void pbNetworkView_RemoveNetLink_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
ProcessChange();
|
||||||
ToolStripItem thing = (ToolStripItem)sender;
|
ToolStripItem thing = (ToolStripItem)sender;
|
||||||
if (thing.Tag != null)
|
if (thing.Tag != null)
|
||||||
{
|
{
|
||||||
@ -1249,6 +1306,8 @@ namespace EduNetworkBuilder
|
|||||||
|
|
||||||
private void pbNetworkView_DHCPRequest_Click(object sender, EventArgs e)
|
private void pbNetworkView_DHCPRequest_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
ProcessChange();
|
||||||
|
|
||||||
ItemClickedOn.DHCPRequestFromHere();
|
ItemClickedOn.DHCPRequestFromHere();
|
||||||
myNetwork.ProcessPackets();
|
myNetwork.ProcessPackets();
|
||||||
UpdateMessages();
|
UpdateMessages();
|
||||||
@ -1260,6 +1319,7 @@ namespace EduNetworkBuilder
|
|||||||
private void pbNetworkView_Reset_Click(object sender, EventArgs e)
|
private void pbNetworkView_Reset_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (ItemClickedOn == null) return;
|
if (ItemClickedOn == null) return;
|
||||||
|
ProcessChange();
|
||||||
ItemClickedOn.ClearIPs(); //reset the device
|
ItemClickedOn.ClearIPs(); //reset the device
|
||||||
UpdateVisuals();
|
UpdateVisuals();
|
||||||
}
|
}
|
||||||
@ -1272,6 +1332,7 @@ namespace EduNetworkBuilder
|
|||||||
return;
|
return;
|
||||||
if (ItemClickedOn != null)
|
if (ItemClickedOn != null)
|
||||||
{
|
{
|
||||||
|
ProcessChange();
|
||||||
|
|
||||||
DeviceConfig editwindow = new DeviceConfig(ItemClickedOn);
|
DeviceConfig editwindow = new DeviceConfig(ItemClickedOn);
|
||||||
editwindow.ShowDialog();
|
editwindow.ShowDialog();
|
||||||
@ -1302,6 +1363,8 @@ namespace EduNetworkBuilder
|
|||||||
{
|
{
|
||||||
if(ShapeForEditing != null)
|
if(ShapeForEditing != null)
|
||||||
{
|
{
|
||||||
|
ProcessChange();
|
||||||
|
|
||||||
myNetwork.RemoveShape(ShapeForEditing);
|
myNetwork.RemoveShape(ShapeForEditing);
|
||||||
ShapeForEditing = null;
|
ShapeForEditing = null;
|
||||||
UpdateForm();
|
UpdateForm();
|
||||||
@ -1311,6 +1374,8 @@ namespace EduNetworkBuilder
|
|||||||
{
|
{
|
||||||
if (ShapeForEditing != null)
|
if (ShapeForEditing != null)
|
||||||
{
|
{
|
||||||
|
ProcessChange();
|
||||||
|
|
||||||
ShapeEditor SE = new ShapeEditor(ShapeForEditing);
|
ShapeEditor SE = new ShapeEditor(ShapeForEditing);
|
||||||
SE.ShowDialog();
|
SE.ShowDialog();
|
||||||
|
|
||||||
@ -1322,8 +1387,11 @@ namespace EduNetworkBuilder
|
|||||||
|
|
||||||
private void pbNetworkView_Delete_Click(object sender, EventArgs e)
|
private void pbNetworkView_Delete_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
ProcessChange();
|
||||||
if (ItemsSelected.Count == 0)
|
if (ItemsSelected.Count == 0)
|
||||||
|
{
|
||||||
TryDeleteOneItem(ItemClickedOn);
|
TryDeleteOneItem(ItemClickedOn);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int i = ItemsSelected.Count - 1; i >= 0; i--)
|
for (int i = ItemsSelected.Count - 1; i >= 0; i--)
|
||||||
@ -1370,6 +1438,8 @@ namespace EduNetworkBuilder
|
|||||||
{
|
{
|
||||||
if (ItemClickedOn == null) return; //we do not have something chosen to ping from
|
if (ItemClickedOn == null) return; //we do not have something chosen to ping from
|
||||||
ToolStripMenuItem Pressed = (ToolStripMenuItem)sender;
|
ToolStripMenuItem Pressed = (ToolStripMenuItem)sender;
|
||||||
|
ProcessChange();
|
||||||
|
|
||||||
string itemname = Pressed.Text;
|
string itemname = Pressed.Text;
|
||||||
string dest = (string)Pressed.Tag;
|
string dest = (string)Pressed.Tag;
|
||||||
NB_IPAddress destination;
|
NB_IPAddress destination;
|
||||||
@ -1384,6 +1454,7 @@ namespace EduNetworkBuilder
|
|||||||
private void pbNetworkView_Traceroute_Name_Click(object sender, EventArgs e)
|
private void pbNetworkView_Traceroute_Name_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (ItemClickedOn == null) return; //we do not have something chosen to ping from
|
if (ItemClickedOn == null) return; //we do not have something chosen to ping from
|
||||||
|
ProcessChange();
|
||||||
ToolStripMenuItem Pressed = (ToolStripMenuItem)sender;
|
ToolStripMenuItem Pressed = (ToolStripMenuItem)sender;
|
||||||
string itemname = Pressed.Text;
|
string itemname = Pressed.Text;
|
||||||
string dest = (string)Pressed.Tag;
|
string dest = (string)Pressed.Tag;
|
||||||
@ -1428,6 +1499,7 @@ namespace EduNetworkBuilder
|
|||||||
private void pbNetworkView_ArpClear_Click(object sender, EventArgs e)
|
private void pbNetworkView_ArpClear_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (ItemClickedOn == null) return; //we do not have something chosen to arp request from
|
if (ItemClickedOn == null) return; //we do not have something chosen to arp request from
|
||||||
|
ProcessChange();
|
||||||
ItemClickedOn.ClearArps();
|
ItemClickedOn.ClearArps();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1496,8 +1568,11 @@ namespace EduNetworkBuilder
|
|||||||
//This mouse-up is part of a double-click operation. Do an edit. But only if we are powered on
|
//This mouse-up is part of a double-click operation. Do an edit. But only if we are powered on
|
||||||
if (ItemClickedOn != null) PoweredOff = ItemClickedOn.PowerOff;
|
if (ItemClickedOn != null) PoweredOff = ItemClickedOn.PowerOff;
|
||||||
if (!PoweredOff)
|
if (!PoweredOff)
|
||||||
|
{
|
||||||
|
ProcessChange();
|
||||||
pbNetworkView_Edit_Click(sender, e);
|
pbNetworkView_Edit_Click(sender, e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (MouseIsDown && ItemsSelected.Count > 0)
|
if (MouseIsDown && ItemsSelected.Count > 0)
|
||||||
@ -1532,6 +1607,8 @@ namespace EduNetworkBuilder
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
ProcessChange();
|
||||||
|
|
||||||
//We just made a shape.
|
//We just made a shape.
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -1570,6 +1647,8 @@ namespace EduNetworkBuilder
|
|||||||
MouseIsDown = false;
|
MouseIsDown = false;
|
||||||
if (selectedButton == "btnLink")
|
if (selectedButton == "btnLink")
|
||||||
{
|
{
|
||||||
|
ProcessChange();
|
||||||
|
|
||||||
//We are making a link
|
//We are making a link
|
||||||
LinkEditor myEditor = new LinkEditor(ItemClickedOn, ReleasedOn);
|
LinkEditor myEditor = new LinkEditor(ItemClickedOn, ReleasedOn);
|
||||||
myEditor.ShowDialog();
|
myEditor.ShowDialog();
|
||||||
@ -1578,6 +1657,8 @@ namespace EduNetworkBuilder
|
|||||||
}
|
}
|
||||||
else if (ItemClickedOn == null)
|
else if (ItemClickedOn == null)
|
||||||
{
|
{
|
||||||
|
ProcessChange();
|
||||||
|
|
||||||
NetworkComponent NC = null;
|
NetworkComponent NC = null;
|
||||||
switch (selectedButton)
|
switch (selectedButton)
|
||||||
{
|
{
|
||||||
@ -1667,6 +1748,7 @@ namespace EduNetworkBuilder
|
|||||||
{
|
{
|
||||||
if (!ItemClickedOn.IsLockedInLocation())
|
if (!ItemClickedOn.IsLockedInLocation())
|
||||||
{
|
{
|
||||||
|
ProcessChange();
|
||||||
ItemClickedOn.ChangeLocation(CenteredLocation);
|
ItemClickedOn.ChangeLocation(CenteredLocation);
|
||||||
ItemClickedOn.UnHide(); //If it was hidden, unhide it
|
ItemClickedOn.UnHide(); //If it was hidden, unhide it
|
||||||
UpdateLinks();
|
UpdateLinks();
|
||||||
@ -1857,6 +1939,7 @@ namespace EduNetworkBuilder
|
|||||||
private void PrepForLoad()
|
private void PrepForLoad()
|
||||||
{
|
{
|
||||||
processing = true;
|
processing = true;
|
||||||
|
ClearStoredNetworkStates();
|
||||||
myNetwork = new Network("");
|
myNetwork = new Network("");
|
||||||
myNetwork.RegisterDisplayArea(pbNetworkView);
|
myNetwork.RegisterDisplayArea(pbNetworkView);
|
||||||
GC.Collect();
|
GC.Collect();
|
||||||
|
@ -12,6 +12,7 @@ namespace EduNetworkBuilder
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A class holding a project that needs to be done as either a test, quiz, or homework
|
/// A class holding a project that needs to be done as either a test, quiz, or homework
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
public class SchoolworkClass
|
public class SchoolworkClass
|
||||||
{
|
{
|
||||||
public Network theProject = null;
|
public Network theProject = null;
|
||||||
|
@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace EduNetworkBuilder
|
namespace EduNetworkBuilder
|
||||||
{
|
{
|
||||||
|
[Serializable]
|
||||||
public class TraversalClass
|
public class TraversalClass
|
||||||
{
|
{
|
||||||
protected struct TraversalRecord
|
protected struct TraversalRecord
|
||||||
|
Loading…
Reference in New Issue
Block a user