UserOverview
This commit is contained in:
parent
e5d504b6c7
commit
7124038b5b
6
admin/dist/main.js
vendored
6
admin/dist/main.js
vendored
File diff suppressed because one or more lines are too long
@ -41,4 +41,8 @@ export default class API {
|
|||||||
async fetchUsers(pageNum = 1) {
|
async fetchUsers(pageNum = 1) {
|
||||||
return this.apiCall("user/fetch", { page: pageNum });
|
return this.apiCall("user/fetch", { page: pageNum });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fetchGroups(pageNum = 1) {
|
||||||
|
return this.apiCall("groups/fetch", { page: pageNum });
|
||||||
|
}
|
||||||
};
|
};
|
@ -27,6 +27,31 @@ export default class UserOverview extends React.Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fetchGroups(page) {
|
||||||
|
page = page || this.state.groups.page;
|
||||||
|
this.setState({ ...this.state, groups: { ...this.state.groups, data: { }, page: 1 } });
|
||||||
|
this.parent.api.fetchGroups(page).then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
this.setState({
|
||||||
|
...this.state,
|
||||||
|
groups: {
|
||||||
|
data: res.groups,
|
||||||
|
pageCount: res.pageCount,
|
||||||
|
page: page
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
...this.state,
|
||||||
|
errors: this.state.errors.slice().push(res.msg)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!this.state.loaded) {
|
||||||
|
this.fetchUsers(1)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fetchUsers(page) {
|
fetchUsers(page) {
|
||||||
page = page || this.state.users.page;
|
page = page || this.state.users.page;
|
||||||
this.setState({ ...this.state, users: { ...this.state.users, data: { }, pageCount: 1 } });
|
this.setState({ ...this.state, users: { ...this.state.users, data: { }, pageCount: 1 } });
|
||||||
@ -53,7 +78,7 @@ export default class UserOverview extends React.Component {
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.setState({ ...this.state, loaded: false });
|
this.setState({ ...this.state, loaded: false });
|
||||||
this.fetchUsers(1);
|
this.fetchGroups(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -86,6 +111,9 @@ export default class UserOverview extends React.Component {
|
|||||||
<div className={"col-lg-6"}>
|
<div className={"col-lg-6"}>
|
||||||
{ this.createUserCard() }
|
{ this.createUserCard() }
|
||||||
</div>
|
</div>
|
||||||
|
<div className={"col-lg-6"}>
|
||||||
|
{ this.createGroupCard() }
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -177,4 +205,76 @@ export default class UserOverview extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createGroupCard() {
|
||||||
|
let groupRows = [];
|
||||||
|
for (let uid in this.state.groups.data) {
|
||||||
|
if (!this.state.groups.data.hasOwnProperty(uid)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let group = this.state.groups.data[uid];
|
||||||
|
|
||||||
|
groupRows.push(
|
||||||
|
<tr key={"group-" + uid}>
|
||||||
|
<td>{group.name}</td>
|
||||||
|
<td>{group.memberCount}</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let pages = [];
|
||||||
|
let previousDisabled = (this.state.groups.page === 1 ? " disabled" : "");
|
||||||
|
let nextDisabled = (this.state.groups.page >= this.state.groups.pageCount ? " disabled" : "");
|
||||||
|
|
||||||
|
for (let i = 1; i <= this.state.groups.pageCount; i++) {
|
||||||
|
let active = (this.state.groups.page === i ? " active" : "");
|
||||||
|
pages.push(
|
||||||
|
<li key={"page-" + i} className={"page-item" + active}>
|
||||||
|
<a className={"page-link"} href={"#"} onClick={() => this.fetchGroups(i)}>
|
||||||
|
{i}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div className={"card"}>
|
||||||
|
<div className={"card-header border-0"}>
|
||||||
|
<h3 className={"card-title"}>Groups</h3>
|
||||||
|
<div className={"card-tools"}>
|
||||||
|
<a href={"#"} className={"btn btn-tool btn-sm"} onClick={() => this.fetchGroups()}>
|
||||||
|
<Icon icon={"sync"}/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"card-body table-responsive p-0"}>
|
||||||
|
<table className={"table table-striped table-valign-middle"}>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Members</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{ groupRows }
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<nav aria-label={""}>
|
||||||
|
<ul className={"pagination p-2 m-0 justify-content-end"}>
|
||||||
|
<li className={"page-item" + previousDisabled}>
|
||||||
|
<a className={"page-link"} href={"#"} onClick={() => this.fetchGroups(this.state.groups.page - 1)}>
|
||||||
|
Previous
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{ pages }
|
||||||
|
<li className={"page-item" + nextDisabled}>
|
||||||
|
<a className={"page-link"} href={"#"} onClick={() => this.fetchGroups(this.state.groups.page + 1)}>
|
||||||
|
Next
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
}
|
}
|
83
core/Api/Groups/Fetch.class.php
Normal file
83
core/Api/Groups/Fetch.class.php
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Api\Groups;
|
||||||
|
|
||||||
|
use \Api\Parameter\Parameter;
|
||||||
|
use \Api\Request;
|
||||||
|
|
||||||
|
class Fetch extends Request {
|
||||||
|
|
||||||
|
const SELECT_SIZE = 10;
|
||||||
|
|
||||||
|
private int $groupCount;
|
||||||
|
|
||||||
|
public function __construct($user, $externalCall = false) {
|
||||||
|
parent::__construct($user, $externalCall, array(
|
||||||
|
'page' => new Parameter('page', Parameter::TYPE_INT, true, 1)
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->loginRequired = true;
|
||||||
|
$this->requiredGroup = USER_GROUP_ADMIN;
|
||||||
|
$this->csrfTokenRequired = true;
|
||||||
|
$this->groupCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getGroupCount() {
|
||||||
|
|
||||||
|
$sql = $this->user->getSQL();
|
||||||
|
$res = $sql->select($sql->count())->from("Group")->execute();
|
||||||
|
$this->success = ($res !== FALSE);
|
||||||
|
$this->lastError = $sql->getLastError();
|
||||||
|
|
||||||
|
if ($this->success) {
|
||||||
|
$this->groupCount = $res[0]["count"];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute($values = array()) {
|
||||||
|
if(!parent::execute($values)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$page = $this->getParam("page");
|
||||||
|
if($page < 1) {
|
||||||
|
return $this->createError("Invalid page count");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->getGroupCount()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = $this->user->getSQL();
|
||||||
|
$res = $sql->select("Group.uid as groupId", "Group.name as groupName", $sql->count("UserGroup.user_id"))
|
||||||
|
->from("Group")
|
||||||
|
->innerJoin("UserGroup", "UserGroup.group_id", "Group.uid")
|
||||||
|
->groupBy("Group.uid")
|
||||||
|
->orderBy("Group.uid")
|
||||||
|
->ascending()
|
||||||
|
->limit(Fetch::SELECT_SIZE)
|
||||||
|
->offset(($page - 1) * Fetch::SELECT_SIZE)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$this->success = ($res !== FALSE);
|
||||||
|
$this->lastError = $sql->getLastError();
|
||||||
|
|
||||||
|
if($this->success) {
|
||||||
|
$this->result["groups"] = array();
|
||||||
|
foreach($res as $row) {
|
||||||
|
$groupId = intval($row["groupId"]);
|
||||||
|
$groupName = $row["groupName"];
|
||||||
|
$memberCount = $row["usergroup_user_id_count"];
|
||||||
|
$this->result["groups"][$groupId] = array(
|
||||||
|
"name" => $groupName,
|
||||||
|
"memberCount" => $memberCount
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$this->result["pageCount"] = intval(ceil($this->groupCount / Fetch::SELECT_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->success;
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@ class Select extends Query {
|
|||||||
private array $conditions;
|
private array $conditions;
|
||||||
private array $joins;
|
private array $joins;
|
||||||
private array $orderColumns;
|
private array $orderColumns;
|
||||||
|
private array $groupColumns;
|
||||||
private bool $sortAscending;
|
private bool $sortAscending;
|
||||||
private int $limit;
|
private int $limit;
|
||||||
private int $offset;
|
private int $offset;
|
||||||
@ -23,6 +24,7 @@ class Select extends Query {
|
|||||||
$this->conditions = array();
|
$this->conditions = array();
|
||||||
$this->joins = array();
|
$this->joins = array();
|
||||||
$this->orderColumns = array();
|
$this->orderColumns = array();
|
||||||
|
$this->groupColumns = array();
|
||||||
$this->limit = 0;
|
$this->limit = 0;
|
||||||
$this->offset = 0;
|
$this->offset = 0;
|
||||||
$this->sortAscending = true;
|
$this->sortAscending = true;
|
||||||
@ -48,6 +50,11 @@ class Select extends Query {
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function groupBy(...$columns) {
|
||||||
|
$this->groupColumns = $columns;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function orderBy(...$columns) {
|
public function orderBy(...$columns) {
|
||||||
$this->orderColumns = $columns;
|
$this->orderColumns = $columns;
|
||||||
return $this;
|
return $this;
|
||||||
@ -85,5 +92,6 @@ class Select extends Query {
|
|||||||
public function getOrderBy() { return $this->orderColumns; }
|
public function getOrderBy() { return $this->orderColumns; }
|
||||||
public function getLimit() { return $this->limit; }
|
public function getLimit() { return $this->limit; }
|
||||||
public function getOffset() { return $this->offset; }
|
public function getOffset() { return $this->offset; }
|
||||||
|
public function getGroupBy() { return $this->groupColumns; }
|
||||||
|
|
||||||
}
|
}
|
@ -180,6 +180,12 @@ abstract class SQL {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$groupBy = "";
|
||||||
|
$groupColumns = $select->getGroupBy();
|
||||||
|
if (!empty($groupColumns)) {
|
||||||
|
$groupBy = " GROUP BY " . $this->columnName($groupColumns);
|
||||||
|
}
|
||||||
|
|
||||||
$orderBy = "";
|
$orderBy = "";
|
||||||
$orderColumns = $select->getOrderBy();
|
$orderColumns = $select->getOrderBy();
|
||||||
if (!empty($orderColumns)) {
|
if (!empty($orderColumns)) {
|
||||||
@ -189,7 +195,7 @@ abstract class SQL {
|
|||||||
|
|
||||||
$limit = ($select->getLimit() > 0 ? (" LIMIT " . $select->getLimit()) : "");
|
$limit = ($select->getLimit() > 0 ? (" LIMIT " . $select->getLimit()) : "");
|
||||||
$offset = ($select->getOffset() > 0 ? (" OFFSET " . $select->getOffset()) : "");
|
$offset = ($select->getOffset() > 0 ? (" OFFSET " . $select->getOffset()) : "");
|
||||||
$query = "SELECT $columns FROM $tables$joinStr$where$orderBy$limit$offset";
|
$query = "SELECT $columns FROM $tables$joinStr$where$groupBy$orderBy$limit$offset";
|
||||||
if($select->dump) { var_dump($query); var_dump($params); }
|
if($select->dump) { var_dump($query); var_dump($params); }
|
||||||
return $this->execute($query, $params, true);
|
return $this->execute($query, $params, true);
|
||||||
}
|
}
|
||||||
@ -280,8 +286,9 @@ abstract class SQL {
|
|||||||
if (is_null($col)) {
|
if (is_null($col)) {
|
||||||
return new Keyword("COUNT(*) AS count");
|
return new Keyword("COUNT(*) AS count");
|
||||||
} else {
|
} else {
|
||||||
|
$countCol = strtolower(str_replace(".","_", $col)) . "_count";
|
||||||
$col = $this->columnName($col);
|
$col = $this->columnName($col);
|
||||||
return new Keyword("COUNT($col) AS count");
|
return new Keyword("COUNT($col) AS $countCol");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
6
js/admin.min.js
vendored
6
js/admin.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user