1
0
Fork 0
mirror of synced 2024-06-01 10:29:48 +12:00

Updated logs screen

This commit is contained in:
Eldad Fux 2021-08-14 13:13:24 +03:00
parent 87a9ce2941
commit 17bbdc3a52
16 changed files with 133 additions and 53 deletions

File diff suppressed because one or more lines are too long

View file

@ -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'],

View file

@ -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 */

View file

@ -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)

View 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>&nbsp; <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>&nbsp; Unknown</span>
<span data-ls-if="{{log.userName|escape}} === '' && {{log.userEmail}} === '' && {{log.mode}} !== 'key'"><i class="icon-user"></i>&nbsp; Anonymous User</span>
<span data-ls-if="{{log.mode}} === 'admin'"><i class="icon-user"></i>&nbsp; <span data-ls-bind="{{log.userName}} (Admin)"></span></span>
<span data-ls-if="{{log.mode}} === 'key'"> <i class="icon-key"></i>&nbsp; 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>

View file

@ -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>

View file

@ -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

View file

@ -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

View file

@ -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;}

View file

@ -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;}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -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"');
}

View file

@ -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 {

View file

@ -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);

View file

@ -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.',