Cleanups.
This commit is contained in:
parent
e898264178
commit
b6f3d928ae
@ -768,7 +768,7 @@ public class Rule implements Comparable<Rule>
|
|||||||
|
|
||||||
for (StatusBarNotification sbn : NotificationListener.getInstance().getActiveNotifications())
|
for (StatusBarNotification sbn : NotificationListener.getInstance().getActiveNotifications())
|
||||||
{
|
{
|
||||||
if(lastExecution == null || sbn.getPostTime() > this.lastExecution.getTimeInMillis())
|
if(getLastExecution() == null || sbn.getPostTime() > this.lastExecution.getTimeInMillis())
|
||||||
{
|
{
|
||||||
String app = sbn.getPackageName();
|
String app = sbn.getPackageName();
|
||||||
String title = sbn.getNotification().extras.getString(EXTRA_TITLE);
|
String title = sbn.getNotification().extras.getString(EXTRA_TITLE);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.jens.automation2;
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
@ -9,6 +10,7 @@ import android.service.notification.StatusBarNotification;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.jens.automation2.location.LocationProvider;
|
||||||
import com.jens.automation2.location.WifiBroadcastReceiver;
|
import com.jens.automation2.location.WifiBroadcastReceiver;
|
||||||
import com.jens.automation2.receivers.BatteryReceiver;
|
import com.jens.automation2.receivers.BatteryReceiver;
|
||||||
import com.jens.automation2.receivers.BluetoothReceiver;
|
import com.jens.automation2.receivers.BluetoothReceiver;
|
||||||
@ -129,6 +131,7 @@ public class Rule implements Comparable<Rule>
|
|||||||
{
|
{
|
||||||
return this.getName();
|
return this.getName();
|
||||||
}
|
}
|
||||||
|
@SuppressLint("NewApi")
|
||||||
public String toStringLong()
|
public String toStringLong()
|
||||||
{
|
{
|
||||||
String returnString = "";
|
String returnString = "";
|
||||||
@ -503,7 +506,7 @@ public class Rule implements Comparable<Rule>
|
|||||||
{
|
{
|
||||||
if(oneTrigger.getTriggerParameter())
|
if(oneTrigger.getTriggerParameter())
|
||||||
{
|
{
|
||||||
if(com.jens.automation2.location.LocationProvider.getSpeed() < oneTrigger.getSpeed())
|
if(LocationProvider.getSpeed() < oneTrigger.getSpeed())
|
||||||
{
|
{
|
||||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyWeAreSlowerThan) + " " + String.valueOf(oneTrigger.getSpeed()), 3);
|
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyWeAreSlowerThan) + " " + String.valueOf(oneTrigger.getSpeed()), 3);
|
||||||
return false;
|
return false;
|
||||||
@ -511,7 +514,7 @@ public class Rule implements Comparable<Rule>
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(com.jens.automation2.location.LocationProvider.getSpeed() > oneTrigger.getSpeed())
|
if(LocationProvider.getSpeed() > oneTrigger.getSpeed())
|
||||||
{
|
{
|
||||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyWeAreFasterThan) + " " + String.valueOf(oneTrigger.getSpeed()), 3);
|
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyWeAreFasterThan) + " " + String.valueOf(oneTrigger.getSpeed()), 3);
|
||||||
return false;
|
return false;
|
||||||
@ -635,45 +638,6 @@ public class Rule implements Comparable<Rule>
|
|||||||
{
|
{
|
||||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Checking for bluetooth...", 4);
|
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Checking for bluetooth...", 4);
|
||||||
|
|
||||||
// if( // connected / disconnected
|
|
||||||
// (oneTrigger.getTriggerParameter() && (BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_ACL_CONNECTED) | BluetoothReceiver.getLastAction().equals("android.bluetooth.device.action.ACL_CONNECTED")))
|
|
||||||
// |
|
|
||||||
// (!oneTrigger.getTriggerParameter() && (BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED) | BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_ACL_DISCONNECTED) | BluetoothReceiver.getLastAction().equals("android.bluetooth.device.action.ACTION_ACL_DISCONNECT_REQUESTED") | BluetoothReceiver.getLastAction().equals("android.bluetooth.device.action.ACTION_ACL_DISCONNECTED")))
|
|
||||||
// )
|
|
||||||
// {
|
|
||||||
// if(oneTrigger.getBluetoothDeviceAddress() != null)
|
|
||||||
// {
|
|
||||||
// if(oneTrigger.getBluetoothDeviceAddress().equals("<any>"))
|
|
||||||
// {
|
|
||||||
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "No bluetooth address specified, any will do.", 4);
|
|
||||||
// }
|
|
||||||
// else if(oneTrigger.getBluetoothDeviceAddress().equals("<none>"))
|
|
||||||
// {
|
|
||||||
// // ???
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Bluetooth address specified, checking that.", 4);
|
|
||||||
// if(!BluetoothReceiver.getLastAffectedDevice().getAddress().equals(oneTrigger.getBluetoothDeviceAddress()))
|
|
||||||
// {
|
|
||||||
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyNotTheCorrectDeviceAddress), 3);
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Bluetooth address matches. Rule will apply.", 4);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else if(BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_FOUND) | BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_FOUND))
|
|
||||||
// {
|
|
||||||
// if(!oneTrigger.getTriggerParameter())
|
|
||||||
// {
|
|
||||||
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyDeviceInRangeButShouldNotBe), 3);
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else // above only checks for last action, this checks for things in the past
|
|
||||||
{
|
|
||||||
if(oneTrigger.getBluetoothDeviceAddress().equals("<any>"))
|
if(oneTrigger.getBluetoothDeviceAddress().equals("<any>"))
|
||||||
{
|
{
|
||||||
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
|
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
|
||||||
@ -737,7 +701,6 @@ public class Rule implements Comparable<Rule>
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.headsetPlugged))
|
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.headsetPlugged))
|
||||||
{
|
{
|
||||||
if(HeadphoneJackListener.isHeadsetConnected() != oneTrigger.getTriggerParameter())
|
if(HeadphoneJackListener.isHeadsetConnected() != oneTrigger.getTriggerParameter())
|
||||||
@ -934,7 +897,16 @@ public class Rule implements Comparable<Rule>
|
|||||||
publishProgress(message);
|
publishProgress(message);
|
||||||
|
|
||||||
for(int i = 0; i< Rule.this.getActionSet().size(); i++)
|
for(int i = 0; i< Rule.this.getActionSet().size(); i++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
Rule.this.getActionSet().get(i).run(automationService, doToggle);
|
Rule.this.getActionSet().get(i).run(automationService, doToggle);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "RuleExecution", "Error running action of rule " + Rule.this.getName() + ": " + Log.getStackTraceString(e), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Keep log of last x rule activations (Settings)
|
// Keep log of last x rule activations (Settings)
|
||||||
try
|
try
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.jens.automation2;
|
package com.jens.automation2;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
@ -10,6 +11,7 @@ import android.util.Log;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.google.android.gms.location.DetectedActivity;
|
import com.google.android.gms.location.DetectedActivity;
|
||||||
|
import com.jens.automation2.location.LocationProvider;
|
||||||
import com.jens.automation2.location.WifiBroadcastReceiver;
|
import com.jens.automation2.location.WifiBroadcastReceiver;
|
||||||
import com.jens.automation2.receivers.ActivityDetectionReceiver;
|
import com.jens.automation2.receivers.ActivityDetectionReceiver;
|
||||||
import com.jens.automation2.receivers.BatteryReceiver;
|
import com.jens.automation2.receivers.BatteryReceiver;
|
||||||
@ -131,6 +133,7 @@ public class Rule implements Comparable<Rule>
|
|||||||
{
|
{
|
||||||
return this.getName();
|
return this.getName();
|
||||||
}
|
}
|
||||||
|
@SuppressLint("NewApi")
|
||||||
public String toStringLong()
|
public String toStringLong()
|
||||||
{
|
{
|
||||||
String returnString = "";
|
String returnString = "";
|
||||||
@ -505,7 +508,7 @@ public class Rule implements Comparable<Rule>
|
|||||||
{
|
{
|
||||||
if(oneTrigger.getTriggerParameter())
|
if(oneTrigger.getTriggerParameter())
|
||||||
{
|
{
|
||||||
if(com.jens.automation2.location.LocationProvider.getSpeed() < oneTrigger.getSpeed())
|
if(LocationProvider.getSpeed() < oneTrigger.getSpeed())
|
||||||
{
|
{
|
||||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyWeAreSlowerThan) + " " + String.valueOf(oneTrigger.getSpeed()), 3);
|
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyWeAreSlowerThan) + " " + String.valueOf(oneTrigger.getSpeed()), 3);
|
||||||
return false;
|
return false;
|
||||||
@ -513,7 +516,7 @@ public class Rule implements Comparable<Rule>
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(com.jens.automation2.location.LocationProvider.getSpeed() > oneTrigger.getSpeed())
|
if(LocationProvider.getSpeed() > oneTrigger.getSpeed())
|
||||||
{
|
{
|
||||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyWeAreFasterThan) + " " + String.valueOf(oneTrigger.getSpeed()), 3);
|
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyWeAreFasterThan) + " " + String.valueOf(oneTrigger.getSpeed()), 3);
|
||||||
return false;
|
return false;
|
||||||
@ -666,45 +669,6 @@ public class Rule implements Comparable<Rule>
|
|||||||
{
|
{
|
||||||
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Checking for bluetooth...", 4);
|
Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Checking for bluetooth...", 4);
|
||||||
|
|
||||||
// if( // connected / disconnected
|
|
||||||
// (oneTrigger.getTriggerParameter() && (BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_ACL_CONNECTED) | BluetoothReceiver.getLastAction().equals("android.bluetooth.device.action.ACL_CONNECTED")))
|
|
||||||
// |
|
|
||||||
// (!oneTrigger.getTriggerParameter() && (BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED) | BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_ACL_DISCONNECTED) | BluetoothReceiver.getLastAction().equals("android.bluetooth.device.action.ACTION_ACL_DISCONNECT_REQUESTED") | BluetoothReceiver.getLastAction().equals("android.bluetooth.device.action.ACTION_ACL_DISCONNECTED")))
|
|
||||||
// )
|
|
||||||
// {
|
|
||||||
// if(oneTrigger.getBluetoothDeviceAddress() != null)
|
|
||||||
// {
|
|
||||||
// if(oneTrigger.getBluetoothDeviceAddress().equals("<any>"))
|
|
||||||
// {
|
|
||||||
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "No bluetooth address specified, any will do.", 4);
|
|
||||||
// }
|
|
||||||
// else if(oneTrigger.getBluetoothDeviceAddress().equals("<none>"))
|
|
||||||
// {
|
|
||||||
// // ???
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Bluetooth address specified, checking that.", 4);
|
|
||||||
// if(!BluetoothReceiver.getLastAffectedDevice().getAddress().equals(oneTrigger.getBluetoothDeviceAddress()))
|
|
||||||
// {
|
|
||||||
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyNotTheCorrectDeviceAddress), 3);
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), "Bluetooth address matches. Rule will apply.", 4);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else if(BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_FOUND) | BluetoothReceiver.getLastAction().equals(android.bluetooth.BluetoothDevice.ACTION_FOUND))
|
|
||||||
// {
|
|
||||||
// if(!oneTrigger.getTriggerParameter())
|
|
||||||
// {
|
|
||||||
// Miscellaneous.logEvent("i", String.format(context.getResources().getString(R.string.ruleCheckOf), this.getName()), context.getResources().getString(R.string.ruleDoesntApplyDeviceInRangeButShouldNotBe), 3);
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else // above only checks for last action, this checks for things in the past
|
|
||||||
{
|
|
||||||
if(oneTrigger.getBluetoothDeviceAddress().equals("<any>"))
|
if(oneTrigger.getBluetoothDeviceAddress().equals("<any>"))
|
||||||
{
|
{
|
||||||
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
|
if(oneTrigger.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED))
|
||||||
@ -768,7 +732,6 @@ public class Rule implements Comparable<Rule>
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.headsetPlugged))
|
else if(oneTrigger.getTriggerType().equals(Trigger.Trigger_Enum.headsetPlugged))
|
||||||
{
|
{
|
||||||
if(HeadphoneJackListener.isHeadsetConnected() != oneTrigger.getTriggerParameter())
|
if(HeadphoneJackListener.isHeadsetConnected() != oneTrigger.getTriggerParameter())
|
||||||
@ -840,6 +803,7 @@ public class Rule implements Comparable<Rule>
|
|||||||
}
|
}
|
||||||
|
|
||||||
foundMatch = true;
|
foundMatch = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -965,7 +929,16 @@ public class Rule implements Comparable<Rule>
|
|||||||
publishProgress(message);
|
publishProgress(message);
|
||||||
|
|
||||||
for(int i = 0; i< Rule.this.getActionSet().size(); i++)
|
for(int i = 0; i< Rule.this.getActionSet().size(); i++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
Rule.this.getActionSet().get(i).run(automationService, doToggle);
|
Rule.this.getActionSet().get(i).run(automationService, doToggle);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Miscellaneous.logEvent("e", "RuleExecution", "Error running action of rule " + Rule.this.getName() + ": " + Log.getStackTraceString(e), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Keep log of last x rule activations (Settings)
|
// Keep log of last x rule activations (Settings)
|
||||||
try
|
try
|
||||||
|
@ -609,7 +609,7 @@
|
|||||||
<string name="newsOptIn">Would you like to receive (only important) news about this app on the main screen? Those are downloaded from the developer\'s website. There will be no intrusive notification, just a text on the main screen when you open the app.</string>
|
<string name="newsOptIn">Would you like to receive (only important) news about this app on the main screen? Those are downloaded from the developer\'s website. There will be no intrusive notification, just a text on the main screen when you open the app.</string>
|
||||||
<string name="locationDisabled">Location disabled</string>
|
<string name="locationDisabled">Location disabled</string>
|
||||||
<string name="locationEngineDisabledShort">Location cannot be determined anymore. Click here to find out why.</string>
|
<string name="locationEngineDisabledShort">Location cannot be determined anymore. Click here to find out why.</string>
|
||||||
<string name="locationEngineDisabledLong">Unfortunately your location cannot be determined anymore. A debt of gratitude is owed to Google for its infinite wisdom and amiableness.\\n\\nLet me explain this further. Starting with Android 10 a new permission was introduced that is needed to determine your location in the background (which of course is required for an app like this). Whilst I consider that a good idea in general the chicanery it involves for developers are not.\\n\\nWhen developing an app you can try to qualify for this permission by abiding to a catalog of requirements. Unfortunately new versions of my app have been rejected over a period of three months. I fulfilled all these requirements, Google\'s shitty development support claimed I would not. After giving them proof that I did after all - I got a response like \"I cannot help you anymore\". Eventually I gave up. \\n\\nAs a consequence the Google Play version can NOT use your location as a trigger anymore. My only alternative option would have been to have this application removed from the store entirely.\\n\\nI\'m very sorry about that, but I\'ve tried my best arguing with a \"support\" that repeatedly failed to pass the Turing test.\\n\\nThe good news: You can still have it all!\\n\\nAutomation is now open source and can be found in F-Droid. That is an app store that really cares about your privacy - rather than just acting like that. Simply backup your config file, uninstall this app, install it again from F-Droid, restore your config file - done.\\n\\nClick here to find out more:</string>
|
<string name="locationEngineDisabledLong">Unfortunately your location cannot be determined anymore. A debt of gratitude is owed to Google for its infinite wisdom and amiableness.\\n\\nLet me explain this further. Starting with Android 10 a new permission was introduced that is needed to determine your location in the background (which of course is required for an app like this). Whilst I consider that a good idea in general the chicanery it involves for developers is not.\\n\\nWhen developing an app you can try to qualify for this permission by abiding to a catalog of requirements. Unfortunately new versions of my app have been rejected over a period of three months. I fulfilled all those requirements, Google\'s shitty development support claimed I would not. After giving them proof that I did after all - I got a response like \"I cannot help you anymore\". Eventually I gave up. \\n\\nAs a consequence the Google Play version can NOT use your location as a trigger anymore. My only alternative option would have been to have this application removed from the store entirely.\\n\\nI\'m very sorry about that, but I\'ve tried my best arguing with a \"support\" that repeatedly failed to pass the Turing test.\\n\\nThe good news: You can still have it all!\\n\\nAutomation is now open source and can be found in F-Droid. That is an app store that really cares about your privacy - rather than just acting like that. Simply backup your config file, uninstall this app, install it again from F-Droid, restore your config file - done.\\n\\nClick here to find out more:</string>
|
||||||
<string name="filesStoredAt">Config and log files are stored in folder %1$s. Click on this text to open a file explorer. Unfortunately this will only work with a rooted device or a debug version. If you want to send me or yourself the config- and logfiles you can use the below button.</string>
|
<string name="filesStoredAt">Config and log files are stored in folder %1$s. Click on this text to open a file explorer. Unfortunately this will only work with a rooted device or a debug version. If you want to send me or yourself the config- and logfiles you can use the below button.</string>
|
||||||
<string name="notification">Notification</string>
|
<string name="notification">Notification</string>
|
||||||
<string name="title">Title</string>
|
<string name="title">Title</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user