Skip to content
Permalink
Browse files

start implementing locked items to prevent multiuser overrides

  • Loading branch information...
aheinze committed Mar 1, 2019
1 parent 342d412 commit 917ba5afdcb9e8504fa5fbedc0e4b76563a6c62e
@@ -51,4 +51,27 @@ public function revisionsCount() {
return 0;
}
public function isResourceLocked($resourceId) {
$meta = $this->app->helper('admin')->isResourceLocked($resourceId);
if ($meta) {
return array_merge($meta, ['locked' => true]);
}
return ['locked' => false];
}
public function lockResourceId($resourceId) {
$user = null;
$meta = $this->app->helper('admin')->lockResourceId($resourceId, $user);
return $meta;
}
public function unlockResourceId($resourceId) {
$this->app->helper('admin')->unlockResourceId($resourceId);
return ['success' => true];
}
}
@@ -158,6 +158,45 @@ public function setUserOption($key, $value) {
return $this->app->module('cockpit')->updateUserOption($key, $value);
}
public function isResourceLocked($resourceId, $ttl = 300) {
$key = "locked:{$resourceId}";
$meta = $this->app->memory->get($key, false);
if ($meta && ($meta['time'] + $ttl) < time()) {
$this->app->memory->del($key);
$meta = false;
}
if ($meta) {
return $meta;
}
return false;
}
public function lockResourceId($resourceId, $user = null) {
$key = "locked:{$resourceId}";
$user = $user ?? $this->app->module('cockpit')->getUser();
$meta = [
'user' => $user,
'time' => time()
];
$this->app->memory->set($key, $meta);
return true;
}
public function unlockResourceId($resourceId) {
$key = "locked:{$resourceId}";
$this->app->memory->del($key);
return true;
}
public function denyRequest() {
if ($this->app->module('cockpit')->getUser()) {
@@ -208,6 +208,12 @@ public function entry($collection, $id = null) {
if (!$entry) {
return false;
}
$meta = $this->app->helper('admin')->isResourceLocked($id);
if ($meta && $meta['user']['_id'] != $this->module('cockpit')->getUser('_id')) {
return $this->render('collections:views/locked.php', compact('collection', 'entry', 'meta'));
}
}
$context = _check_collection_rule($collection, 'read', ['options' => ['filter'=>[]]]);
@@ -224,6 +230,8 @@ public function entry($collection, $id = null) {
$view = $override;
}
$this->app->helper('admin')->lockResourceId($id);
return $this->render($view, compact('collection', 'entry', 'excludeFields'));
}
@@ -266,6 +274,8 @@ public function save_entry($collection) {
$entry = $this->module('collections')->save($collection['name'], $entry, ['revision' => $revision]);
$this->app->helper('admin')->lockResourceId($entry['_id']);
return $entry;
}
@@ -0,0 +1,51 @@
@if(isset($collection['color']) && $collection['color'])
<style>
.app-header { border-top: 8px {{ $collection['color'] }} solid; }
</style>
@endif
<div>
<ul class="uk-breadcrumb">
<li><a href="@route('/collections')">@lang('Collections')</a></li>
<li data-uk-dropdown="mode:'hover', delay:300">
<a href="@route('/collections/entries/'.$collection['name'])"><i class="uk-icon-bars"></i> {{ htmlspecialchars(@$collection['label'] ? $collection['label']:$collection['name']) }}</a>
@if($app->module('collections')->hasaccess($collection['name'], 'collection_edit'))
<div class="uk-dropdown">
<ul class="uk-nav uk-nav-dropdown">
<li class="uk-nav-header">@lang('Actions')</li>
<li><a href="@route('/collections/collection/'.$collection['name'])">@lang('Edit')</a></li>
<li class="uk-nav-divider"></li>
<li class="uk-text-truncate"><a href="@route('/collections/export/'.$collection['name'])" download="{{ $collection['name'] }}.collection.json">@lang('Export entries')</a></li>
<li class="uk-text-truncate"><a href="@route('/collections/import/collection/'.$collection['name'])">@lang('Import entries')</a></li>
</ul>
</div>
@endif
</li>
</ul>
</div>
<div class="uk-width-medium-1-2 uk-viewport-height-1-2 uk-container-center uk-flex uk-flex-center uk-flex-middle" riot-view>
<div class="uk-animation-fade uk-width-1-1">
<p class="uk-h2">
@lang('This item is already being edited.')
</p>
<div class="uk-panel-box uk-panel-card uk-margin-top">
<strong class="uk-text-uppercase uk-text-small">@lang('Current editor')</strong>
<div class="uk-margin-top uk-flex">
<div>
<cp-gravatar size="30" alt="<?=($meta['user']['name'] ? $meta['user']['name'] : $meta['user']['user'])?>"></cp-gravatar>
</div>
<div class="uk-margin-left">
<span><?=($meta['user']['name'] ? $meta['user']['name'] : $meta['user']['user'])?></span><br />
<span class="uk-text-muted"><?=($meta['user']['email'])?></span>
</div>
</div>
</div>
</div>
</div>
@@ -61,6 +61,8 @@ public function singleton($name = null) {
if (!$singleton) {
return false;
}
}
// acl groups
@@ -95,8 +97,17 @@ public function form($name = null) {
'description' => ''
], $singleton);
$lockId = "singleton_{$singleton['name']}";
$meta = $this->app->helper('admin')->isResourceLocked($lockId);
if ($meta && $meta['user']['_id'] != $this->module('cockpit')->getUser('_id')) {
return $this->render('singletons:views/locked.php', compact('singleton', 'meta'));
}
$data = $this->module('singletons')->getData($name);
$this->app->helper('admin')->lockResourceId($lockId);
return $this->render('singletons:views/form.php', compact('singleton', 'data'));
}
@@ -145,6 +156,8 @@ public function update_data($singleton) {
$this->module('singletons')->saveData($singleton['name'], $data, ['revision' => $revision]);
$this->app->helper('admin')->lockResourceId("singleton_{$singleton['name']}");
return ['data' => $data];
}
@@ -0,0 +1,50 @@

@if($singleton['color'])
<style>
.app-header { border-top: 8px {{ $singleton['color'] }} solid; }
</style>
@endif
<div>
<ul class="uk-breadcrumb">
<li><a href="@route('/singletons')">@lang('Singletons')</a></li>
<li class="uk-active" data-uk-dropdown>
<a><i class="uk-icon-bars"></i> {{ htmlspecialchars(@$singleton['label'] ? $singleton['label']:$singleton['name']) }}</a>
@if($app->module('singletons')->hasaccess($singleton['name'], 'edit'))
<div class="uk-dropdown">
<ul class="uk-nav uk-nav-dropdown">
<li class="uk-nav-header">@lang('Actions')</li>
<li><a href="@route('/singletons/singleton/'.$singleton['name'])">@lang('Edit')</a></li>
</ul>
</div>
@endif
</li>
</ul>
</div>
<div class="uk-width-medium-1-2 uk-viewport-height-1-2 uk-container-center uk-flex uk-flex-center uk-flex-middle" riot-view>
<div class="uk-animation-fade uk-width-1-1">
<p class="uk-h2">
@lang('This singleton is already being edited.')
</p>
<div class="uk-panel-box uk-panel-card uk-margin-top">
<strong class="uk-text-uppercase uk-text-small">@lang('Current editor')</strong>
<div class="uk-margin-top uk-flex">
<div>
<cp-gravatar size="30" alt="<?=($meta['user']['name'] ? $meta['user']['name'] : $meta['user']['user'])?>"></cp-gravatar>
</div>
<div class="uk-margin-left">
<span><?=($meta['user']['name'] ? $meta['user']['name'] : $meta['user']['user'])?></span><br />
<span class="uk-text-muted"><?=($meta['user']['email'])?></span>
</div>
</div>
</div>
</div>
</div>

0 comments on commit 917ba5a

Please sign in to comment.
You can’t perform that action at this time.