Compare commits
25 Commits
kdmurrayhp
...
06601c5d20
Author | SHA1 | Date | |
---|---|---|---|
|
06601c5d20 | ||
|
eedd954a11 | ||
|
a3b927f802 | ||
|
1853715a19 | ||
b17daba4ed
|
|||
70d5983ede
|
|||
31a5994731
|
|||
aaaaa29d8e
|
|||
3662ebd0aa
|
|||
c64ad492c8
|
|||
0f57b99fbe
|
|||
48b3c51bb3
|
|||
4e9f1457d5
|
|||
4ae854f5e1
|
|||
af810c88bc
|
|||
|
92dce90753 | ||
|
65e4e1af5e | ||
|
b5384408db | ||
|
1a84becd8d | ||
|
d74c23bace | ||
|
f1817e6820 | ||
|
493bae282b | ||
|
dbc557d4c5 | ||
|
2099f0e130 | ||
|
29c9c827a4 |
@@ -41,8 +41,9 @@ apt install libconfig-std-perl \
|
|||||||
## Using CPAN to install the modules
|
## Using CPAN to install the modules
|
||||||
|
|
||||||
A cross platform method to install the needed modules is the Perl CPAN application.
|
A cross platform method to install the needed modules is the Perl CPAN application.
|
||||||
Make sure both the [make](https://www.gnu.org/software/make/manual/make.html)
|
Make sure that the [gcc](https://www.gnu.org/software/gcc/),
|
||||||
command and the [cpan](https://perldoc.perl.org/CPAN) command are available.
|
[make](https://www.gnu.org/software/make/manual/make.html),
|
||||||
|
and [cpan](https://perldoc.perl.org/CPAN) commands are available.
|
||||||
Install them using the operating system's package manager, or from source.
|
Install them using the operating system's package manager, or from source.
|
||||||
|
|
||||||
Run commands:
|
Run commands:
|
||||||
@@ -51,9 +52,21 @@ Run commands:
|
|||||||
cpan Config::Std
|
cpan Config::Std
|
||||||
cpan Template
|
cpan Template
|
||||||
cpan Template::Plugin::DBI
|
cpan Template::Plugin::DBI
|
||||||
|
cpan Template::Plugin::HTML::Strip
|
||||||
cpan DBD::SQLite
|
cpan DBD::SQLite
|
||||||
cpan Date::Calc
|
cpan Date::Calc
|
||||||
cpan Tie::DBI
|
cpan Tie::DBI
|
||||||
|
cpan Text:CSV_XS
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing for Perl module dependencies
|
||||||
|
|
||||||
|
A bash script is included in the utils directory that will list the Perl modules used by the site-generator and report whether the modules are installed on the current OS.
|
||||||
|
|
||||||
|
It can be run from any directory. To run from the utils directory:
|
||||||
|
|
||||||
|
```
|
||||||
|
./check-dependencies.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
# Create the HPR database
|
# Create the HPR database
|
||||||
|
@@ -25,7 +25,7 @@ Static web page generator for the Hacker Public Radio website.
|
|||||||
- ``GRANT SELECT ON hpr_hpr.* TO 'hpr-generator'@'localhost';``
|
- ``GRANT SELECT ON hpr_hpr.* TO 'hpr-generator'@'localhost';``
|
||||||
- ``GRANT EXECUTE ON `hpr_hpr`.* TO 'hpr-generator'@'localhost';``
|
- ``GRANT EXECUTE ON `hpr_hpr`.* TO 'hpr-generator'@'localhost';``
|
||||||
* Install the needed Perl modules using preferred method (distribution packages, CPAN, etc.)
|
* Install the needed Perl modules using preferred method (distribution packages, CPAN, etc.)
|
||||||
* GetOpt
|
* Getopt::Long
|
||||||
* Pod::Usage
|
* Pod::Usage
|
||||||
* Config::Std
|
* Config::Std
|
||||||
* Template
|
* Template
|
||||||
@@ -35,7 +35,7 @@ Static web page generator for the Hacker Public Radio website.
|
|||||||
* Template::Plugin::HTML::Strip
|
* Template::Plugin::HTML::Strip
|
||||||
* DBI
|
* DBI
|
||||||
* Tie::DBI
|
* Tie::DBI
|
||||||
* DBD::SQLite or DBD:mysql
|
* DBD::SQLite or DBD::mysql
|
||||||
* Date::Calc
|
* Date::Calc
|
||||||
* Text::CSV_XS
|
* Text::CSV_XS
|
||||||
* HTML::Entities
|
* HTML::Entities
|
||||||
@@ -72,6 +72,8 @@ and add the label "**Feature Request**".
|
|||||||
|
|
||||||
## Authors and acknowledgment
|
## Authors and acknowledgment
|
||||||
* Roan "Rho`n" Horning
|
* Roan "Rho`n" Horning
|
||||||
|
* Dave Morriss
|
||||||
* gordons
|
* gordons
|
||||||
* Ken Fallon
|
* Ken Fallon
|
||||||
* norrist
|
* norrist
|
||||||
|
|
||||||
|
BIN
public_html/images/hosts/149.png
Normal file
BIN
public_html/images/hosts/149.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.1 KiB |
BIN
public_html/images/hosts/421.png
Normal file
BIN
public_html/images/hosts/421.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.5 KiB |
BIN
public_html/images/hosts/425.png
Normal file
BIN
public_html/images/hosts/425.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
public_html/images/hosts/433.png
Normal file
BIN
public_html/images/hosts/433.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.0 KiB |
@@ -122,7 +122,6 @@ use Text::CSV_XS;
|
|||||||
use HTML::Entities qw(encode_entities);
|
use HTML::Entities qw(encode_entities);
|
||||||
use Date::Calc;
|
use Date::Calc;
|
||||||
use DBI;
|
use DBI;
|
||||||
use DBD::SQLite;
|
|
||||||
use Tie::DBI;
|
use Tie::DBI;
|
||||||
use Template;
|
use Template;
|
||||||
use Template::Plugin::Date;
|
use Template::Plugin::Date;
|
||||||
|
@@ -582,9 +582,10 @@
|
|||||||
|
|
||||||
<h1 id="reserve_queue">Feed the reserve queue<a href="<!--% absolute_url(baseurl,'about.html#reserve_queue') %-->">.</a></h1>
|
<h1 id="reserve_queue">Feed the reserve queue<a href="<!--% absolute_url(baseurl,'about.html#reserve_queue') %-->">.</a></h1>
|
||||||
<p>
|
<p>
|
||||||
The reserve queue is intended only to be used in the cases where there is still a gap in the schedule 24 hours prior to release.
|
The reserve queue is intended only to be used in the cases where there is still a gap in the schedule one week prior to release.
|
||||||
This was known as the emergency queue, but now can also be used when the hosts don't care when the shows are scheduled.
|
This was known as the emergency queue, but now can also be used when the hosts don't care when the shows are scheduled.
|
||||||
They will be used on a first come first go basis, when there is no conflict with the scheduling guidelines.
|
They will be used on a first come first go basis, when there is no conflict with the scheduling guidelines.
|
||||||
|
These shows contain a message alerting listeners to the fact that we had free slots that were not filled.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
@@ -592,11 +593,12 @@
|
|||||||
<h1 id="scheduling_guidelines">Scheduling Guidelines</h1>
|
<h1 id="scheduling_guidelines">Scheduling Guidelines</h1>
|
||||||
<ol>
|
<ol>
|
||||||
<li>You must have your audio recording ready to upload <strong>before</strong> you pick a slot.</li>
|
<li>You must have your audio recording ready to upload <strong>before</strong> you pick a slot.</li>
|
||||||
|
<li>New hosts, Interviews, and other time critical shows should use the first free slot.</li>
|
||||||
<li>Always try and fill any free slots that are available in the upcoming two weeks.</li>
|
<li>Always try and fill any free slots that are available in the upcoming two weeks.</li>
|
||||||
<li>If the queue is filling up then please consider leaving some slots free for new contributors.</li>
|
<li>When the queue is filling up then leave some slots free for new contributors.</li>
|
||||||
<li>If you have a non urgent show then find a empty week and schedule it then.</li>
|
<li>Post non urgent shows into the first empty week.</li>
|
||||||
<li>If you are uploading a series of shows, consider scheduling one every two weeks.</li>
|
<li>If you are uploading a series of shows then post them one every two weeks.</li>
|
||||||
<li>Interviews may be released sooner.</li>
|
<li>If you have a non urgent show that is timeless, then add it to the <a href="<!--% absolute_url(baseurl,'about.html#reserve_queue') %-->">Reserve Queue</a>.</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
@@ -3,15 +3,10 @@
|
|||||||
<!--% PROCESS 'shared-utils.tpl.html' %-->
|
<!--% PROCESS 'shared-utils.tpl.html' %-->
|
||||||
<!--% PROCESS "queries-correspondent-${constants.database}.tpl.html" %-->
|
<!--% PROCESS "queries-correspondent-${constants.database}.tpl.html" %-->
|
||||||
<!--% USE DBI(constants.driver, constants.user, constants.password) %-->
|
<!--% USE DBI(constants.driver, constants.user, constants.password) %-->
|
||||||
<!--% query_hpr_show_count = DBI.prepare('
|
|
||||||
SELECT id
|
|
||||||
FROM eps
|
|
||||||
WHERE eps.hostid = ?
|
|
||||||
')
|
|
||||||
%-->
|
|
||||||
<!--% results_hpr_shows = DBI.prepare(query_hpr_shows)
|
<!--% results_hpr_shows = DBI.prepare(query_hpr_shows)
|
||||||
%-->
|
%-->
|
||||||
<!--% hpr_shows_to_count = query_hpr_show_count.execute(id); %-->
|
<!--% results_hpr_show_count = DBI.prepare(query_hpr_show_count) %-->
|
||||||
|
<!--% hpr_shows_to_count = results_hpr_show_count.execute(id); %-->
|
||||||
<!--% hpr_shows = results_hpr_shows.execute(id); %-->
|
<!--% hpr_shows = results_hpr_shows.execute(id); %-->
|
||||||
<!--% hpr_show_count = 0 %-->
|
<!--% hpr_show_count = 0 %-->
|
||||||
<!--% FOREACH show IN hpr_shows_to_count %-->
|
<!--% FOREACH show IN hpr_shows_to_count %-->
|
||||||
|
@@ -110,9 +110,18 @@ Subscribe to the comments <a href="<!--% absolute_path(baseurl) %-->comments.rss
|
|||||||
</tr>
|
</tr>
|
||||||
<!-- . -->
|
<!-- . -->
|
||||||
<tr>
|
<tr>
|
||||||
<td>What is the <strong>HOST_ID</strong> for the host of this show?</td>
|
<td>Who is the <strong>host</strong> of this show?</td>
|
||||||
|
<td>
|
||||||
|
<select required name="hostid" id="hostid">
|
||||||
|
<option value="Spammer" selected="selected">Spammer</option>
|
||||||
|
<option value="Spammer">Linus Torvalds</option>
|
||||||
|
<option value="Spammer">Marie Curie</option>
|
||||||
|
<option value="<!--% episode.hostid %-->"><!--% episode.host %--></option>
|
||||||
|
<option value="Spammer">Alan Turing</option>
|
||||||
|
<option value="Spammer">Terry Pratchett</option>
|
||||||
|
<option value="Spammer">Yuri Gagarin</option>
|
||||||
|
</select>
|
||||||
<td>
|
<td>
|
||||||
<input required type="text" name="hostid" size="20" maxlength="5" placeholder="Type the host number"></td>
|
|
||||||
<td>
|
<td>
|
||||||
<!-- . -->
|
<!-- . -->
|
||||||
<tr>
|
<tr>
|
||||||
|
@@ -4,27 +4,27 @@
|
|||||||
<!--% PERL %-->
|
<!--% PERL %-->
|
||||||
$Template::Stash::PRIVATE = undef; # Allow . in tag
|
$Template::Stash::PRIVATE = undef; # Allow . in tag
|
||||||
<!--% END %-->
|
<!--% END %-->
|
||||||
|
<!--% USE String %-->
|
||||||
<!--% uniq_tag_count = 0 %-->
|
<!--% uniq_tag_count = 0 %-->
|
||||||
<!--% comma_re = '(?x)(?:^|,\s*)(?:"((?>[^"]*)(?:""[^"]*)*)"|([^",]*))'; %-->
|
|
||||||
<!--# 'Moka5,interview, "computer science"' -->
|
|
||||||
<!--% FOREACH episode IN DBI.query(query_tags);
|
<!--% FOREACH episode IN DBI.query(query_tags);
|
||||||
ep_id = episode.id;
|
ep_id = episode.id;
|
||||||
ep_tags = episode.tags;
|
ep_tags = episode.tags;
|
||||||
FOREACH tag_str IN ep_tags.split(comma_re);
|
FOREACH tag_str IN ep_tags.csv_parse;
|
||||||
NEXT UNLESS tag_str;
|
NEXT UNLESS tag_str;
|
||||||
NEXT IF tag_str == '';
|
NEXT IF tag_str == '';
|
||||||
tag = tag_str.lower;
|
tag = tag_str.lower;
|
||||||
|
tag_index = String.new(tag).push('_');
|
||||||
first_char = tag.substr(0,1);
|
first_char = tag.substr(0,1);
|
||||||
IF first_char == '.';
|
IF first_char == '.';
|
||||||
first_char = '.'; # Unicode .
|
first_char = '.'; # Unicode .
|
||||||
END;
|
END;
|
||||||
IF all_tags.${first_char}.exists(tag);
|
IF all_tags.${first_char}.exists(tag_index);
|
||||||
all_tags.${first_char}.${tag}.count = all_tags.${first_char}.${tag}.count + 1;
|
all_tags.${first_char}.${tag_index}.count = all_tags.${first_char}.${tag_index}.count + 1;
|
||||||
all_tags.${first_char}.${tag}.urls.push(ep_id);
|
all_tags.${first_char}.${tag_index}.urls.push(ep_id);
|
||||||
ELSE;
|
ELSE;
|
||||||
all_tags.${first_char}.${tag}.count = 1;
|
all_tags.${first_char}.${tag_index}.count = 1;
|
||||||
uniq_tag_count = uniq_tag_count + 1;
|
uniq_tag_count = uniq_tag_count + 1;
|
||||||
all_tags.${first_char}.${tag}.urls = [ep_id];
|
all_tags.${first_char}.${tag_index}.urls = [ep_id];
|
||||||
END;
|
END;
|
||||||
END;
|
END;
|
||||||
END %-->
|
END %-->
|
||||||
@@ -53,7 +53,7 @@ END %-->
|
|||||||
<ul class="columns3">
|
<ul class="columns3">
|
||||||
<!--% FOREACH first_char IN all_first %-->
|
<!--% FOREACH first_char IN all_first %-->
|
||||||
<!--% IF all_tags.${first_char} %-->
|
<!--% IF all_tags.${first_char} %-->
|
||||||
<li><a href="<!--% absolute_path(baseurl) %-->tags.html#<!--% all_tags.${first_char}.keys.sort.first %-->"><strong><!--% first_char %--></strong></a></li>
|
<li><a href="<!--% absolute_path(baseurl) %-->tags.html#<!--% tag_to_id(String.new(all_tags.${first_char}.keys.sort.first).chop) %-->"><strong><!--% first_char %--></strong></a></li>
|
||||||
<!--% END %-->
|
<!--% END %-->
|
||||||
<!--% END %-->
|
<!--% END %-->
|
||||||
</ul>
|
</ul>
|
||||||
@@ -63,11 +63,12 @@ END %-->
|
|||||||
<p class="ralign"><a href="<!--% absolute_path(baseurl) %-->tags.html#TOP">↑ Go to index</a></p>
|
<p class="ralign"><a href="<!--% absolute_path(baseurl) %-->tags.html#TOP">↑ Go to index</a></p>
|
||||||
<h3>Tags beginning with '<!--% first_char %-->'</h3>
|
<h3>Tags beginning with '<!--% first_char %-->'</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<!--% FOREACH tag IN all_tags.${first_char}.keys.sort %-->
|
<!--% FOREACH tag_index IN all_tags.${first_char}.keys.sort %-->
|
||||||
|
<!--% tag = String.new(tag_index).chop; tag_id = String.new(tag_index).chop; %-->
|
||||||
<li>
|
<li>
|
||||||
<a id="<!--% tag %-->"><strong><!--% tag %--></strong></a>:
|
<a id="<!--% tag_to_id(tag_id) %-->"><strong><!--% tag %--></strong></a>:
|
||||||
<!--% ep_links = [] %-->
|
<!--% ep_links = [] %-->
|
||||||
<!--% FOREACH ep_id IN all_tags.${first_char}.${tag}.urls.nsort;
|
<!--% FOREACH ep_id IN all_tags.${first_char}.${tag_index}.urls.nsort;
|
||||||
ep_links.push("<a href=\"${absolute_path(baseurl)}eps/hpr" _ zero_pad_left(ep_id) _ '/index.html"'
|
ep_links.push("<a href=\"${absolute_path(baseurl)}eps/hpr" _ zero_pad_left(ep_id) _ '/index.html"'
|
||||||
' target="_blank" aria-label="' _ tag _
|
' target="_blank" aria-label="' _ tag _
|
||||||
' - show ' _ ep_id _ '">' _ ep_id _ '</a>');
|
' - show ' _ ep_id _ '">' _ ep_id _ '</a>');
|
||||||
|
@@ -16,3 +16,9 @@
|
|||||||
ORDER BY eps.id DESC
|
ORDER BY eps.id DESC
|
||||||
'
|
'
|
||||||
%-->
|
%-->
|
||||||
|
<!--% query_hpr_show_count = '
|
||||||
|
SELECT id
|
||||||
|
FROM eps
|
||||||
|
WHERE eps.hostid = ? AND eps.date < DATE_ADD(NOW(), INTERVAL 1 DAY)
|
||||||
|
'
|
||||||
|
%-->
|
||||||
|
@@ -16,3 +16,9 @@
|
|||||||
ORDER BY eps.id + 0 DESC
|
ORDER BY eps.id + 0 DESC
|
||||||
'
|
'
|
||||||
%-->
|
%-->
|
||||||
|
<!--% query_hpr_show_count = '
|
||||||
|
SELECT id
|
||||||
|
FROM eps
|
||||||
|
WHERE eps.hostid = ? AND eps.date < date(\'now\', \'+1 days\')
|
||||||
|
'
|
||||||
|
%-->
|
||||||
|
@@ -14,7 +14,7 @@ from the series <em><a href="<!--% baseurl %-->series/<!--% zero_pad_left(series
|
|||||||
<!--% MACRO display_tags(tags) BLOCK %-->
|
<!--% MACRO display_tags(tags) BLOCK %-->
|
||||||
<span><label>Tags:</label> <em>
|
<span><label>Tags:</label> <em>
|
||||||
<!--% FOREACH tag IN tags.csv_parse %-->
|
<!--% FOREACH tag IN tags.csv_parse %-->
|
||||||
<a href="<!--% absolute_path(baseurl) %-->tags.html#<!--% tag.lower %-->"><!--% tag %--></a><!--% IF loop.count == loop.size %-->.<!--% ELSE %-->,<!--% END %-->
|
<a href="<!--% absolute_path(baseurl) %-->tags.html#<!--% tag_to_id(tag) %-->"><!--% tag %--></a><!--% IF loop.count == loop.size %-->.<!--% ELSE %-->,<!--% END %-->
|
||||||
<!--% END %--></em>
|
<!--% END %--></em>
|
||||||
</span>
|
</span>
|
||||||
<!--% END %-->
|
<!--% END %-->
|
||||||
|
@@ -49,6 +49,15 @@
|
|||||||
<!--% iso8601_date.format(date_to_format) %-->
|
<!--% iso8601_date.format(date_to_format) %-->
|
||||||
<!--% END %-->
|
<!--% END %-->
|
||||||
|
|
||||||
|
<!--% MACRO tag_to_id(tag, is_index) BLOCK %-->
|
||||||
|
<!--% tag = tag.replace('\s+','_') %-->
|
||||||
|
<!--% IF is_index %-->
|
||||||
|
<!--% tag.upper %-->
|
||||||
|
<!--% ELSE %-->
|
||||||
|
<!--% tag.lower %-->
|
||||||
|
<!--% END %-->
|
||||||
|
<!--% END %-->
|
||||||
|
|
||||||
<!--% MACRO absolute_url(base, path) BLOCK %-->
|
<!--% MACRO absolute_url(base, path) BLOCK %-->
|
||||||
<!--% UNLESS base.empty %-->
|
<!--% UNLESS base.empty %-->
|
||||||
<!--% UNLESS base.substr(-1) == '/' %-->
|
<!--% UNLESS base.substr(-1) == '/' %-->
|
||||||
|
73
utils/check-dependencies.sh
Executable file
73
utils/check-dependencies.sh
Executable file
@@ -0,0 +1,73 @@
|
|||||||
|
#!/bin/bash -
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
# FILE: check-dependencies.sh
|
||||||
|
#
|
||||||
|
# USAGE: ./check-dependencies.sh
|
||||||
|
#
|
||||||
|
# DESCRIPTION: Check that Perl module dependencies for the hpr_generator
|
||||||
|
# are installed.
|
||||||
|
#
|
||||||
|
# OPTIONS: ---
|
||||||
|
# REQUIREMENTS: ---
|
||||||
|
# BUGS: ---
|
||||||
|
# NOTES: ---
|
||||||
|
# AUTHOR: Roan "Rho`n" Horning (roan.horning@gmail.com)
|
||||||
|
# ORGANIZATION:
|
||||||
|
# CREATED: 09/05/2024 09:55:00 PM
|
||||||
|
# REVISION: ---
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
set -o nounset # Treat unset variables as an error
|
||||||
|
|
||||||
|
#--- FUNCTION ----------------------------------------------------------------
|
||||||
|
# NAME: is_module_installed
|
||||||
|
# DESCRIPTION: Tests if the supplied module is found on the system
|
||||||
|
# PARAMETERS: Name of the denpendent Perl module
|
||||||
|
# RETURNS: 0 if not found, 1 if found
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
function is_module_installed {
|
||||||
|
HR="----------------------"
|
||||||
|
perl -e "use ${1} "
|
||||||
|
if [ $? -ne 0 ]
|
||||||
|
then
|
||||||
|
echo ${HR}
|
||||||
|
else
|
||||||
|
echo "Found module ${1}"
|
||||||
|
echo ${HR}
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
MODULES=( \
|
||||||
|
"Getopt::Long" \
|
||||||
|
"Pod::Usage" \
|
||||||
|
"Config::Std" \
|
||||||
|
"Template" \
|
||||||
|
"Template::Plugin::File" \
|
||||||
|
"Template::Plugin::DBI" \
|
||||||
|
"Template::Plugin::HTML::Strip" \
|
||||||
|
"DBI" \
|
||||||
|
"Tie::DBI" \
|
||||||
|
"DBD::SQLite" \
|
||||||
|
"DBD::mysql" \
|
||||||
|
"Date::Calc" \
|
||||||
|
"Text::CSV_XS" \
|
||||||
|
)
|
||||||
|
|
||||||
|
echo "The following modules must be installed for the site-generator to function: "
|
||||||
|
for module in "${MODULES[@]}"
|
||||||
|
do
|
||||||
|
echo "* ${module}"
|
||||||
|
done
|
||||||
|
echo "When MySQL is used, the DBD:mysql module is required (otherwise it is optional)"
|
||||||
|
echo "When SQLite is used, then the DBD:SQLite module is required (otherwise it is optional)"
|
||||||
|
|
||||||
|
echo "Scanning for modules ..."
|
||||||
|
echo "----------------------"
|
||||||
|
|
||||||
|
for module in "${MODULES[@]}"
|
||||||
|
do
|
||||||
|
is_module_installed "${module}"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Finished scanning."
|
Reference in New Issue
Block a user