WIP: bring participo back - consistent use of bootstrap - formatting -
phpstan level 0 error free - fixes for kyu subpage - move mams into participo framework - remove legacy `lib/db.php` usage - add attributer admin function - add newsposter - fixing apiKey creation
This commit is contained in:
@@ -1,240 +1,183 @@
|
||||
<?php
|
||||
require_once "bootstrap.php";
|
||||
|
||||
setlocale(LC_ALL, 'de_DE@euro', 'de_DE', 'de', 'ge');
|
||||
require_once 'config/participo.php';
|
||||
require_once "./lib/api.php";
|
||||
require_once "./lib/participoLib/participo.php";
|
||||
|
||||
require_once './local/dbConf.php';
|
||||
require_once './local/cwsvJudo.php';
|
||||
participo::init($CONFIG["cwsvJudo"], $SECRETS["cwsvJudo"]);
|
||||
|
||||
require_once './lib/db.php';
|
||||
require_once './lib/api.php';
|
||||
require_once './lib/participoLib/participo.php';
|
||||
$userData = getUserData($_SESSION["user"]["userId"]);
|
||||
$usersKids = getUsersKids($_SESSION["user"]["userId"]);
|
||||
|
||||
require_once $config['basePath'] . '/config/cwsvJudo.config.php';
|
||||
require_once $config['basePath'] . '/config/phpcount.config.php';
|
||||
abstract class AttendanceType
|
||||
{
|
||||
const __default = null;
|
||||
|
||||
dbConnector::connect(
|
||||
$cwsvJudoConfig['db']['host'],
|
||||
$cwsvJudoConfig['db']['name'],
|
||||
$cwsvJudoConfig['db']['user'],
|
||||
$cwsvJudoConfig['db']['password']
|
||||
);
|
||||
const Training = 1;
|
||||
const Excused = 2;
|
||||
const Ill = 3;
|
||||
const SpecialTraining = 4;
|
||||
const Competition = 5;
|
||||
}
|
||||
|
||||
participo::authentificate();
|
||||
$userData = getUserData(dbConnector::getDbConnection(), $_SESSION['user']['userId']);
|
||||
$usersKids = getUsersKids(dbConnector::getDbConnection(), $_SESSION['user']['userId']);
|
||||
abstract class UserAttribute
|
||||
{
|
||||
const __default = null;
|
||||
|
||||
abstract class AttendanceType
|
||||
{
|
||||
const __default = null;
|
||||
const IsAdmin = 1;
|
||||
const WantsNewsLetter = 2;
|
||||
const Passive = 3;
|
||||
const InTraining = 4;
|
||||
}
|
||||
|
||||
const Training = 1;
|
||||
const Excused = 2;
|
||||
const Ill = 3;
|
||||
const SpecialTraining = 4;
|
||||
const Competition = 5;
|
||||
}
|
||||
/**
|
||||
* Datastructure and interface for attendances
|
||||
*/
|
||||
class Attendance
|
||||
{
|
||||
private $id = null; //< id in the db
|
||||
private $userId = null; //< user of the attendance
|
||||
private $date = null; //< date of the attendance
|
||||
private $type = null; //< type of attendance
|
||||
|
||||
abstract class UserAttribute
|
||||
{
|
||||
const __default = null;
|
||||
private static $Types = [
|
||||
AttendanceType::Training => "Training",
|
||||
AttendanceType::Excused => "Entschuldigt",
|
||||
AttendanceType::Ill => "Krank",
|
||||
AttendanceType::SpecialTraining => "SonderTraining",
|
||||
AttendanceType::Competition => "Wettkampf",
|
||||
];
|
||||
private static $NameOfMonth = [
|
||||
1 => "Januar",
|
||||
2 => "Februar",
|
||||
3 => "März",
|
||||
4 => "April",
|
||||
5 => "Mai",
|
||||
6 => "Juni",
|
||||
7 => "Juli",
|
||||
8 => "August",
|
||||
9 => "September",
|
||||
10 => "Oktober",
|
||||
11 => "November",
|
||||
12 => "Dezember",
|
||||
];
|
||||
|
||||
const IsAdmin = 1;
|
||||
const WantsNewsLetter = 2;
|
||||
const Passive = 3;
|
||||
const InTraining = 4;
|
||||
}
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @param string/int $id id in the db
|
||||
* @param string/int $userId user of the attendance
|
||||
* @param string $date date of the attendance
|
||||
*/
|
||||
public function __construct($id, $userId, $date)
|
||||
{
|
||||
$this->id = (int) $id;
|
||||
$this->userId = (int) $userId;
|
||||
$this->date = DateTime::createFromFormat("Y-m-d", $date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Datastructure and interface for an user
|
||||
*/
|
||||
// class User
|
||||
// {
|
||||
// private $id = null;
|
||||
// private $familyName = null;
|
||||
// private $givenName = null;
|
||||
/**
|
||||
* create an Attendance from an assoziative array
|
||||
*
|
||||
* @param array $member
|
||||
* @return Attendance
|
||||
*/
|
||||
public static function constructFromArray($member)
|
||||
{
|
||||
return new Attendance(
|
||||
$member["id"],
|
||||
$member["userId"],
|
||||
$member["date"],
|
||||
);
|
||||
}
|
||||
|
||||
// private $attributes = null;
|
||||
/**
|
||||
* request a users attendances from the database
|
||||
*
|
||||
* @param int/string $userId
|
||||
* @return array with attendances
|
||||
*/
|
||||
public static function getUsersAttendance($userId)
|
||||
{
|
||||
$userId = (int) $userId;
|
||||
$query =
|
||||
"SELECT `id`, `date` FROM `cwsvjudo_main`.`anwesenheit` WHERE `userId` = :userId";
|
||||
$response = dbConnector::query($query, [
|
||||
":userId" => ["value" => $userId, "data_type" => PDO::PARAM_INT],
|
||||
]);
|
||||
$attendances = [];
|
||||
foreach ($response as $r) {
|
||||
$attendances[] = new Attendance($r["id"], $userId, $r["date"]);
|
||||
}
|
||||
return $attendances;
|
||||
}
|
||||
|
||||
// public function __construct($id, $familyName, $givenName)
|
||||
// {
|
||||
// $this->id = (int)$id;
|
||||
// $this->familyName = $familyName;
|
||||
// $this->givenName = $givenName;
|
||||
// }
|
||||
/**
|
||||
* html table with users attendances
|
||||
*
|
||||
* @param int $userId
|
||||
* @return string with html code of the attendance table
|
||||
*/
|
||||
public static function userAttendanceHtmlTable(int $userId): string
|
||||
{
|
||||
$htmlTableString = "";
|
||||
$htmlTableString .= "<ul>";
|
||||
$userAttendances = Attendance::groupAttendances(
|
||||
Attendance::getUsersAttendance($userId),
|
||||
);
|
||||
krsort($userAttendances);
|
||||
foreach ($userAttendances as $year => $months) {
|
||||
$htmlTableString .= "<li>{$year}<dl>";
|
||||
// Counting the attendances per half year
|
||||
$attendanceCountH1 = 0;
|
||||
$attendanceCountH2 = 0;
|
||||
foreach ($months as $month => $days) {
|
||||
if (1 <= $month and $month <= 6) {
|
||||
$attendanceCountH1 += count($days);
|
||||
}
|
||||
if (7 <= $month and $month <= 12) {
|
||||
$attendanceCountH2 += count($days);
|
||||
}
|
||||
}
|
||||
$htmlTableString .= "<dt>Gesamt erstes Halbjahr:</dt><dd> {$attendanceCountH1}</dd>";
|
||||
$htmlTableString .= "<dt>Gesamt zweites Halbjahr:</dt><dd>{$attendanceCountH2}</dd>";
|
||||
krsort($months);
|
||||
foreach ($months as $month => $days) {
|
||||
$htmlTableString .=
|
||||
"<dt>" . Attendance::$NameOfMonth[$month] . "</dt>";
|
||||
$htmlTableString .= "<dd>" . join(", ", $days) . "</dd>";
|
||||
}
|
||||
$htmlTableString .= "</dl></li>";
|
||||
}
|
||||
$htmlTableString .= "</ul>";
|
||||
|
||||
// public static function fromArray($member)
|
||||
// {
|
||||
// $id = $member['id'];
|
||||
// $familyName = $member['familyName'];
|
||||
// $givenName = $member['givenName'];
|
||||
// return new User($id, $familyName, $givenName);
|
||||
// }
|
||||
|
||||
// public static function getUsers($db, $options = [])
|
||||
// {
|
||||
// $attributeId = $options['attributeId'] ?? null;
|
||||
// $params = [];
|
||||
// $query = 'SELECT ' .
|
||||
// '`cwsvjudo`.`wkParticipo_Users`.`id` AS `id`' .
|
||||
// ', `cwsvjudo`.`wkParticipo_Users`.`vorname` AS `givenName`' .
|
||||
// ', `cwsvjudo`.`wkParticipo_Users`.`name` AS `familyName`' .
|
||||
// ', `cwsvjudo`.`wkParticipo_userAttributes`.`name` AS `attributeName`' .
|
||||
// 'FROM `cwsvjudo`.`wkParticipo_Users` ' .
|
||||
// 'JOIN `cwsvjudo`.`wkParticipo_user<=>userAttributes` ' .
|
||||
// 'ON `cwsvjudo`.`wkParticipo_Users`.`id` = `cwsvjudo`.`wkParticipo_user<=>userAttributes`.`userId`' .
|
||||
// 'JOIN `cwsvjudo`.`wkParticipo_userAttributes` ' .
|
||||
// 'ON `cwsvjudo`.`wkParticipo_user<=>userAttributes`.`attributeId` = `cwsvjudo`.`wkParticipo_userAttributes`.`id`';
|
||||
// if ($attributeId != null) {
|
||||
// $query .= ' WHERE `cwsvjudo`.`wkParticipo_userAttributes`.`id` = :attributeId';
|
||||
// $params['attributeId'] = ['value' => $attributeId, 'data_type' => PDO::PARAM_INT];
|
||||
// }
|
||||
// $query .= ';';
|
||||
// $response = dbQuery($db, $query, $params);
|
||||
|
||||
// $users = [];
|
||||
// foreach ($response as $r) {
|
||||
// $users[] = User::fromDbArray($r);
|
||||
// }
|
||||
// return $users;
|
||||
// }
|
||||
|
||||
// public static function htmlTable($users)
|
||||
// {
|
||||
// echo('<table><tr><th>Id<th>Name</th><th>Vorname</th></tr>');
|
||||
// foreach ($users as $u) {
|
||||
// echo('<tr><td>' . $u->id . '</td><td>' . $u->familyName . '</td><td>' . $u->givenName . '</td></tr>');
|
||||
// }
|
||||
// echo('</table>');
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Datastructure and interface for attendances
|
||||
*/
|
||||
class Attendance
|
||||
{
|
||||
private $id = null; //< id in the db
|
||||
private $userId = null; //< user of the attendance
|
||||
private $date = null; //< date of the attendance
|
||||
private $type = null; //< type of attendance
|
||||
|
||||
private static $Types = [
|
||||
AttendanceType::Training => 'Training', AttendanceType::Excused => 'Entschuldigt', AttendanceType::Ill => 'Krank', AttendanceType::SpecialTraining => 'SonderTraining', AttendanceType::Competition => 'Wettkampf'
|
||||
];
|
||||
private static $NameOfMonth = [1 => 'Januar', 2 => 'Februar', 3 => 'März', 4 => 'April', 4 => 'Mai', 6 => 'Juni', 7 => 'Juli', 8 => 'August', 9 => 'September', 10 => 'Oktober', 11 => 'November', 12 => 'Dezember'];
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @param string/int $id id in the db
|
||||
* @param string/int $userId user of the attendance
|
||||
* @param string $date date of the attendance
|
||||
*/
|
||||
public function __construct($id, $userId, $date)
|
||||
{
|
||||
$this->id = (int)$id;
|
||||
$this->userId = (int)$userId;
|
||||
$this->date = DateTime::createFromFormat('Y-m-d', $date);
|
||||
}
|
||||
|
||||
/**
|
||||
* create an Attendance from an assoziative array
|
||||
*
|
||||
* @param array $member
|
||||
* @return Attendance
|
||||
*/
|
||||
public static function constructFromArray($member)
|
||||
{
|
||||
return new Attendance($member['id'], $member['userId'], $member['date']);
|
||||
}
|
||||
|
||||
/**
|
||||
* request a users attendances from the database
|
||||
*
|
||||
* @param PDO $db
|
||||
* @param int/string $userId
|
||||
* @return array with attendances
|
||||
*/
|
||||
public static function getUsersAttendance($db, $userId)
|
||||
{
|
||||
$userId = (int)$userId;
|
||||
$query = 'SELECT `id`, `date` FROM `cwsvjudo`.`anwesenheit` WHERE `userId` = :userId';
|
||||
$response = dbQuery($db, $query, [':userId' => ['value' => $userId, 'data_type' => PDO::PARAM_INT]]);
|
||||
$attendances = [];
|
||||
foreach ($response as $r) {
|
||||
$attendances[] = new Attendance($r['id'], $userId, $r['date']);
|
||||
}
|
||||
return $attendances;
|
||||
}
|
||||
|
||||
/**
|
||||
* html table with users attendances
|
||||
*
|
||||
* @param PDO $db
|
||||
* @param string/int $userId
|
||||
* @return string with html code of the attendance table
|
||||
*/
|
||||
public static function userAttendanceHtmlTable($db, $userId)
|
||||
{
|
||||
$htmlTableString = '';
|
||||
$htmlTableString .= '<ul>';
|
||||
$userAttendances = Attendance::groupAttendances(
|
||||
Attendance::getUsersAttendance($db, $userId)
|
||||
);
|
||||
krsort($userAttendances);
|
||||
foreach ($userAttendances as $year => $months) {
|
||||
$htmlTableString .= '<li>' . $year . '<dl>';
|
||||
// Counting the attendances per half year
|
||||
$attendanceCountH1 = 0;
|
||||
$attendanceCountH2 = 0;
|
||||
foreach ($months as $month => $days) {
|
||||
if (1 <= $month and $month <= 6) {
|
||||
$attendanceCountH1 += count($days);
|
||||
}
|
||||
if (7 <= $month and $month <= 12) {
|
||||
$attendanceCountH2 += count($days);
|
||||
}
|
||||
}
|
||||
$htmlTableString .= '<dt>Gesamt erstes Halbjahr:</dt><dd>' . $attendanceCountH1 . '</dd>';
|
||||
$htmlTableString .= '<dt>Gesamt zweites Halbjahr:</dt><dd>' . $attendanceCountH2 . '</dd>';
|
||||
krsort($months);
|
||||
foreach ($months as $month => $days) {
|
||||
$htmlTableString .= '<dt>' . Attendance::$NameOfMonth[$month] . '</dt>';
|
||||
$htmlTableString .= '<dd>' . join(', ', $days) . '</dd>';
|
||||
}
|
||||
$htmlTableString .= '</dl></li>';
|
||||
}
|
||||
$htmlTableString .= '</ul>';
|
||||
|
||||
return $htmlTableString;
|
||||
}
|
||||
|
||||
/**
|
||||
* group the attendances by year and month.
|
||||
*
|
||||
* @param list $attendances list of attendances
|
||||
* @return array[int][int](list of int) array with a list of days for every month in every year
|
||||
*/
|
||||
public static function groupAttendances($attendances)
|
||||
{
|
||||
$groupedAttendances = [];
|
||||
foreach ($attendances as $a) {
|
||||
$year = (int) $a->date->format('Y');
|
||||
if (!array_key_exists($year, $groupedAttendances)) {
|
||||
$groupedAttendances[$year] = [];
|
||||
}
|
||||
$month = (int) $a->date->format('m');
|
||||
if (!array_key_exists($month, $groupedAttendances[$year])) {
|
||||
$groupedAttendances[$year][$month] = [];
|
||||
}
|
||||
$day = (int) $a->date->format('d');
|
||||
$groupedAttendances[$year][$month][] = $day;
|
||||
}
|
||||
return $groupedAttendances;
|
||||
}
|
||||
}
|
||||
return $htmlTableString;
|
||||
}
|
||||
|
||||
/**
|
||||
* group the attendances by year and month.
|
||||
*
|
||||
* @param array $attendances list of attendances
|
||||
* @return array (list of int) array with a list of days for every month in every year
|
||||
*/
|
||||
public static function groupAttendances(array $attendances): array
|
||||
{
|
||||
$groupedAttendances = [];
|
||||
foreach ($attendances as $a) {
|
||||
$year = (int) $a->date->format("Y");
|
||||
if (!array_key_exists($year, $groupedAttendances)) {
|
||||
$groupedAttendances[$year] = [];
|
||||
}
|
||||
$month = (int) $a->date->format("m");
|
||||
if (!array_key_exists($month, $groupedAttendances[$year])) {
|
||||
$groupedAttendances[$year][$month] = [];
|
||||
}
|
||||
$day = (int) $a->date->format("d");
|
||||
$groupedAttendances[$year][$month][] = $day;
|
||||
}
|
||||
return $groupedAttendances;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
@@ -242,7 +185,7 @@ setlocale(LC_ALL, 'de_DE@euro', 'de_DE', 'de', 'ge');
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
||||
<?php readfile('./shared/imports.php'); ?>
|
||||
<?php readfile("./shared/imports.php"); ?>
|
||||
|
||||
<!-- inits for the materializeCss -->
|
||||
<script>
|
||||
@@ -257,71 +200,91 @@ setlocale(LC_ALL, 'de_DE@euro', 'de_DE', 'de', 'ge');
|
||||
<title>participo</title>
|
||||
<meta name="description" content="Online-Apps der Judoka des Chemnitzer WSV">
|
||||
|
||||
<link rel="icon" href="<?echo($config['ressourceUrl']);?>/graphiken/icons/cwsv.ico" />
|
||||
<link rel="apple-touch-icon" href="<?echo($config['baseUrl']);?>/apple-touch-icon.png">
|
||||
<link rel="icon" href="/ressourcen/graphiken/icons/cwsv.ico" />
|
||||
<link rel="apple-touch-icon" href="/ressourcen/graphiken/logos/favIcons/apple-touch-icon.png">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<nav class="indigo darken-4">
|
||||
<a href="http://cwsvjudo.bplaced.net/participo" class="breadcrumb">cwsvJudo-Apps</a>
|
||||
<a href="http://cwsvjudo.bplaced.net/participo/attendance" class="breadcrumb">Anwesenheit</a>
|
||||
<a href="/participo" class="breadcrumb">cwsvJudo-Apps</a>
|
||||
<a href="/participo/attendance" class="breadcrumb">Anwesenheit</a>
|
||||
<a class="right top-nav sidenav-trigger waves-effect waves-light hide-on-large-only" href="#" data-target="nav-mobile"><i class="material-icons">menu</i></a>
|
||||
</nav>
|
||||
<ul class="sidenav sidenav-fixed sidenav-close" id="nav-mobile">
|
||||
<li class="logo">
|
||||
<a style="height:auto;" class="brand-logo" id="logo-container" href="/participo/">
|
||||
<img alt="cwsvJudoApps" style="max-width:100%;height:12vh;" class="responsive-img" src="http://cwsvjudo.bplaced.net/ressourcen/graphiken/logos/cwsvJudoLogoWappen.x256.png" />
|
||||
<img alt="cwsvJudoApps" style="max-width:100%;height:12vh;" class="responsive-img" src="/ressourcen/graphiken/logos/cwsvJudoLogoWappen.256w.png" />
|
||||
</a>
|
||||
</li>
|
||||
<?php require_once 'sidenav/loginStatus.php'; ?><!-- brings its own li -->
|
||||
<?php require_once "sidenav/loginStatus.php"; ?><!-- brings its own li -->
|
||||
<li class="bold">
|
||||
<a class="waves-effect waves-teal right-align" href="#attendance-<?php echo($userData['id']); ?>">Selber</a>
|
||||
<a class="waves-effect waves-teal right-align" href="#attendance-<?php echo $userData[
|
||||
"id"
|
||||
]; ?>">Selber</a>
|
||||
</li>
|
||||
<?php foreach ($usersKids as $k) {
|
||||
if ($userData["id"] == $k["id"]) {
|
||||
continue;
|
||||
} ?>
|
||||
<li class="bold">
|
||||
<a class="waves-effect waves-teal right-align" href="#attendance-<?php echo $k[
|
||||
"kidId"
|
||||
]; ?>"><?php echo $k["vorname"] . " " . $k["name"]; ?></a>
|
||||
</li>
|
||||
<?php
|
||||
foreach ($usersKids as $k) {
|
||||
if ($userData['id'] == $k['id']) {
|
||||
continue;
|
||||
} ?>
|
||||
<li class="bold">
|
||||
<a class="waves-effect waves-teal right-align" href="#attendance-<?php echo($k['kidId']); ?>"><?php echo($k['vorname'] . ' ' . $k['name']); ?></a>
|
||||
</li>
|
||||
<?php
|
||||
}?>
|
||||
} ?>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<?php
|
||||
if ($_SESSION['login']) {
|
||||
?>
|
||||
<?php if ($_SESSION["login"]) { ?>
|
||||
<main>
|
||||
<?php //User::htmlTable( User::getUsers(dbConnector::getDbConnection(), ['attributeId' => UserAttribute::InTraining]));?>
|
||||
<?php // show own ...
|
||||
$ownAttendances = Attendance::getUsersAttendance(dbConnector::getDbConnection(), $_SESSION['user']['userId']);
|
||||
if (!empty($ownAttendances)) {
|
||||
echo(
|
||||
'<h2 id="attendance-' . $userData['id'] . '">Eigene Anwesenheiten</h2>' .
|
||||
Attendance::userAttendanceHtmlTable(dbConnector::getDbConnection(), $userData['id'])
|
||||
);
|
||||
require_once './lib/participoLib/participo.php';
|
||||
}
|
||||
// ... and kids attendances
|
||||
if (!empty($usersKids)) {
|
||||
echo('<h2>Anwesenheit der Kinder</h2>');
|
||||
foreach ($usersKids as $k) {
|
||||
if ($userData['id'] == $k['kidId']) {
|
||||
continue;
|
||||
}
|
||||
echo(
|
||||
'<h3 id="attendance-' . $k['kidId'] . '">' . $k['vorname'] . ' ' . $k['name'] . '</h3>' .
|
||||
Attendance::userAttendanceHtmlTable(dbConnector::getDbConnection(), $k['kidId'])
|
||||
);
|
||||
}
|
||||
} ?>
|
||||
</main>
|
||||
<?php
|
||||
}
|
||||
<?php // show own ...
|
||||
// show own ...
|
||||
|
||||
// show own ...
|
||||
|
||||
// show own ...
|
||||
|
||||
// show own ...
|
||||
|
||||
// show own ...
|
||||
|
||||
// show own ...
|
||||
|
||||
// show own ...
|
||||
|
||||
// show own ...
|
||||
|
||||
// show own ...
|
||||
|
||||
$ownAttendances = Attendance::getUsersAttendance($_SESSION["user"]["userId"]);
|
||||
if (!empty($ownAttendances)) {
|
||||
echo '<h2 id="attendance-' .
|
||||
$userData["id"] .
|
||||
'">Eigene Anwesenheiten</h2>' .
|
||||
Attendance::userAttendanceHtmlTable($userData["id"]);
|
||||
require_once "./lib/participoLib/participo.php";
|
||||
} // ... and kids attendances
|
||||
if (!empty($usersKids)) {
|
||||
echo "<h2>Anwesenheit der Kinder</h2>";
|
||||
foreach ($usersKids as $k) {
|
||||
if ($userData["id"] == $k["kidId"]) {
|
||||
continue;
|
||||
}
|
||||
echo '<h3 id="attendance-' .
|
||||
$k["kidId"] .
|
||||
'">' .
|
||||
$k["vorname"] .
|
||||
" " .
|
||||
$k["name"] .
|
||||
"</h3>" .
|
||||
Attendance::userAttendanceHtmlTable($k["kidId"]);
|
||||
}
|
||||
}
|
||||
?>
|
||||
</main>
|
||||
<?php } ?>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user