refactor: Renamed the provider field in a config file to type to make things a little easier to understand; also removed husky
This commit is contained in:
@@ -1,13 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
set -e
|
|
||||||
|
|
||||||
echo "Running pre-push hook:"
|
|
||||||
|
|
||||||
echo "Executing: cargo fmt"
|
|
||||||
cargo fmt
|
|
||||||
|
|
||||||
echo "Executing: make lint"
|
|
||||||
make lint
|
|
||||||
|
|
||||||
echo "Executing: cargo test"
|
|
||||||
cargo test -- --skip prop_
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
set -e
|
|
||||||
|
|
||||||
echo "Running pre-push hook:"
|
|
||||||
|
|
||||||
echo "Executing: cargo fmt --check"
|
|
||||||
cargo fmt --check
|
|
||||||
|
|
||||||
echo "Executing: make lint"
|
|
||||||
make lint
|
|
||||||
|
|
||||||
echo "Executing: cargo test"
|
|
||||||
cargo test -- --skip prop_
|
|
||||||
Generated
-7
@@ -224,12 +224,6 @@ version = "3.19.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cargo-husky"
|
|
||||||
version = "1.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7b02b629252fe8ef6460461409564e2c21d0c8e77e0944f3d189ff06c4e932ad"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.36"
|
version = "1.2.36"
|
||||||
@@ -714,7 +708,6 @@ dependencies = [
|
|||||||
"assert_cmd",
|
"assert_cmd",
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"base64",
|
"base64",
|
||||||
"cargo-husky",
|
|
||||||
"chacha20poly1305",
|
"chacha20poly1305",
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ tempfile = "3.10.1"
|
|||||||
proptest = "1.5.0"
|
proptest = "1.5.0"
|
||||||
assert_cmd = "2.0.16"
|
assert_cmd = "2.0.16"
|
||||||
predicates = "3.1.2"
|
predicates = "3.1.2"
|
||||||
cargo-husky = { version = "1.5.0", default-features = false, features = ["user-hooks"] }
|
|
||||||
|
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ gman supports multiple providers. Select one as the default and then list provid
|
|||||||
default_provider: local
|
default_provider: local
|
||||||
providers:
|
providers:
|
||||||
- name: local
|
- name: local
|
||||||
provider: local
|
type: local
|
||||||
password_file: ~/.gman_password
|
password_file: ~/.gman_password
|
||||||
# Optional Git sync settings for the 'local' provider
|
# Optional Git sync settings for the 'local' provider
|
||||||
git_branch: main # Defaults to 'main'
|
git_branch: main # Defaults to 'main'
|
||||||
@@ -191,7 +191,7 @@ For use across multiple systems, `gman` can sync with a remote Git repository (r
|
|||||||
default_provider: local
|
default_provider: local
|
||||||
providers:
|
providers:
|
||||||
- name: local
|
- name: local
|
||||||
provider: local
|
type: local
|
||||||
git_branch: main
|
git_branch: main
|
||||||
git_remote_url: "git@github.com:my-user/gman-secrets.git"
|
git_remote_url: "git@github.com:my-user/gman-secrets.git"
|
||||||
git_user_name: "Your Name"
|
git_user_name: "Your Name"
|
||||||
@@ -397,13 +397,13 @@ Example: two AWS Secrets Manager providers named `lab` and `prod`.
|
|||||||
default_provider: prod
|
default_provider: prod
|
||||||
providers:
|
providers:
|
||||||
- name: lab
|
- name: lab
|
||||||
provider: local
|
type: local
|
||||||
password_file: /home/user/.lab_gman_password
|
password_file: /home/user/.lab_gman_password
|
||||||
git_branch: main
|
git_branch: main
|
||||||
git_remote_url: git@github.com:username/lab-vault.git
|
git_remote_url: git@github.com:username/lab-vault.git
|
||||||
|
|
||||||
- name: prod
|
- name: prod
|
||||||
provider: local
|
type: local
|
||||||
password_file: /home/user/.prod_gman_password
|
password_file: /home/user/.prod_gman_password
|
||||||
git_branch: main
|
git_branch: main
|
||||||
git_remote_url: git@github.com:username/prod-vault.git
|
git_remote_url: git@github.com:username/prod-vault.git
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
$ErrorActionPreference = 'Stop';
|
||||||
|
|
||||||
|
$PackageName = 'managarr'
|
||||||
|
$toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"
|
||||||
|
$url64 = 'https://github.com/Dark-Alex-17/managarr/releases/download/v$version/managarr-windows.tar.gz'
|
||||||
|
$checksum64 = '$hash_64'
|
||||||
|
|
||||||
|
$packageArgs = @{
|
||||||
|
packageName = $packageName
|
||||||
|
softwareName = $packageName
|
||||||
|
unzipLocation = $toolsDir
|
||||||
|
fileType = 'exe'
|
||||||
|
url = $url64
|
||||||
|
checksum = $checksum64
|
||||||
|
checksumType = 'sha256'
|
||||||
|
|
||||||
|
}
|
||||||
|
Install-ChocolateyZipPackage @packageArgs
|
||||||
|
$File = Get-ChildItem -File -Path $env:ChocolateyInstall\lib\$packageName\tools\ -Filter *.tar
|
||||||
|
Get-ChocolateyUnzip -fileFullPath $File.FullName -destination $env:ChocolateyInstall\lib\$packageName\tools\
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Read this before creating packages: https://chocolatey.org/docs/create-packages -->
|
||||||
|
<!-- It is especially important to read the above link to understand additional requirements when publishing packages to the community feed aka dot org (https://chocolatey.org/packages). -->
|
||||||
|
|
||||||
|
<!-- Test your packages in a test environment: https://github.com/chocolatey/chocolatey-test-environment -->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
This is a nuspec. It mostly adheres to https://docs.nuget.org/create/Nuspec-Reference. Chocolatey uses a special version of NuGet.Core that allows us to do more than was initially possible. As such there are certain things to be aware of:
|
||||||
|
|
||||||
|
* the package xmlns schema url may cause issues with nuget.exe
|
||||||
|
* Any of the following elements can ONLY be used by choco tools - projectSourceUrl, docsUrl, mailingListUrl, bugTrackerUrl, packageSourceUrl, provides, conflicts, replaces
|
||||||
|
* nuget.exe can still install packages with those elements but they are ignored. Any authoring tools or commands will error on those elements
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- You can embed software files directly into packages, as long as you are not bound by distribution rights. -->
|
||||||
|
<!-- * If you are an organization making private packages, you probably have no issues here -->
|
||||||
|
<!-- * If you are releasing to the community feed, you need to consider distribution rights. -->
|
||||||
|
<!-- Do not remove this test for UTF-8: if “Ω” doesn’t appear as greek uppercase omega letter enclosed in quotation marks, you should use an editor that supports UTF-8, not this one. -->
|
||||||
|
<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">
|
||||||
|
<metadata>
|
||||||
|
<!-- == PACKAGE SPECIFIC SECTION == -->
|
||||||
|
<id>managarr</id>
|
||||||
|
<version>$version</version>
|
||||||
|
|
||||||
|
<!-- == SOFTWARE SPECIFIC SECTION == -->
|
||||||
|
<!-- This section is about the software itself -->
|
||||||
|
<title>Managarr</title>
|
||||||
|
<authors>Alex Clarke</authors>
|
||||||
|
<projectUrl>https://github.com/Dark-Alex-17/managarr</projectUrl>
|
||||||
|
<licenseUrl>https://github.com/Dark-Alex-17/managarr/blob/main/LICENSE</licenseUrl>
|
||||||
|
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||||
|
<projectSourceUrl>https://github.com/Dark-Alex-17/managarr</projectSourceUrl>
|
||||||
|
<docsUrl>https://github.com/Dark-Alex-17/managarr/blob/main/README.md</docsUrl>
|
||||||
|
<bugTrackerUrl>https://github.com/Dark-Alex-17/managarr/issues</bugTrackerUrl>
|
||||||
|
<tags>cli cross-platform terminal servarr tui sonarr radarr rust</tags>
|
||||||
|
<summary>A TUI and CLI for managing *arr servers.</summary>
|
||||||
|
<description>
|
||||||
|
A TUI and CLI for managing *arr servers. Built with love in Rust!
|
||||||
|
|
||||||
|
**Usage**
|
||||||
|
To use, run `managarr` in a terminal.
|
||||||
|
|
||||||
|
For more [documentation and usage](https://github.com/Dark-Alex-17/managarr/blob/main/README.md), see the [official repo](https://github.com/Dark-Alex-17/managarr).
|
||||||
|
|
||||||
|
</description>
|
||||||
|
<releaseNotes>https://github.com/Dark-Alex-17/managarr/releases/tag/v$version/</releaseNotes>
|
||||||
|
</metadata>
|
||||||
|
<files>
|
||||||
|
<!-- this section controls what actually gets packaged into the Chocolatey package -->
|
||||||
|
<file src="tools\**" target="tools" />
|
||||||
|
<!--Building from Linux? You may need this instead: <file src="tools/**" target="tools" />-->
|
||||||
|
</files>
|
||||||
|
</package>
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import hashlib
|
||||||
|
import sys
|
||||||
|
from string import Template
|
||||||
|
|
||||||
|
sys.stdout.reconfigure(encoding='utf-8')
|
||||||
|
args = sys.argv
|
||||||
|
version = args[1].replace("v", "")
|
||||||
|
template_file_path = args[2]
|
||||||
|
generated_file_path = args[3]
|
||||||
|
|
||||||
|
# Deployment files
|
||||||
|
hash_64 = args[4].strip()
|
||||||
|
|
||||||
|
print("Generating formula")
|
||||||
|
print(" VERSION: %s" % version)
|
||||||
|
print(" TEMPLATE PATH: %s" % template_file_path)
|
||||||
|
print(" SAVING AT: %s" % generated_file_path)
|
||||||
|
print(" HASH: %s" % hash_64)
|
||||||
|
|
||||||
|
with open(template_file_path, "r", encoding="utf-8") as template_file:
|
||||||
|
template = Template(template_file.read())
|
||||||
|
substitute = template.safe_substitute(version=version, hash_64=hash_64)
|
||||||
|
print("\n================== Generated package file ==================\n")
|
||||||
|
print(substitute)
|
||||||
|
print("\n============================================================\n")
|
||||||
|
|
||||||
|
with open(generated_file_path, "w", encoding="utf-8") as generated_file:
|
||||||
|
generated_file.write(substitute)
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# Documentation: https://docs.brew.sh/Formula-Cookbook
|
||||||
|
# https://rubydoc.brew.sh/Formula
|
||||||
|
class Managarr < Formula
|
||||||
|
desc "A fast and simple dashboard for Kubernetes written in Rust"
|
||||||
|
homepage "https://github.com/Dark-Alex-17/managarr"
|
||||||
|
if OS.mac? and Hardware::CPU.arm?
|
||||||
|
url "https://github.com/Dark-Alex-17/managarr/releases/download/v$version/managarr-macos-arm64.tar.gz"
|
||||||
|
sha256 "$hash_mac_arm"
|
||||||
|
elsif OS.mac? and Hardware::CPU.intel?
|
||||||
|
url "https://github.com/Dark-Alex-17/managarr/releases/download/v$version/managarr-macos.tar.gz"
|
||||||
|
sha256 "$hash_mac"
|
||||||
|
else
|
||||||
|
url "https://github.com/Dark-Alex-17/managarr/releases/download/v$version/managarr-linux-musl.tar.gz"
|
||||||
|
sha256 "$hash_linux"
|
||||||
|
end
|
||||||
|
version "$version"
|
||||||
|
license "MIT"
|
||||||
|
|
||||||
|
def install
|
||||||
|
bin.install "managarr"
|
||||||
|
ohai "You're done! Run with \"managarr\""
|
||||||
|
ohai "For runtime flags, see \"managarr --help\""
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import hashlib
|
||||||
|
import sys
|
||||||
|
from string import Template
|
||||||
|
|
||||||
|
args = sys.argv
|
||||||
|
version = args[1]
|
||||||
|
template_file_path = args[2]
|
||||||
|
generated_file_path = args[3]
|
||||||
|
|
||||||
|
# Deployment files
|
||||||
|
hash_mac = args[4].strip()
|
||||||
|
hash_mac_arm = args[5].strip()
|
||||||
|
hash_linux = args[6].strip()
|
||||||
|
|
||||||
|
print("Generating formula")
|
||||||
|
print(" VERSION: %s" % version)
|
||||||
|
print(" TEMPLATE PATH: %s" % template_file_path)
|
||||||
|
print(" SAVING AT: %s" % generated_file_path)
|
||||||
|
print(" MAC HASH: %s" % hash_mac)
|
||||||
|
print(" MAC ARM HASH: %s" % hash_mac_arm)
|
||||||
|
print(" LINUX HASH: %s" % hash_linux)
|
||||||
|
|
||||||
|
with open(template_file_path, "r") as template_file:
|
||||||
|
template = Template(template_file.read())
|
||||||
|
substitute = template.safe_substitute(version=version, hash_mac=hash_mac, hash_mac_arm=hash_mac_arm, hash_linux=hash_linux)
|
||||||
|
print("\n================== Generated package file ==================\n")
|
||||||
|
print(substitute)
|
||||||
|
print("\n============================================================\n")
|
||||||
|
|
||||||
|
with open(generated_file_path, "w") as generated_file:
|
||||||
|
generated_file.write(substitute)
|
||||||
+12
-11
@@ -25,7 +25,7 @@ use anyhow::Result;
|
|||||||
use log::debug;
|
use log::debug;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_with::serde_as;
|
use serde_with::serde_as;
|
||||||
use serde_with::{DisplayFromStr, skip_serializing_none};
|
use serde_with::{skip_serializing_none, DisplayFromStr};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use validator::{Validate, ValidationError};
|
use validator::{Validate, ValidationError};
|
||||||
@@ -107,8 +107,8 @@ fn flags_or_files(run_config: &RunConfig) -> Result<(), ValidationError> {
|
|||||||
/// use gman::providers::local::LocalProvider;
|
/// use gman::providers::local::LocalProvider;
|
||||||
/// use validator::Validate;
|
/// use validator::Validate;
|
||||||
///
|
///
|
||||||
/// let provider = SupportedProvider::Local(LocalProvider);
|
/// let provider_type = SupportedProvider::Local(LocalProvider);
|
||||||
/// let provider_config = ProviderConfig { provider, ..Default::default() };
|
/// let provider_config = ProviderConfig { provider_type, ..Default::default() };
|
||||||
/// provider_config.validate().unwrap();
|
/// provider_config.validate().unwrap();
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug, Clone, Validate, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Validate, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
@@ -116,7 +116,8 @@ pub struct ProviderConfig {
|
|||||||
#[validate(required)]
|
#[validate(required)]
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
#[serde_as(as = "DisplayFromStr")]
|
#[serde_as(as = "DisplayFromStr")]
|
||||||
pub provider: SupportedProvider,
|
#[serde(rename(deserialize = "type"))]
|
||||||
|
pub provider_type: SupportedProvider,
|
||||||
pub password_file: Option<PathBuf>,
|
pub password_file: Option<PathBuf>,
|
||||||
pub git_branch: Option<String>,
|
pub git_branch: Option<String>,
|
||||||
pub git_remote_url: Option<String>,
|
pub git_remote_url: Option<String>,
|
||||||
@@ -130,7 +131,7 @@ impl Default for ProviderConfig {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: Some("local".into()),
|
name: Some("local".into()),
|
||||||
provider: SupportedProvider::Local(LocalProvider),
|
provider_type: SupportedProvider::Local(LocalProvider),
|
||||||
password_file: Config::local_provider_password_file(),
|
password_file: Config::local_provider_password_file(),
|
||||||
git_branch: Some("main".into()),
|
git_branch: Some("main".into()),
|
||||||
git_remote_url: None,
|
git_remote_url: None,
|
||||||
@@ -146,11 +147,11 @@ impl ProviderConfig {
|
|||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// # use gman::config::ProviderConfig;
|
/// # use gman::config::ProviderConfig;
|
||||||
/// let provider = ProviderConfig::default().extract_provider();
|
/// let provider_config = ProviderConfig::default().extract_provider();
|
||||||
/// println!("using provider: {}", provider.name());
|
/// println!("using provider: {}", provider_config.name());
|
||||||
/// ```
|
/// ```
|
||||||
pub fn extract_provider(&self) -> Box<dyn SecretProvider> {
|
pub fn extract_provider(&self) -> Box<dyn SecretProvider> {
|
||||||
match &self.provider {
|
match &self.provider_type {
|
||||||
SupportedProvider::Local(p) => {
|
SupportedProvider::Local(p) => {
|
||||||
debug!("Using local secret provider");
|
debug!("Using local secret provider");
|
||||||
Box::new(*p)
|
Box::new(*p)
|
||||||
@@ -171,8 +172,8 @@ impl ProviderConfig {
|
|||||||
/// use gman::providers::local::LocalProvider;
|
/// use gman::providers::local::LocalProvider;
|
||||||
/// use validator::Validate;
|
/// use validator::Validate;
|
||||||
///
|
///
|
||||||
/// let provider = SupportedProvider::Local(LocalProvider);
|
/// let provider_type = SupportedProvider::Local(LocalProvider);
|
||||||
/// let provider_config = ProviderConfig { provider, ..Default::default() };
|
/// let provider_config = ProviderConfig { provider_type, ..Default::default() };
|
||||||
/// let cfg = Config{ providers: vec![provider_config], ..Default::default() };
|
/// let cfg = Config{ providers: vec![provider_config], ..Default::default() };
|
||||||
/// cfg.validate().unwrap();
|
/// cfg.validate().unwrap();
|
||||||
/// ```
|
/// ```
|
||||||
@@ -256,7 +257,7 @@ pub fn load_config() -> Result<Config> {
|
|||||||
config
|
config
|
||||||
.providers
|
.providers
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.filter(|p| matches!(p.provider, SupportedProvider::Local(_)))
|
.filter(|p| matches!(p.provider_type, SupportedProvider::Local(_)))
|
||||||
.for_each(|p| {
|
.for_each(|p| {
|
||||||
if p.password_file.is_none()
|
if p.password_file.is_none()
|
||||||
&& let Some(local_password_file) = Config::local_provider_password_file()
|
&& let Some(local_password_file) = Config::local_provider_password_file()
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ fn write_yaml_config(xdg_config_home: &Path, password_file: &Path, run_profile:
|
|||||||
r#"default_provider: local
|
r#"default_provider: local
|
||||||
providers:
|
providers:
|
||||||
- name: local
|
- name: local
|
||||||
provider: local
|
type: local
|
||||||
password_file: {}
|
password_file: {}
|
||||||
run_configs:
|
run_configs:
|
||||||
- name: {}
|
- name: {}
|
||||||
@@ -38,7 +38,7 @@ run_configs:
|
|||||||
r#"default_provider: local
|
r#"default_provider: local
|
||||||
providers:
|
providers:
|
||||||
- name: local
|
- name: local
|
||||||
provider: local
|
type: local
|
||||||
password_file: {}
|
password_file: {}
|
||||||
"#,
|
"#,
|
||||||
password_file.display()
|
password_file.display()
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use gman::config::{Config, ProviderConfig, RunConfig};
|
use gman::config::{Config, ProviderConfig, RunConfig};
|
||||||
use gman::providers::SupportedProvider;
|
|
||||||
use gman::providers::local::LocalProvider;
|
use gman::providers::local::LocalProvider;
|
||||||
|
use gman::providers::SupportedProvider;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
use validator::Validate;
|
use validator::Validate;
|
||||||
@@ -165,7 +165,7 @@ mod tests {
|
|||||||
fn test_provider_config_valid() {
|
fn test_provider_config_valid() {
|
||||||
let config = ProviderConfig {
|
let config = ProviderConfig {
|
||||||
name: Some("local-test".to_string()),
|
name: Some("local-test".to_string()),
|
||||||
provider: SupportedProvider::Local(LocalProvider),
|
provider_type: SupportedProvider::Local(LocalProvider),
|
||||||
password_file: None,
|
password_file: None,
|
||||||
git_branch: None,
|
git_branch: None,
|
||||||
git_remote_url: None,
|
git_remote_url: None,
|
||||||
@@ -181,7 +181,7 @@ mod tests {
|
|||||||
fn test_provider_config_invalid_email() {
|
fn test_provider_config_invalid_email() {
|
||||||
let config = ProviderConfig {
|
let config = ProviderConfig {
|
||||||
name: Some("local-test".to_string()),
|
name: Some("local-test".to_string()),
|
||||||
provider: SupportedProvider::Local(LocalProvider),
|
provider_type: SupportedProvider::Local(LocalProvider),
|
||||||
password_file: None,
|
password_file: None,
|
||||||
git_branch: None,
|
git_branch: None,
|
||||||
git_remote_url: None,
|
git_remote_url: None,
|
||||||
@@ -197,7 +197,7 @@ mod tests {
|
|||||||
fn test_provider_config_missing_name() {
|
fn test_provider_config_missing_name() {
|
||||||
let config = ProviderConfig {
|
let config = ProviderConfig {
|
||||||
name: None,
|
name: None,
|
||||||
provider: SupportedProvider::Local(LocalProvider),
|
provider_type: SupportedProvider::Local(LocalProvider),
|
||||||
password_file: None,
|
password_file: None,
|
||||||
git_branch: None,
|
git_branch: None,
|
||||||
git_remote_url: None,
|
git_remote_url: None,
|
||||||
|
|||||||
Reference in New Issue
Block a user