update to nationwide standard
This commit is contained in:
82
README.md
82
README.md
@@ -1,64 +1,38 @@
|
||||
# Django Installer for CentOS 7
|
||||
## Quick Install
|
||||
# Django Setup for CentOS 7
|
||||
## Install
|
||||
```bash
|
||||
$ git clone https://gitlab.ducoterra.net/server/django_installer.git
|
||||
$ cd django_installer
|
||||
$ vim vars
|
||||
vim vars
|
||||
```
|
||||
|
||||
```bash
|
||||
# django project settings
|
||||
# django project settings
|
||||
export user="centos" <---- set to your user (can use nginx)
|
||||
export projectname="mysite" <---- set to your project name
|
||||
# TODO:
|
||||
# change hostname to an array:
|
||||
# (hostname1.net hostname2.net hostname2.net)
|
||||
export hostname="centos.duco.net" <---- set to your hostname (ip or domain)
|
||||
export letsencrypt=False <---- not working yet
|
||||
export user="" <-- give the user you want to own the site
|
||||
export projectname="" <-- give your project a friendly name
|
||||
export hostname="" <-- add your hostname (can be an IP address)
|
||||
export usegit=False <-- if you have an existing project, set to True
|
||||
export giturl="" <-- put the url for the git repo here
|
||||
export gitkey="" <-- put the path to the ssh key git will use here
|
||||
```
|
||||
|
||||
```bash
|
||||
$ sudo ./install.sh
|
||||
Installing dependencies
|
||||
Installing gcc
|
||||
Installing wget
|
||||
Installing nginx
|
||||
Installing libsqlite3x-devel.x86_64
|
||||
Installing postgresql-server
|
||||
Installing postgresql-devel
|
||||
Installing postgresql-contrib
|
||||
Installing bzip2-devel
|
||||
Installing zlib-devel
|
||||
Installing libffi-devel
|
||||
Installing openssl-devel
|
||||
Installing policycoreutils-python.x86_64
|
||||
Installing Python
|
||||
Configure
|
||||
Make
|
||||
Make altinstall
|
||||
Upgrading pip
|
||||
Installing virtualenv
|
||||
Starting Django project
|
||||
Creating venv
|
||||
Installing django
|
||||
Installing gunicorn
|
||||
Installing psycopg2-binary
|
||||
Starting django project
|
||||
Collecting static
|
||||
Making migrations
|
||||
Migrating
|
||||
Setting up gunicorn
|
||||
Starting gunicorn
|
||||
Enabling gunicorn at startup
|
||||
Configuring Nginx
|
||||
Starting nginx
|
||||
Enabling nginx
|
||||
Done!
|
||||
$
|
||||
sudo ./install.sh
|
||||
```
|
||||
|
||||
Done!
|
||||
## Reset
|
||||
If anything goes wrong with the project and you don't want to perform a full uninstall:
|
||||
```bash
|
||||
sudo ./reset
|
||||
```
|
||||
will reset the project but leave the dependencies installed. You can rerun the installer with different variables to fix what was incorrect. WARNING: This will delete your project (including your database)
|
||||
|
||||
## Uninstall
|
||||
To completely remove every trace of the project from your server:
|
||||
```bash
|
||||
sudo ./uninstall
|
||||
```
|
||||
This will completely remove everything.
|
||||
|
||||
|
||||
## A more detailed explanation
|
||||
### vars
|
||||
```bash
|
||||
@@ -111,7 +85,7 @@ In order for this script to work its magic you'll need a few packages provided b
|
||||
```bash
|
||||
# check if root
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo -e "This script must be run as root"
|
||||
echo -e "This script must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
cd /root/
|
||||
@@ -288,7 +262,7 @@ Next the script starts the Django project. You'll notice that the project struct
|
||||
│ └── manage.py
|
||||
└── venv/
|
||||
```
|
||||
When making changes to nginx or gunicorn it's important to keep this structure in mind. There are 3 folders called ```$projectname```.
|
||||
When making changes to nginx or gunicorn it's important to keep this structure in mind. There are 3 folders called ```$projectname```.
|
||||
|
||||
After this, the script updates allowed hosts, collects static, and makes migrations.
|
||||
|
||||
@@ -337,4 +311,4 @@ if [ ! $user = "nginx" ] ; then
|
||||
sed -i "s/user nginx/user $user nginx/" /etc/nginx/nginx.conf
|
||||
fi
|
||||
```
|
||||
Which inserts the specified user (if not nginx) into nginx.conf. The script finishes by enabling gunicorn and nginx at startup.
|
||||
Which inserts the specified user (if not nginx) into nginx.conf. The script finishes by enabling gunicorn and nginx at startup.
|
||||
183
install.sh
183
install.sh
@@ -1,4 +1,9 @@
|
||||
################################################################################
|
||||
# NATIONWIDE AWS INSTALLER
|
||||
# Based on the django installer
|
||||
################################################################################
|
||||
|
||||
################################################################################s
|
||||
# Dependencies
|
||||
# Installs Dependencies automatically
|
||||
################################################################################
|
||||
@@ -8,7 +13,7 @@ source ./vars
|
||||
|
||||
# check if root
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo -e "This script must be run as root"
|
||||
echo -e "This script must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
cd /root/
|
||||
@@ -20,9 +25,6 @@ tput setaf 9
|
||||
if [ ! -d $logdir ] ; then
|
||||
mkdir $logdir
|
||||
fi
|
||||
if [ $install_epel_release=True ] ; then
|
||||
yum -y install epel-release 1>> $yumlogloc 2>> $yumlogloc 3>> $yumlogloc
|
||||
fi
|
||||
|
||||
# install dependencies
|
||||
packages=(gcc wget nginx libsqlite3x-devel.x86_64 postgresql-server postgresql-devel postgresql-contrib bzip2-devel zlib-devel libffi-devel openssl-devel policycoreutils-python.x86_64)
|
||||
@@ -36,23 +38,7 @@ do
|
||||
fi
|
||||
done
|
||||
|
||||
# set firewall
|
||||
ports=(80 443)
|
||||
for port in ${ports[@]};
|
||||
do
|
||||
echo -e "firewall-cmd --zone=public --add-port=$port/tcp --permanent" > $firelogloc
|
||||
firewall-cmd --zone=public --add-port=$port/tcp --permanent 1>> $firelogloc 2>> $firelogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "\tfirewall failed to update port $port correctly (this may not be an issue). $firelogmsg"
|
||||
fi
|
||||
done
|
||||
|
||||
echo -e "firewall-cmd --reload" >> $firelogloc
|
||||
firewall-cmd --reload 1>> $firelogloc 2>> $firelogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "\tfirewall failed to reload, (this may not be an issue). $firelogmsg"
|
||||
fi
|
||||
|
||||
# firewall
|
||||
echo -e "semanage permissive -a httpd_t" >> $firelogloc
|
||||
semanage permissive -a httpd_t >> $firelogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
@@ -69,51 +55,52 @@ echo -e "Installing Python"
|
||||
tput setaf 9
|
||||
|
||||
# fetch Python
|
||||
wget $pylink 1> $pylogloc 2>> $pylogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "Failed to fetch python, make sure wget is installed and $pylink is what you're after. $pylogmsg"
|
||||
exit 1
|
||||
fi
|
||||
tar xf Python-3.7.0.tar.xz >> $pylogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "Failed to unzip python. $pylogmsg"
|
||||
exit 1
|
||||
fi
|
||||
cd Python-3.7.0
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "Missing python directory. $pylogmsg"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -d $pyinstalldir ] ; then # if we already installed python
|
||||
wget $pylink 1> $pylogloc 2>> $pylogloc 3>> $pylogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "Failed to fetch python, make sure wget is installed and $pylink is what you're after. $pylogmsg"
|
||||
exit 1
|
||||
fi
|
||||
tar xf Python-3.7.0.tar.xz 1>> $pylogloc 2>> $pylogloc 3>> $pylogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "Failed to unzip python. $pylogmsg"
|
||||
exit 1
|
||||
fi
|
||||
cd Python-3.7.0
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "Missing python directory. $pylogmsg"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# install Python
|
||||
echo -e "\tConfigure"
|
||||
./configure --prefix $pyinstalldir 1>> $pylogloc 2>> $pylogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "./configure failed. $pylogmsg"
|
||||
exit 1
|
||||
# install Python
|
||||
echo -e "\tConfigure"
|
||||
./configure --prefix $pyinstalldir 1>> $pylogloc 2>> $pylogloc 3>> $pylogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "./configure failed. $pylogmsg"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "\tMake"
|
||||
make 1>> $pylogloc 2>> $pylogloc 3>> $pylogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "make failed. $pylogmsg"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "\tMake altinstall"
|
||||
make altinstall 1>> $pylogloc 2>> $pylogloc 3>> $pylogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "make altinstall failed. $pylogmsg"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
echo -e "\tMake"
|
||||
make 1>> $pylogloc 2>> $pylogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "make failed. $pylogmsg"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "\tMake altinstall"
|
||||
make altinstall 1>> $pylogloc 2>> $pylogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "make altinstall failed. $pylogmsg"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# upgrade pip and install virtualenv
|
||||
echo -e "\tUpgrading pip"
|
||||
/usr/src/python37/bin/python3.7 -m pip install --upgrade pip 1>> $pylogloc 2>> $pylogloc
|
||||
/usr/src/python37/bin/python3.7 -m pip install --upgrade pip 1>> $pylogloc 2>> $pylogloc 3>> $pylogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "pip upgrade failed. $pylogmsg"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "\tInstalling virtualenv"
|
||||
/usr/src/python37/bin/python3.7 -m pip install virtualenv 1>> $pylogloc 2>> $pylogloc
|
||||
/usr/src/python37/bin/python3.7 -m pip install virtualenv 1>> $pylogloc 2>> $pylogloc 3>> $pylogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "installing virtualenv failed. $pylogmsg"
|
||||
exit 1
|
||||
@@ -133,7 +120,7 @@ tput setaf 2
|
||||
echo -e "Starting Django project"
|
||||
tput setaf 9
|
||||
|
||||
adduser $user 1> /dev/null 2> /dev/null
|
||||
adduser $user 1> /dev/null 2> /dev/null 3> /dev/null
|
||||
if [ ! -d "/home/$user" ] ; then
|
||||
mkdir /home/$user
|
||||
chown -R $user:$user /home/$user
|
||||
@@ -146,13 +133,13 @@ fi
|
||||
|
||||
# virtual environment
|
||||
echo -e "\tCreating venv"
|
||||
cd /home/$user/
|
||||
/usr/src/python37/bin/python3.7 -m virtualenv $projectname/venv 1>> $djalogloc 2>> $djalogloc
|
||||
cd /home/$user/$projectname
|
||||
/usr/src/python37/bin/python3.7 -m virtualenv venv 1>> $djalogloc 2>> $djalogloc 3>> $djalogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "Failed to create virtual environment. $djamsg"
|
||||
exit 1
|
||||
fi
|
||||
source $projectname/venv/bin/activate >> $djalogloc
|
||||
source venv/bin/activate 1>> $djalogloc 2>> $djalogloc 3>> $djalogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "Failed to source virtual environment. $djamsg"
|
||||
exit 1
|
||||
@@ -163,52 +150,63 @@ pips=(django gunicorn psycopg2-binary)
|
||||
for pip in ${pips[@]};
|
||||
do
|
||||
echo -e "\tInstalling $pip"
|
||||
pip install $pip >> $djalogloc
|
||||
pip install $pip 1>> $djalogloc 2>> $djalogloc 3>> $djalogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "Failed to install $pip. $djamsg"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# start django project
|
||||
echo -e "\tStarting django project"
|
||||
cd $projectname
|
||||
django-admin startproject $projectname >> $djalogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "Failed to start project $projectname with django-admin. $djamsg"
|
||||
exit 1
|
||||
if [ $usegit = False ] ; then
|
||||
# start django project in the project directory
|
||||
echo -e "\tStarting django project"
|
||||
django-admin startproject config . 1>> $djalogloc 2>> $djalogloc 3>> $djalogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "Failed to start project $projectname with django-admin. $djamsg"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# update allowed hosts
|
||||
echo -e "echo -e sed -i 's/ALLOWED_HOSTS = []/ALLOWED_HOSTS = ['localhost', os.environ.get('HOST')'] config/settings.py" >> $djalogloc
|
||||
# | FROM | TO |
|
||||
sed -i "s/ALLOWED_HOSTS = \[\]/ALLOWED_HOSTS = \['localhost', os.environ.get('HOST')\]/" config/settings.py
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "Failed to change ALLOWED_HOSTS. $djamsg"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "echo -e STATIC_ROOT = os.path.join(BASE_DIR, 'static') >> config//settings.py" >> $djalogloc
|
||||
echo -e "STATIC_ROOT = os.path.join(BASE_DIR, 'static')" >> config/settings.py
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "Failed to append STATIC_ROOT. $djamsg"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# update allowed hosts
|
||||
cd /home/$user/
|
||||
echo -e "echo -e sed -i 's/ALLOWED_HOSTS = []/ALLOWED_HOSTS = [\"$hostname\"]/' $projectname/$projectname/$projectname/settings.py" >> $djalogloc
|
||||
sed -i "s/ALLOWED_HOSTS = \[\]/ALLOWED_HOSTS = \[\"$hostname\"\]/" $projectname/$projectname/$projectname/settings.py
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "Failed to change ALLOWED_HOSTS. $djamsg"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "echo -e STATIC_ROOT = os.path.join(BASE_DIR, 'static') >> $projectname/$projectname/$projectname/settings.py" >> $djalogloc
|
||||
echo -e "STATIC_ROOT = os.path.join(BASE_DIR, 'static')" >> $projectname/$projectname/$projectname/settings.py
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "Failed to append STATIC_ROOT. $djamsg"
|
||||
exit 1
|
||||
if [ $usegit = True ] ; then
|
||||
echo -e "\tCloning django project"
|
||||
ssh-agent bash -c 'ssh-add $gitkey 1>> $gitlogloc 2>> $gitlogloc 3>> $gitlogloc;
|
||||
git init 1>> $gitlogloc 2>> $gitlogloc 3>> $gitlogloc;
|
||||
git remote add origin $giturl 1>> $gitlogloc 2>> $gitlogloc 3>> $gitlogloc;
|
||||
git pull origin master 1>> $gitlogloc 2>> $gitlogloc 3>> $gitlogloc;'
|
||||
echo -e "\tInstalling pip requirements"
|
||||
pip install -r requirements.txt 1>> $gitlogloc 2>> $gitlogloc 3>> $gitlogloc
|
||||
fi
|
||||
|
||||
# collect static, migrate
|
||||
echo -e "\tCollecting static"
|
||||
python $projectname/$projectname/manage.py collectstatic >> $djalogloc
|
||||
python manage.py collectstatic 1>> $djalogloc 2>> $djalogloc 3>> $djalogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "Failed to collect static files. $djamsg"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "\tMaking migrations"
|
||||
python $projectname/$projectname/manage.py makemigrations >> $djalogloc
|
||||
python manage.py makemigrations 1>> $djalogloc 2>> $djalogloc 3>> $djalogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "Failed to make migrations. $djamsg"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "\tMigrating"
|
||||
python $projectname/$projectname/manage.py migrate >> $djalogloc
|
||||
python manage.py migrate 1>> $djalogloc 2>> $djalogloc 3>> $djalogloc
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "Failed to migrate. You do not survive the winter. $djamsg"
|
||||
exit 1
|
||||
@@ -217,12 +215,11 @@ deactivate
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "Failed to deactivate virtual environment, (this may not be an issue). $djamsg"
|
||||
fi
|
||||
chown -R $user:$user $projectname
|
||||
chown -R $user:$user .
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "Failed to change permissions of $projectname. $djamsg"
|
||||
exit 1
|
||||
fi
|
||||
cd /root/
|
||||
|
||||
################################################################################
|
||||
# Gunicorn
|
||||
@@ -239,13 +236,15 @@ After=network.target
|
||||
[Service]
|
||||
User=$user
|
||||
Group=nginx
|
||||
WorkingDirectory=/home/$user/$projectname/$projectname
|
||||
ExecStart=/home/$user/$projectname/venv/bin/gunicorn --workers 3 --bind unix:/home/$user/$projectname/$projectname.sock $projectname.wsgi:application
|
||||
WorkingDirectory=/home/$user/$projectname
|
||||
ExecStart=/home/$user/$projectname/venv/bin/gunicorn --workers 3 --bind unix:/home/$user/$projectname/$projectname.sock config.wsgi:application
|
||||
Environment=HOST=$hostname
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target" > /etc/systemd/system/gunicorn.service
|
||||
echo -e "\tStarting gunicorn"
|
||||
systemctl start gunicorn > $gunicornlogloc
|
||||
systemctl daemon-reload > $gunicornlogloc
|
||||
systemctl start gunicorn >> $gunicornlogloc
|
||||
systemctl status gunicorn >> $gunicornlogloc
|
||||
echo -e "\tEnabling gunicorn at startup"
|
||||
systemctl enable gunicorn 1>> $gunicornlogloc 2>> $gunicornlogloc
|
||||
@@ -264,7 +263,7 @@ server {
|
||||
|
||||
location = /favicon.ico { access_log off; log_not_found off; }
|
||||
location /static/ {
|
||||
root /home/$user/$projectname/$projectname;
|
||||
root /home/$user/$projectname;
|
||||
}
|
||||
|
||||
location / {
|
||||
@@ -288,4 +287,4 @@ systemctl enable nginx 1>> $nginxlogloc 2>> $nginxlogloc
|
||||
tput setaf 2
|
||||
echo -e "Done! Navigate to $hostname to access the site. Logs can be found in $logdir"
|
||||
tput setaf 9
|
||||
exit 0
|
||||
exit 0
|
||||
30
reset.sh
Normal file
30
reset.sh
Normal file
@@ -0,0 +1,30 @@
|
||||
################################################################################
|
||||
# Performs a QUICK uninstall #
|
||||
# - Does not uninstall dependencies #
|
||||
# - Does not remove python #
|
||||
################################################################################
|
||||
|
||||
# source vars
|
||||
source ./vars
|
||||
|
||||
# remove nginx conf
|
||||
tput setaf 2
|
||||
echo "Disabling nginx"
|
||||
tput setaf 9
|
||||
systemctl stop nginx 1> /dev/null 2> /dev/null
|
||||
systemctl disable nginx 1> /dev/null 2> /dev/null
|
||||
rm -f /etc/nginx/conf.d/$projectname.conf
|
||||
|
||||
# remove gunicorn
|
||||
tput setaf 2
|
||||
echo "Uninstalling gunicorn"
|
||||
tput setaf 9
|
||||
systemctl disable gunicorn 1> /dev/null 2> /dev/null
|
||||
systemctl stop gunicorn 1> /dev/null 2> /dev/null
|
||||
rm -f /etc/systemd/system/gunicorn.service
|
||||
|
||||
# remove project
|
||||
tput setaf 2
|
||||
echo "Removing Django project"
|
||||
tput setaf 9
|
||||
rm -rf /home/$user/$projectname
|
||||
@@ -1,9 +1,13 @@
|
||||
################################################################################
|
||||
# Performs a FULL uninstall #
|
||||
################################################################################
|
||||
|
||||
# source vars
|
||||
source ./vars
|
||||
|
||||
# remove nginx conf
|
||||
tput setaf 2
|
||||
echo "Uninstalling nginx"
|
||||
echo "Disabling nginx"
|
||||
tput setaf 9
|
||||
systemctl stop nginx 1> /dev/null 2> /dev/null
|
||||
systemctl disable nginx 1> /dev/null 2> /dev/null
|
||||
@@ -41,4 +45,4 @@ do
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo -e "\tyum failed to remove $package."
|
||||
fi
|
||||
done
|
||||
done
|
||||
18
vars
18
vars
@@ -1,14 +1,10 @@
|
||||
# django project settings
|
||||
export user="centos"
|
||||
export projectname="mysite"
|
||||
# TODO:
|
||||
# change hostname to an array:
|
||||
# (hostname1.net hostname2.net hostname2.net)
|
||||
export hostname="centos.duco.net"
|
||||
export letsencrypt=False
|
||||
|
||||
# set True if CentOS minimal install
|
||||
export install_epel_release=False
|
||||
export user=""
|
||||
export projectname=""
|
||||
export hostname=""
|
||||
export usegit=False # if you have a django git project
|
||||
export giturl="" # url for git project
|
||||
export gitkey="" # IdentityFile
|
||||
|
||||
# general install settings
|
||||
export logdir="/var/log/djangosetup/"
|
||||
@@ -22,6 +18,8 @@ export djalogloc=$logdir"django.log"
|
||||
export djamsg="See $djalogloc for more info."
|
||||
export gunicornlogloc=$logdir"gunicorn.log"
|
||||
export nginxlogloc=$logdir"nginx.log"
|
||||
export gitlogloc=$logdir"git.log"
|
||||
export gitlogmsg="See $gitlogloc for more info."
|
||||
|
||||
# python settings
|
||||
export pylink="https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tar.xz"
|
||||
|
||||
Reference in New Issue
Block a user