Updated logs screen
This commit is contained in:
parent
87a9ce2941
commit
17bbdc3a52
File diff suppressed because one or more lines are too long
|
@ -226,12 +226,12 @@ App::get('/v1/database/collections/:collectionId')
|
|||
});
|
||||
|
||||
App::get('/v1/database/collections/:collectionId/logs')
|
||||
->desc('Get Collection Logs')
|
||||
->desc('List Collection Logs')
|
||||
->groups(['api', 'database'])
|
||||
->label('scope', 'collections.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
->label('sdk.namespace', 'database')
|
||||
->label('sdk.method', 'getCollectionLogs')
|
||||
->label('sdk.method', 'listCollectionLogs')
|
||||
->label('sdk.description', '/docs/references/database/get-collection-logs.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
|
@ -287,6 +287,9 @@ App::get('/v1/database/collections/:collectionId/logs')
|
|||
$output[$i] = new Document([
|
||||
'event' => $log['event'],
|
||||
'userId' => $log['userId'],
|
||||
'userEmail' => $log['data']['userEmail'] ?? null,
|
||||
'userName' => $log['data']['userName'] ?? null,
|
||||
'mode' => $log['data']['mode'] ?? null,
|
||||
'ip' => $log['ip'],
|
||||
'time' => $log['time'],
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ use Utopia\Abuse\Adapters\TimeLimit;
|
|||
use Utopia\Storage\Device\Local;
|
||||
use Utopia\Storage\Storage;
|
||||
|
||||
App::init(function ($utopia, $request, $response, $project, $user, $register, $events, $audits, $usage, $deletes, $database, $dbForInternal) {
|
||||
App::init(function ($utopia, $request, $response, $project, $user, $events, $audits, $usage, $deletes, $database, $dbForInternal, $mode) {
|
||||
/** @var Utopia\App $utopia */
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
|
@ -89,6 +89,9 @@ App::init(function ($utopia, $request, $response, $project, $user, $register, $e
|
|||
$audits
|
||||
->setParam('projectId', $project->getId())
|
||||
->setParam('userId', $user->getId())
|
||||
->setParam('userEmail', $user->getAttribute('email'))
|
||||
->setParam('userName', $user->getAttribute('name'))
|
||||
->setParam('mode', $mode)
|
||||
->setParam('event', '')
|
||||
->setParam('resource', '')
|
||||
->setParam('userAgent', $request->getUserAgent(''))
|
||||
|
@ -113,7 +116,7 @@ App::init(function ($utopia, $request, $response, $project, $user, $register, $e
|
|||
$database
|
||||
->setParam('projectId', $project->getId())
|
||||
;
|
||||
}, ['utopia', 'request', 'response', 'project', 'user', 'register', 'events', 'audits', 'usage', 'deletes', 'database', 'dbForInternal'], 'api');
|
||||
}, ['utopia', 'request', 'response', 'project', 'user', 'events', 'audits', 'usage', 'deletes', 'database', 'dbForInternal', 'mode'], 'api');
|
||||
|
||||
App::init(function ($utopia, $request, $project) {
|
||||
/** @var Utopia\App $utopia */
|
||||
|
|
|
@ -214,8 +214,11 @@ App::get('/console/database/collection')
|
|||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\View $layout */
|
||||
|
||||
$logs = new View(__DIR__.'/../../views/console/comps/logs.phtml');
|
||||
$page = new View(__DIR__.'/../../views/console/database/collection.phtml');
|
||||
|
||||
$page->setParam('logs', $logs);
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - Database Collection')
|
||||
->setParam('body', $page)
|
||||
|
|
67
app/views/console/comps/logs.phtml
Normal file
67
app/views/console/comps/logs.phtml
Normal file
|
@ -0,0 +1,67 @@
|
|||
<div
|
||||
data-service="database.listCollectionLogs"
|
||||
data-param-collection-id="{{router.params.id}}"
|
||||
data-scope="sdk"
|
||||
data-event="load"
|
||||
data-name="project-collection-logs">
|
||||
|
||||
<div class="box margin-bottom">
|
||||
<table class="vertical small">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="120">Date</th>
|
||||
<th width="180">Initiator</th>
|
||||
<th>Event</th>
|
||||
<th width="90">Location</th>
|
||||
<th width="90">IP</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody data-ls-loop="project-collection-logs.logs" data-ls-as="log" class="text-size-small">
|
||||
<tr>
|
||||
<td data-title="Date: "><span class="text-fade" data-ls-bind="{{log.time|dateTime}}"></span></td>
|
||||
<td data-title="Initiator: ">
|
||||
<span data-ls-if="{{log.userName|escape}} !== '' && {{log.mode}} === ''"><i class="icon-user"></i> <a data-ls-attrs="href=/console/users/user?id={{log.userId}}&project={{router.params.project}}" data-ls-bind="{{log.userName}}"></a></span>
|
||||
<span data-ls-if="{{log.userName|escape}} === '' && {{log.userEmail}} !== '' && {{log.mode}} !== 'key'"><i class="icon-user"></i> Unknown</span>
|
||||
<span data-ls-if="{{log.userName|escape}} === '' && {{log.userEmail}} === '' && {{log.mode}} !== 'key'"><i class="icon-user"></i> Anonymous User</span>
|
||||
<span data-ls-if="{{log.mode}} === 'admin'"><i class="icon-user"></i> <span data-ls-bind="{{log.userName}} (Admin)"></span></span>
|
||||
<span data-ls-if="{{log.mode}} === 'key'"> <i class="icon-key"></i> API Key</span>
|
||||
</td>
|
||||
<td data-title="Event: "><span data-ls-bind="{{log.event}}"></span></td>
|
||||
<td data-title="Location: ">
|
||||
<img onerror="this.onerror=null;this.src='/images/unknown.svg'" data-ls-attrs="src={{env.API}}/avatars/flags/{{log.countryCode}}?width=80&height=80&project={{env.PROJECT}}" class="avatar xxs inline margin-end-small" />
|
||||
<span data-ls-bind="{{log.geo.countryName}}"></span>
|
||||
</td>
|
||||
<td data-title="IP: "><span data-ls-bind="{{log.ip}}"></span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pull-end text-align-center paging">
|
||||
<form
|
||||
data-service="database.listCollectionLogs"
|
||||
data-event="submit"
|
||||
data-param-collection-id="{{router.params.id}}"
|
||||
data-param-limit="<?php echo APP_PAGING_LIMIT; ?>"
|
||||
data-param-order-type="DESC"
|
||||
data-scope="sdk"
|
||||
data-name="project-collection-logs"
|
||||
data-success="state"
|
||||
data-success-param-state-keys="search,offset">
|
||||
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-sum="{{project-collection-logs.sum}}" class="margin-end-small round small" aria-label="Back"><i class="icon-left-open"></i></button>
|
||||
</form>
|
||||
|
||||
<form
|
||||
data-service="database.listCollectionLogs"
|
||||
data-event="submit"
|
||||
data-param-collection-id="{{router.params.id}}"
|
||||
data-param-limit="<?php echo APP_PAGING_LIMIT; ?>"
|
||||
data-param-order-type="DESC"
|
||||
data-scope="sdk"
|
||||
data-name="project-collection-logs"
|
||||
data-success="state"
|
||||
data-success-param-state-keys="search,offset">
|
||||
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-sum="{{project-collection-logs.sum}}" class="margin-start-small round small" aria-label="Next"><i class="icon-right-open"></i></button>
|
||||
</form>
|
||||
</div>
|
|
@ -1,3 +1,8 @@
|
|||
<?php
|
||||
|
||||
$logs = $this->getParam('logs', null);
|
||||
|
||||
?>
|
||||
<div
|
||||
data-service="database.getCollection"
|
||||
data-param-collection-id="{{router.params.id}}"
|
||||
|
@ -238,7 +243,7 @@
|
|||
<p class="margin-bottom-no">Add your first index to get started</p>
|
||||
</div>
|
||||
|
||||
<table class="vertical" data-ls-if="0 < {{project-collection.indexes.length}} || 0 < {{project-collection.indexesInQueue.length}}">
|
||||
<table class="vertical multi-line" data-ls-if="0 < {{project-collection.indexes.length}} || 0 < {{project-collection.indexesInQueue.length}}">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="120"></th>
|
||||
|
@ -265,7 +270,7 @@
|
|||
</td>
|
||||
|
||||
<td data-title="Attributes:">
|
||||
<span class="text-size-small" data-ls-bind="{{index|indexAttributes}}"></span>xxx1
|
||||
<span class="text-size-small" data-ls-bind="{{index|indexAttributes}}"></span>
|
||||
</td>
|
||||
|
||||
<td data-title="">
|
||||
|
@ -303,7 +308,7 @@
|
|||
|
||||
<hr data-ls-if="0 < {{project-collection.indexesInQueue.length}}" />
|
||||
|
||||
<table class="vertical" data-ls-if="0 < {{project-collection.indexesInQueue.length}}">
|
||||
<table class="vertical multi-line" data-ls-if="0 < {{project-collection.indexesInQueue.length}}">
|
||||
<tbody data-ls-loop="project-collection.indexesInQueue" data-ls-as="index">
|
||||
<tr>
|
||||
<td width="120" data-title="Status">
|
||||
|
@ -320,7 +325,7 @@
|
|||
</td>
|
||||
|
||||
<td width="180" data-title="Attributes:">
|
||||
<span class="text-size-small" data-ls-bind="{{index.attributes}}"></span>
|
||||
<span class="text-size-small" data-ls-bind="{{index|indexAttributes}}"></span>
|
||||
</td>
|
||||
|
||||
<td data-title="">
|
||||
|
@ -340,41 +345,7 @@
|
|||
<li data-state="/console/database/collection/activity?id={{router.params.id}}&project={{router.params.project}}">
|
||||
<h2>Activity <span class="badge" data-ls-bind="{{project-collection-logs.logs.length}}"></span></h2>
|
||||
|
||||
<div
|
||||
data-service="database.getCollectionLogs"
|
||||
data-param-collection-id="{{router.params.id}}"
|
||||
data-scope="sdk"
|
||||
data-event="load"
|
||||
data-name="project-collection-logs">
|
||||
|
||||
<div class="box">
|
||||
<table class="vertical small">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="120">Date</th>
|
||||
<th width="120">User</th>
|
||||
<th>Event</th>
|
||||
<th width="90">Location</th>
|
||||
<th width="90">IP</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody data-ls-loop="project-collection-logs.logs" data-ls-as="log">
|
||||
<tr>
|
||||
<td data-title="Date: "><span data-ls-bind="{{log.time|dateTime}}"></span></td>
|
||||
<td data-title="User: ">
|
||||
<span data-ls-bind="{{log.userId}}"></span>
|
||||
</td>
|
||||
<td data-title="Event: "><span data-ls-bind="{{log.event}}"></span></td>
|
||||
<td data-title="Location: ">
|
||||
<img onerror="this.onerror=null;this.src='/images/unknown.svg'" data-ls-attrs="src={{env.API}}/avatars/flags/{{log.countryCode}}?width=80&height=80&project={{env.PROJECT}}" class="avatar xxs inline margin-end-small" />
|
||||
<span data-ls-bind="{{log.geo.countryName}}"></span>
|
||||
</td>
|
||||
<td data-title="IP: "><span data-ls-bind="{{log.ip}}"></span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<?php echo $logs->render(); ?>
|
||||
</li>
|
||||
<li data-state="/console/database/collection/settings?id={{router.params.id}}&project={{router.params.project}}">
|
||||
<h2>Settings</h2>
|
||||
|
|
|
@ -21,6 +21,9 @@ class AuditsV1 extends Worker
|
|||
{
|
||||
$projectId = $this->args['projectId'];
|
||||
$userId = $this->args['userId'];
|
||||
$userName = $this->args['userName'];
|
||||
$userEmail = $this->args['userEmail'];
|
||||
$mode = $this->args['mode'];
|
||||
$event = $this->args['event'];
|
||||
$resource = $this->args['resource'];
|
||||
$userAgent = $this->args['userAgent'];
|
||||
|
@ -30,7 +33,12 @@ class AuditsV1 extends Worker
|
|||
$dbForInternal = $this->getInternalDB($projectId);
|
||||
$audit = new Audit($dbForInternal);
|
||||
|
||||
$audit->log($userId, $event, $resource, $userAgent, $ip, '', $data);
|
||||
$audit->log($userId, $event, $resource, $userAgent, $ip, '', [
|
||||
'userName' => $userName,
|
||||
'userEmail' => $userEmail,
|
||||
'mode' => $mode,
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function shutdown(): void
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.database.getCollectionLogs('[COLLECTION_ID]');
|
||||
let promise = sdk.database.listCollectionLogs('[COLLECTION_ID]');
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
2
public/dist/scripts/app-all.js
vendored
2
public/dist/scripts/app-all.js
vendored
|
@ -205,7 +205,7 @@ console.log(collectionId,indexId,type,attributes,orders);const uri=new URL(this.
|
|||
if(typeof indexId==='undefined'){throw new AppwriteException('Missing required parameter: "indexId"');}
|
||||
let path='/database/collections/{collectionId}/indexes/{indexId}'.replace('{collectionId}',collectionId).replace('{indexId}',indexId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),deleteIndex:(collectionId,indexId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
if(typeof indexId==='undefined'){throw new AppwriteException('Missing required parameter: "indexId"');}
|
||||
let path='/database/collections/{collectionId}/indexes/{indexId}'.replace('{collectionId}',collectionId).replace('{indexId}',indexId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),getCollectionLogs:(collectionId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
let path='/database/collections/{collectionId}/indexes/{indexId}'.replace('{collectionId}',collectionId).replace('{indexId}',indexId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),listCollectionLogs:(collectionId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
let path='/database/collections/{collectionId}/logs'.replace('{collectionId}',collectionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.functions={list:(search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/functions';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
if(typeof limit!=='undefined'){payload['limit']=limit;}
|
||||
if(typeof offset!=='undefined'){payload['offset']=offset;}
|
||||
|
|
2
public/dist/scripts/app-dep.js
vendored
2
public/dist/scripts/app-dep.js
vendored
|
@ -205,7 +205,7 @@ console.log(collectionId,indexId,type,attributes,orders);const uri=new URL(this.
|
|||
if(typeof indexId==='undefined'){throw new AppwriteException('Missing required parameter: "indexId"');}
|
||||
let path='/database/collections/{collectionId}/indexes/{indexId}'.replace('{collectionId}',collectionId).replace('{indexId}',indexId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),deleteIndex:(collectionId,indexId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
if(typeof indexId==='undefined'){throw new AppwriteException('Missing required parameter: "indexId"');}
|
||||
let path='/database/collections/{collectionId}/indexes/{indexId}'.replace('{collectionId}',collectionId).replace('{indexId}',indexId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),getCollectionLogs:(collectionId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
let path='/database/collections/{collectionId}/indexes/{indexId}'.replace('{collectionId}',collectionId).replace('{indexId}',indexId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),listCollectionLogs:(collectionId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
let path='/database/collections/{collectionId}/logs'.replace('{collectionId}',collectionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.functions={list:(search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/functions';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
if(typeof limit!=='undefined'){payload['limit']=limit;}
|
||||
if(typeof offset!=='undefined'){payload['offset']=offset;}
|
||||
|
|
2
public/dist/styles/default-ltr.css
vendored
2
public/dist/styles/default-ltr.css
vendored
File diff suppressed because one or more lines are too long
2
public/dist/styles/default-rtl.css
vendored
2
public/dist/styles/default-rtl.css
vendored
File diff suppressed because one or more lines are too long
|
@ -1732,7 +1732,7 @@
|
|||
* @throws {AppwriteException}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
getCollectionLogs: (collectionId) => __awaiter(this, void 0, void 0, function* () {
|
||||
listCollectionLogs: (collectionId) => __awaiter(this, void 0, void 0, function* () {
|
||||
if (typeof collectionId === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "collectionId"');
|
||||
}
|
||||
|
|
|
@ -662,7 +662,7 @@ input[type=checkbox], input[type=radio] {
|
|||
|
||||
.paging {
|
||||
color: var(--config-color-fade);
|
||||
padding: 5px 15px;
|
||||
padding: 0;
|
||||
font-size: 12px;
|
||||
|
||||
form {
|
||||
|
|
|
@ -7,11 +7,18 @@ table {
|
|||
position: relative;
|
||||
table-layout: fixed;
|
||||
|
||||
|
||||
&.y-scroll {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
&.multi-line {
|
||||
thead th, tbody td {
|
||||
line-height: inherit;
|
||||
text-overflow:inherit;
|
||||
white-space: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
thead {
|
||||
box-shadow: 0 0 2px rgba(0,0,0,.25);
|
||||
border-bottom: solid 1px var(--config-color-fade-super);
|
||||
|
|
|
@ -22,6 +22,24 @@ class Log extends Model
|
|||
'default' => '',
|
||||
'example' => '610fc2f985ee0',
|
||||
])
|
||||
->addRule('userEmail', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'User Email.',
|
||||
'default' => '',
|
||||
'example' => 'john@appwrite.io',
|
||||
])
|
||||
->addRule('userName', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'User Name.',
|
||||
'default' => '',
|
||||
'example' => 'John Doe',
|
||||
])
|
||||
->addRule('mode', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'API mode when event triggered.',
|
||||
'default' => '',
|
||||
'example' => 'admin',
|
||||
])
|
||||
->addRule('ip', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'IP session in use when the session was created.',
|
||||
|
|
Loading…
Reference in a new issue