mirror of
https://github.com/cydrobolt/polr.git
synced 2024-09-19 23:21:47 +02:00
Merge pull request #335 from cydrobolt/feature/edit_long_link
Allow editing of long links and refactor modals
This commit is contained in:
commit
def7e36bc1
@ -14,75 +14,126 @@ class AdminPaginationController extends Controller {
|
|||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Cell rendering functions */
|
||||||
|
|
||||||
|
public function renderLongUrlCell($link) {
|
||||||
|
return '<a target="_blank" title="' . e($link->long_url) . '" href="'. $link->long_url .'">' . str_limit($link->long_url, 50) . '</a>
|
||||||
|
<a class="btn btn-primary btn-xs edit-long-link-btn" ng-click="editLongLink(\'' . $link->short_url . '\', \'' . $link->long_url . '\')"><i class="fa fa-edit edit-link-icon"></i></a>';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderClicksCell($link) {
|
||||||
|
if (env('SETTING_ADV_ANALYTICS')) {
|
||||||
|
return $link->clicks . ' <a target="_blank" class="stats-icon" href="/admin/stats/' . e($link->short_url) . '">
|
||||||
|
<i class="fa fa-area-chart" aria-hidden="true"></i>
|
||||||
|
</a>';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return $link->clicks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderDeleteUserCell($user) {
|
||||||
|
// Add "Delete" action button
|
||||||
|
$btn_class = '';
|
||||||
|
if (session('username') === $user->username) {
|
||||||
|
$btn_class = 'disabled';
|
||||||
|
}
|
||||||
|
return '<a ng-click="deleteUser($event, \''. $user->id .'\')" class="btn btn-sm btn-danger ' . $btn_class . '">
|
||||||
|
Delete
|
||||||
|
</a>';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderDeleteLinkCell($link) {
|
||||||
|
// Add "Delete" action button
|
||||||
|
return '<a ng-click="deleteLink($event, \'' . e($link->short_url) . '\')"
|
||||||
|
class="btn btn-sm btn-warning delete-link">
|
||||||
|
Delete
|
||||||
|
</a>';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderAdminApiActionCell($user) {
|
||||||
|
// Add "API Info" action button
|
||||||
|
return '<a class="activate-api-modal btn btn-sm btn-info"
|
||||||
|
ng-click="openAPIModal($event, \'' . e($user->username) . '\', \'' . $user->api_key . '\', \'' . $user->api_active . '\', \'' . e($user->api_quota) . '\', \'' . $user->id . '\')">
|
||||||
|
API info
|
||||||
|
</a>';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderToggleUserActiveCell($user) {
|
||||||
|
// Add user account active state toggle buttons
|
||||||
|
$btn_class = '';
|
||||||
|
if (session('username') === $user->username) {
|
||||||
|
$btn_class = ' disabled';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user->active) {
|
||||||
|
$active_text = 'Active';
|
||||||
|
$btn_color_class = ' btn-success';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$active_text = 'Inactive';
|
||||||
|
$btn_color_class = ' btn-danger';
|
||||||
|
}
|
||||||
|
|
||||||
|
return '<a class="btn btn-sm status-display' . $btn_color_class . $btn_class . '" ng-click="toggleUserActiveStatus($event, ' . $user->id . ')">' . $active_text . '</a>';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderChangeUserRoleCell($user) {
|
||||||
|
// Add "change role" select box
|
||||||
|
// <select> field does not use Angular bindings
|
||||||
|
// because of an issue affecting fields with duplicate names.
|
||||||
|
|
||||||
|
$select_role = '<select ng-init="changeUserRole.u' . $user->id . ' = \'' . e($user->role) . '\'"
|
||||||
|
ng-model="changeUserRole.u' . $user->id . '" ng-change="changeUserRole(changeUserRole.u' . $user->id . ', '.$user->id.')"
|
||||||
|
class="form-control"';
|
||||||
|
|
||||||
|
if (session('username') === $user->username) {
|
||||||
|
// Do not allow user to change own role
|
||||||
|
$select_role .= ' disabled';
|
||||||
|
}
|
||||||
|
$select_role .= '>';
|
||||||
|
|
||||||
|
foreach (UserHelper::$USER_ROLES as $role_text => $role_val) {
|
||||||
|
// Iterate over each available role and output option
|
||||||
|
$select_role .= '<option value="' . e($role_val) . '"';
|
||||||
|
|
||||||
|
if ($user->role === $role_val) {
|
||||||
|
$select_role .= ' selected';
|
||||||
|
}
|
||||||
|
|
||||||
|
$select_role .= '>' . e($role_text) . '</option>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$select_role .= '</select>';
|
||||||
|
return $select_role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderToggleLinkActiveCell($link) {
|
||||||
|
// Add "Disable/Enable" action buttons
|
||||||
|
$btn_class = 'btn-danger';
|
||||||
|
$btn_text = 'Disable';
|
||||||
|
|
||||||
|
if ($link->is_disabled) {
|
||||||
|
$btn_class = 'btn-success';
|
||||||
|
$btn_text = 'Enable';
|
||||||
|
}
|
||||||
|
|
||||||
|
return '<a ng-click="toggleLink($event, \'' . e($link->short_url) . '\')" class="btn btn-sm ' . $btn_class . '">
|
||||||
|
' . $btn_text . '
|
||||||
|
</a>';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DataTables bindings */
|
||||||
|
|
||||||
public function paginateAdminUsers(Request $request) {
|
public function paginateAdminUsers(Request $request) {
|
||||||
self::ensureAdmin();
|
self::ensureAdmin();
|
||||||
|
|
||||||
$admin_users = User::select(['username', 'email', 'created_at', 'active', 'api_key', 'api_active', 'api_quota', 'role', 'id']);
|
$admin_users = User::select(['username', 'email', 'created_at', 'active', 'api_key', 'api_active', 'api_quota', 'role', 'id']);
|
||||||
return Datatables::of($admin_users)
|
return Datatables::of($admin_users)
|
||||||
->addColumn('api_action', function ($user) {
|
->addColumn('api_action', [$this, 'renderAdminApiActionCell'])
|
||||||
// Add "API Info" action button
|
->addColumn('toggle_active', [$this, 'renderToggleUserActiveCell'])
|
||||||
return '<a class="activate-api-modal btn btn-sm btn-info"
|
->addColumn('change_role', [$this, 'renderChangeUserRoleCell'])
|
||||||
ng-click="openAPIModal($event, \'' . e($user->username) . '\', \'' . $user->api_key . '\', \'' . $user->api_active . '\', \'' . e($user->api_quota) . '\', \'' . $user->id . '\')">
|
->addColumn('delete', [$this, 'renderDeleteUserCell'])
|
||||||
API info
|
|
||||||
</a>';
|
|
||||||
})
|
|
||||||
->addColumn('toggle_active', function ($user) {
|
|
||||||
// Add user account active state toggle buttons
|
|
||||||
$btn_class = '';
|
|
||||||
if (session('username') == $user->username) {
|
|
||||||
$btn_class = ' disabled';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($user->active) {
|
|
||||||
$active_text = 'Active';
|
|
||||||
$btn_color_class = ' btn-success';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$active_text = 'Inactive';
|
|
||||||
$btn_color_class = ' btn-danger';
|
|
||||||
}
|
|
||||||
|
|
||||||
return '<a class="btn btn-sm status-display' . $btn_color_class . $btn_class . '" ng-click="toggleUserActiveStatus($event, ' . $user->id . ')">' . $active_text . '</a>';
|
|
||||||
})
|
|
||||||
->addColumn('change_role', function ($user) {
|
|
||||||
// Add "change role" select box
|
|
||||||
// FIXME <select> field does not use Angular bindings
|
|
||||||
// because of an issue affecting fields with duplicate names.
|
|
||||||
|
|
||||||
$select_role = '<select ng-init="changeUserRole.u' . $user->id . ' = \'' . e($user->role) . '\'"
|
|
||||||
ng-model="changeUserRole.u' . $user->id . '" ng-change="changeUserRole(changeUserRole.u' . $user->id . ', '.$user->id.')"
|
|
||||||
class="form-control"';
|
|
||||||
|
|
||||||
if (session('username') == $user->username) {
|
|
||||||
// Do not allow user to change own role
|
|
||||||
$select_role .= ' disabled';
|
|
||||||
}
|
|
||||||
$select_role .= '>';
|
|
||||||
|
|
||||||
foreach (UserHelper::$USER_ROLES as $role_text => $role_val) {
|
|
||||||
// Iterate over each available role and output option
|
|
||||||
$select_role .= '<option value="' . e($role_val) . '"';
|
|
||||||
|
|
||||||
if ($user->role == $role_val) {
|
|
||||||
$select_role .= ' selected';
|
|
||||||
}
|
|
||||||
|
|
||||||
$select_role .= '>' . e($role_text) . '</option>';
|
|
||||||
}
|
|
||||||
|
|
||||||
$select_role .= '</select>';
|
|
||||||
return $select_role;
|
|
||||||
})
|
|
||||||
->addColumn('delete', function ($user) {
|
|
||||||
// Add "Delete" action button
|
|
||||||
$btn_class = '';
|
|
||||||
if (session('username') == $user->username) {
|
|
||||||
$btn_class = 'disabled';
|
|
||||||
}
|
|
||||||
return '<a ng-click="deleteUser($event, \''. $user->id .'\')" class="btn btn-sm btn-danger ' . $btn_class . '">
|
|
||||||
Delete
|
|
||||||
</a>';
|
|
||||||
})
|
|
||||||
->escapeColumns(['username', 'email'])
|
->escapeColumns(['username', 'email'])
|
||||||
->make(true);
|
->make(true);
|
||||||
}
|
}
|
||||||
@ -92,38 +143,10 @@ class AdminPaginationController extends Controller {
|
|||||||
|
|
||||||
$admin_links = Link::select(['short_url', 'long_url', 'clicks', 'created_at', 'creator', 'is_disabled']);
|
$admin_links = Link::select(['short_url', 'long_url', 'clicks', 'created_at', 'creator', 'is_disabled']);
|
||||||
return Datatables::of($admin_links)
|
return Datatables::of($admin_links)
|
||||||
->addColumn('disable', function ($link) {
|
->addColumn('disable', [$this, 'renderToggleLinkActiveCell'])
|
||||||
// Add "Disable/Enable" action buttons
|
->addColumn('delete', [$this, 'renderDeleteLinkCell'])
|
||||||
$btn_class = 'btn-danger';
|
->editColumn('clicks', [$this, 'renderClicksCell'])
|
||||||
$btn_text = 'Disable';
|
->editColumn('long_url', [$this, 'renderLongUrlCell'])
|
||||||
|
|
||||||
if ($link->is_disabled) {
|
|
||||||
$btn_class = 'btn-success';
|
|
||||||
$btn_text = 'Enable';
|
|
||||||
}
|
|
||||||
|
|
||||||
return '<a ng-click="toggleLink($event, \'' . e($link->short_url) . '\')" class="btn btn-sm ' . $btn_class . '">
|
|
||||||
' . $btn_text . '
|
|
||||||
</a>';
|
|
||||||
})
|
|
||||||
->addColumn('delete', function ($link) {
|
|
||||||
// Add "Delete" action button
|
|
||||||
return '<a ng-click="deleteLink($event, \'' . e($link->short_url) . '\')"
|
|
||||||
class="btn btn-sm btn-warning delete-link">
|
|
||||||
Delete
|
|
||||||
</a>';
|
|
||||||
})
|
|
||||||
->editColumn('clicks', function ($link) {
|
|
||||||
if (env('SETTING_ADV_ANALYTICS')) {
|
|
||||||
return $link->clicks . ' <a target="_blank" class="stats-icon" href="/admin/stats/' . e($link->short_url) . '">
|
|
||||||
<i class="fa fa-area-chart" aria-hidden="true"></i>
|
|
||||||
</a>';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return $link->clicks;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
->editColumn('long_url', '<a target="_blank" title="{{ $long_url }}" href="{{ $long_url }}">{{ str_limit($long_url, 50) }}</a>')
|
|
||||||
->escapeColumns(['short_url', 'creator'])
|
->escapeColumns(['short_url', 'creator'])
|
||||||
->make(true);
|
->make(true);
|
||||||
}
|
}
|
||||||
@ -133,20 +156,11 @@ class AdminPaginationController extends Controller {
|
|||||||
|
|
||||||
$username = session('username');
|
$username = session('username');
|
||||||
$user_links = Link::where('creator', $username)
|
$user_links = Link::where('creator', $username)
|
||||||
->select(['short_url', 'long_url', 'clicks', 'created_at']);
|
->select(['id', 'short_url', 'long_url', 'clicks', 'created_at']);
|
||||||
|
|
||||||
return Datatables::of($user_links)
|
return Datatables::of($user_links)
|
||||||
->editColumn('clicks', function ($link) {
|
->editColumn('clicks', [$this, 'renderClicksCell'])
|
||||||
if (env('SETTING_ADV_ANALYTICS')) {
|
->editColumn('long_url', [$this, 'renderLongUrlCell'])
|
||||||
return $link->clicks . ' <a target="_blank" class="stats-icon" href="/admin/stats/' . e($link->short_url) . '">
|
|
||||||
<i class="fa fa-area-chart" aria-hidden="true"></i>
|
|
||||||
</a>';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return $link->clicks;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
->editColumn('long_url', '<a target="_blank" title="{{ $long_url }}" href="{{ $long_url }}">{{ str_limit($long_url, 50) }}</a>')
|
|
||||||
->escapeColumns(['short_url'])
|
->escapeColumns(['short_url'])
|
||||||
->make(true);
|
->make(true);
|
||||||
}
|
}
|
||||||
|
@ -225,4 +225,32 @@ class AjaxController extends Controller {
|
|||||||
|
|
||||||
return ($new_status ? "Enable" : "Disable");
|
return ($new_status ? "Enable" : "Disable");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function editLinkLongUrl(Request $request) {
|
||||||
|
/**
|
||||||
|
* If user is an admin, allow the user to edit the value of any link's long URL.
|
||||||
|
* Otherwise, only allow the user to edit their own links.
|
||||||
|
*/
|
||||||
|
|
||||||
|
$link_ending = $request->input('link_ending');
|
||||||
|
$link = LinkHelper::linkExists($link_ending);
|
||||||
|
|
||||||
|
$new_long_url = $request->input('new_long_url');
|
||||||
|
|
||||||
|
$this->validate($request, [
|
||||||
|
'new_long_url' => 'required|url',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!$link) {
|
||||||
|
abort(404, 'Link not found.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($link->creator !== session('username')) {
|
||||||
|
self::ensureAdmin();
|
||||||
|
}
|
||||||
|
|
||||||
|
$link->long_url = $new_long_url;
|
||||||
|
$link->save();
|
||||||
|
return "OK";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@ $app->group(['prefix' => '/api/v2', 'namespace' => 'App\Http\Controllers'], func
|
|||||||
$app->post('admin/delete_user', ['as' => 'api_delete_user', 'uses' => 'AjaxController@deleteUser']);
|
$app->post('admin/delete_user', ['as' => 'api_delete_user', 'uses' => 'AjaxController@deleteUser']);
|
||||||
$app->post('admin/toggle_link', ['as' => 'api_toggle_link', 'uses' => 'AjaxController@toggleLink']);
|
$app->post('admin/toggle_link', ['as' => 'api_toggle_link', 'uses' => 'AjaxController@toggleLink']);
|
||||||
$app->post('admin/delete_link', ['as' => 'api_delete_link', 'uses' => 'AjaxController@deleteLink']);
|
$app->post('admin/delete_link', ['as' => 'api_delete_link', 'uses' => 'AjaxController@deleteLink']);
|
||||||
|
$app->post('admin/edit_link_long_url', ['as' => 'api_edit_link_long_url', 'uses' => 'AjaxController@editLinkLongUrl']);
|
||||||
|
|
||||||
$app->get('admin/get_admin_users', ['as' => 'api_get_admin_users', 'uses' => 'AdminPaginationController@paginateAdminUsers']);
|
$app->get('admin/get_admin_users', ['as' => 'api_get_admin_users', 'uses' => 'AdminPaginationController@paginateAdminUsers']);
|
||||||
$app->get('admin/get_admin_links', ['as' => 'api_get_admin_links', 'uses' => 'AdminPaginationController@paginateAdminLinks']);
|
$app->get('admin/get_admin_links', ['as' => 'api_get_admin_links', 'uses' => 'AdminPaginationController@paginateAdminLinks']);
|
||||||
|
@ -21,6 +21,7 @@ you may be interested in looking at a [legacy 1.x release](https://github.com/cy
|
|||||||
- Mbstring PHP Extension
|
- Mbstring PHP Extension
|
||||||
- Tokenizer PHP Extension
|
- Tokenizer PHP Extension
|
||||||
- JSON PHP Extension
|
- JSON PHP Extension
|
||||||
|
- PHP curl extension
|
||||||
|
|
||||||
## Downloading the source code
|
## Downloading the source code
|
||||||
|
|
||||||
@ -57,6 +58,14 @@ curl -sS https://getcomposer.org/installer | php
|
|||||||
php composer.phar install --no-dev -o
|
php composer.phar install --no-dev -o
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If composer fails to install the proper dependencies due to your PHP version, delete `composer.lock`
|
||||||
|
and try installing the dependencies again.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rm composer.lock
|
||||||
|
php composer.phar install --no-dev -o
|
||||||
|
```
|
||||||
|
|
||||||
## Running Polr on...
|
## Running Polr on...
|
||||||
|
|
||||||
### Apache
|
### Apache
|
||||||
|
@ -54,3 +54,7 @@ input.api-quota {
|
|||||||
a.new-user-add {
|
a.new-user-add {
|
||||||
margin-left: 0.5em
|
margin-left: 0.5em
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.edit-long-link-btn {
|
||||||
|
opacity: 0.45;
|
||||||
|
}
|
||||||
|
18
public/directives/editLongLinkModal.html
Normal file
18
public/directives/editLongLinkModal.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<div class="modal fade" id="edit-long-link-{{ linkEnding }}" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
<h4 class="modal-title">Long URL</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<input type="url" value="{{ oldLongLink }}" placeholder="Long URL..." class="form-control" />
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal" ng-click="saveChanges()">Save Changes</button>
|
||||||
|
</div>
|
||||||
|
</div> <!-- /.modal-content -->
|
||||||
|
</div> <!-- /.modal-dialog -->
|
||||||
|
</div> <!-- /.modal -->
|
31
public/directives/editUserApiInfoModal.html
Normal file
31
public/directives/editUserApiInfoModal.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<div class="modal fade" id="edit-user-api-info-{{ userId }}" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
<h4 class="modal-title">Edit User API Settings</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>
|
||||||
|
<span>API Active</span>:
|
||||||
|
|
||||||
|
<code class='status-display' ng-bind="apiActive"></code>
|
||||||
|
|
||||||
|
<a ng-click="toggleAPIStatus()" class='btn btn-xs btn-success'>toggle</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<span>API Key: </span><code class='status-display' ng-bind="apiKey">{{api_key}}</code>
|
||||||
|
<a ng-click="parentGenerateNewAPIKey($event)" class='btn btn-xs btn-danger'>reset</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<span>API Quota (req/min, -1 for unlimited):</span> <input type='number' class='form-control api-quota' ng-model="apiQuota">
|
||||||
|
<a ng-click="updateAPIQuota()" class='btn btn-xs btn-warning'>change</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div> <!-- /.modal-content -->
|
||||||
|
</div> <!-- /.modal-dialog -->
|
||||||
|
</div> <!-- /.modal -->
|
@ -1,8 +1,107 @@
|
|||||||
polr.controller('AdminCtrl', function($scope, $compile) {
|
polr.directive('editLongLinkModal', function () {
|
||||||
|
return {
|
||||||
|
scope: {
|
||||||
|
oldLongLink: '=',
|
||||||
|
linkEnding: '=',
|
||||||
|
cleanModals: '='
|
||||||
|
},
|
||||||
|
templateUrl: '/directives/editLongLinkModal.html',
|
||||||
|
transclude: true,
|
||||||
|
controller: function ($scope, $element, $timeout) {
|
||||||
|
$scope.init = function () {
|
||||||
|
// Destroy directive and clean modal on close
|
||||||
|
$element.find('.modal').on("hidden.bs.modal", function () {
|
||||||
|
$scope.$destroy();
|
||||||
|
$scope.cleanModals('editLongLink');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.saveChanges = function () {
|
||||||
|
// Save long URL changes
|
||||||
|
apiCall('admin/edit_link_long_url', {
|
||||||
|
'link_ending': $scope.linkEnding,
|
||||||
|
'new_long_url': $element.find('input').val()
|
||||||
|
}, function(data) {
|
||||||
|
toastr.success('The link was updated.', 'Success')
|
||||||
|
}, function(err) {
|
||||||
|
toastr.error('The new URL format is not valid.', 'Error');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.init();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
polr.directive('editUserApiInfoModal', function () {
|
||||||
|
return {
|
||||||
|
scope: {
|
||||||
|
userId: '=',
|
||||||
|
apiActive: '=',
|
||||||
|
apiKey: '=',
|
||||||
|
apiQuota: '=',
|
||||||
|
generateNewApiKey: '=',
|
||||||
|
cleanModals: '='
|
||||||
|
},
|
||||||
|
templateUrl: '/directives/editUserApiInfoModal.html',
|
||||||
|
transclude: true,
|
||||||
|
controller: function ($scope, $element, $timeout) {
|
||||||
|
$scope.init = function () {
|
||||||
|
// Destroy directive and clean modal on close
|
||||||
|
$element.find('.modal').on("hidden.bs.modal", function () {
|
||||||
|
$scope.$destroy();
|
||||||
|
$scope.cleanModals('editUserApiInfo');
|
||||||
|
});
|
||||||
|
|
||||||
|
$scope.apiActive = res_value_to_text($scope.apiActive);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle API access status
|
||||||
|
$scope.toggleAPIStatus = function() {
|
||||||
|
apiCall('admin/toggle_api_active', {
|
||||||
|
'user_id': $scope.userId,
|
||||||
|
}, function(new_status) {
|
||||||
|
$scope.apiActive = res_value_to_text(new_status);
|
||||||
|
$scope.$digest();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate new API key for user_id
|
||||||
|
$scope.parentGenerateNewAPIKey = function($event) {
|
||||||
|
$scope.generateNewApiKey($event, $scope.userId, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update user API quotas
|
||||||
|
$scope.updateAPIQuota = function() {
|
||||||
|
apiCall('admin/edit_api_quota', {
|
||||||
|
'user_id': $scope.userId,
|
||||||
|
'new_quota': parseInt($scope.apiQuota)
|
||||||
|
}, function(next_action) {
|
||||||
|
toastr.success("Quota successfully changed.", "Success");
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.init();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
polr.controller('AdminCtrl', function($scope, $compile, $timeout) {
|
||||||
|
/* Initialize $scope variables */
|
||||||
$scope.state = {
|
$scope.state = {
|
||||||
showNewUserWell: false
|
showNewUserWell: false
|
||||||
};
|
};
|
||||||
$scope.datatables = {};
|
$scope.datatables = {};
|
||||||
|
$scope.modals = {
|
||||||
|
editLongLink: [],
|
||||||
|
editUserApiInfo: []
|
||||||
|
};
|
||||||
|
$scope.newUserParams = {
|
||||||
|
username: '',
|
||||||
|
userPassword: '',
|
||||||
|
userEmail: '',
|
||||||
|
userRole: ''
|
||||||
|
};
|
||||||
|
|
||||||
$scope.syncHash = function() {
|
$scope.syncHash = function() {
|
||||||
var url = document.location.toString();
|
var url = document.location.toString();
|
||||||
@ -11,8 +110,16 @@ polr.controller('AdminCtrl', function($scope, $compile) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.cleanModals = function(modalType) {
|
||||||
|
$timeout(function () {
|
||||||
|
$scope.modals[modalType].shift();
|
||||||
|
});
|
||||||
|
|
||||||
|
$scope.reloadLinkTables();
|
||||||
|
};
|
||||||
|
|
||||||
// Initialise Datatables elements
|
// Initialise Datatables elements
|
||||||
$scope.initTables = function () {
|
$scope.initTables = function() {
|
||||||
var datatables_config = {
|
var datatables_config = {
|
||||||
'autoWidth': false,
|
'autoWidth': false,
|
||||||
'processing': true,
|
'processing': true,
|
||||||
@ -70,27 +177,18 @@ polr.controller('AdminCtrl', function($scope, $compile) {
|
|||||||
}, datatables_config));
|
}, datatables_config));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Append modals to Angular root
|
$scope.reloadLinkTables = function () {
|
||||||
$scope.appendModal = function(html, id) {
|
// Reload DataTables for affected tables
|
||||||
id = esc_selector(id);
|
// without resetting page
|
||||||
|
if ('admin_links_table' in $scope.datatables) {
|
||||||
|
$scope.datatables['admin_links_table'].ajax.reload(null, false);
|
||||||
|
}
|
||||||
|
|
||||||
$(".ng-root").append(html);
|
$scope.datatables['user_links_table'].ajax.reload(null, false);
|
||||||
var modal_ele = $("#" + id);
|
|
||||||
|
|
||||||
modal_ele.append(html);
|
|
||||||
modal_ele.modal();
|
|
||||||
$compile(modal_ele)($scope);
|
|
||||||
|
|
||||||
$("body").delegate("#" + id, "hidden.bs.modal", function() {
|
|
||||||
modal_ele.remove();
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Hide table rows
|
$scope.reloadUserTables = function () {
|
||||||
$scope.hideRow = function(el, msg) {
|
$scope.datatables['admin_users_table'].ajax.reload(null, false);
|
||||||
var row = el.parent().parent();
|
|
||||||
toastr.success(msg, "Success");
|
|
||||||
row.fadeOut('slow');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -113,68 +211,6 @@ polr.controller('AdminCtrl', function($scope, $compile) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.checkNewUserFields = function() {
|
|
||||||
var response = true;
|
|
||||||
|
|
||||||
$('.new-user-fields input').each(function () {
|
|
||||||
if ($(this).val().trim() == '' || response == false) {
|
|
||||||
response = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.addNewUser = function($event) {
|
|
||||||
// Create a new user
|
|
||||||
// FIXME could use Angular models in the future
|
|
||||||
// instead of relying on .val()
|
|
||||||
|
|
||||||
var username = $('#new-username').val();
|
|
||||||
var user_password = $('#new-user-password').val();
|
|
||||||
var user_email = $('#new-user-email').val();
|
|
||||||
var user_role = $('#new-user-role').val();
|
|
||||||
|
|
||||||
if (!$scope.checkNewUserFields()) {
|
|
||||||
toastr.error("Fields cannot be empty.", "Error");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
apiCall('admin/add_new_user', {
|
|
||||||
'username': username,
|
|
||||||
'user_password': user_password,
|
|
||||||
'user_email': user_email,
|
|
||||||
'user_role': user_role,
|
|
||||||
}, function(result) {
|
|
||||||
toastr.success("User " + username + " successfully created.", "Success");
|
|
||||||
$('#new-user-form').clearForm();
|
|
||||||
$scope.datatables['admin_users_table'].ajax.reload();
|
|
||||||
}, function () {
|
|
||||||
toastr.error("An error occured while creating the user.", "Error");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete user
|
|
||||||
$scope.deleteUser = function($event, user_id) {
|
|
||||||
var el = $($event.target);
|
|
||||||
|
|
||||||
apiCall('admin/delete_user', {
|
|
||||||
'user_id': user_id,
|
|
||||||
}, function(new_status) {
|
|
||||||
$scope.hideRow(el, 'User successfully deleted.');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.changeUserRole = function(role, user_id) {
|
|
||||||
apiCall('admin/change_user_role', {
|
|
||||||
'user_id': user_id,
|
|
||||||
'role': role,
|
|
||||||
}, function(result) {
|
|
||||||
toastr.success("User role successfully changed.", "Success");
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Generate new API key for user_id
|
// Generate new API key for user_id
|
||||||
$scope.generateNewAPIKey = function($event, user_id, is_dev_tab) {
|
$scope.generateNewAPIKey = function($event, user_id, is_dev_tab) {
|
||||||
var el = $($event.target);
|
var el = $($event.target);
|
||||||
@ -195,51 +231,75 @@ polr.controller('AdminCtrl', function($scope, $compile) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Toggle API access status
|
$scope.checkNewUserFields = function() {
|
||||||
$scope.toggleAPIStatus = function($event, user_id) {
|
var response = true;
|
||||||
var el = $($event.target);
|
|
||||||
var status_display_elem = el.prevAll('.status-display');
|
|
||||||
|
|
||||||
apiCall('admin/toggle_api_active', {
|
$('.new-user-fields input').each(function () {
|
||||||
|
if ($(this).val().trim() == '' || response == false) {
|
||||||
|
response = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.addNewUser = function($event) {
|
||||||
|
// Allow admins to add new users
|
||||||
|
|
||||||
|
if (!$scope.checkNewUserFields()) {
|
||||||
|
toastr.error("Fields cannot be empty.", "Error");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
apiCall('admin/add_new_user', {
|
||||||
|
'username': $scope.newUserParams.username,
|
||||||
|
'user_password': $scope.newUserParams.userPassword,
|
||||||
|
'user_email': $scope.newUserParams.userEmail,
|
||||||
|
'user_role': $scope.newUserParams.userRole,
|
||||||
|
}, function(result) {
|
||||||
|
toastr.success("User " + $scope.newUserParams.username + " successfully created.", "Success");
|
||||||
|
$('#new-user-form').clearForm();
|
||||||
|
$scope.datatables['admin_users_table'].ajax.reload();
|
||||||
|
}, function () {
|
||||||
|
toastr.error("An error occured while creating the user.", "Error");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete user
|
||||||
|
$scope.deleteUser = function($event, user_id) {
|
||||||
|
var el = $($event.target);
|
||||||
|
|
||||||
|
apiCall('admin/delete_user', {
|
||||||
'user_id': user_id,
|
'user_id': user_id,
|
||||||
}, function(new_status) {
|
}, function(new_status) {
|
||||||
new_status = res_value_to_text(new_status);
|
toastr.success('User successfully deleted.', 'Success');
|
||||||
status_display_elem.text(new_status);
|
$scope.reloadUserTables();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update user API quotas
|
$scope.changeUserRole = function(role, user_id) {
|
||||||
$scope.updateAPIQuota = function($event, user_id) {
|
apiCall('admin/change_user_role', {
|
||||||
var el = $($event.target);
|
|
||||||
var new_quota = el.prevAll('.api-quota').val();
|
|
||||||
|
|
||||||
apiCall('admin/edit_api_quota', {
|
|
||||||
'user_id': user_id,
|
'user_id': user_id,
|
||||||
'new_quota': parseInt(new_quota)
|
'role': role,
|
||||||
}, function(next_action) {
|
}, function(result) {
|
||||||
toastr.success("Quota successfully changed.", "Success");
|
toastr.success("User role successfully changed.", "Success");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Open user API settings menu
|
// Open user API settings menu
|
||||||
$scope.openAPIModal = function($event, username, api_key, api_active, api_quota, user_id) {
|
$scope.openAPIModal = function($event, username, api_key, api_active, api_quota, user_id) {
|
||||||
var el = $($event.target);
|
var el = $($event.target);
|
||||||
var markup = $('#api-modal-template').html();
|
|
||||||
|
|
||||||
var modal_id = "api-modal-" + username;
|
$scope.modals.editUserApiInfo.push({
|
||||||
var modal_context = {
|
apiKey: api_key,
|
||||||
id: modal_id,
|
apiQuota: parseInt(api_quota),
|
||||||
api_key: api_key,
|
userId: user_id,
|
||||||
api_active: parseInt(api_active),
|
apiActive: api_active
|
||||||
api_quota: api_quota,
|
});
|
||||||
user_id: user_id,
|
|
||||||
title: "API Information for " + username,
|
$timeout(function () {
|
||||||
body: markup
|
$('#edit-user-api-info-' + user_id).modal('show');
|
||||||
};
|
});
|
||||||
var mt_html = $scope.modal_template(modal_context);
|
|
||||||
var compiled_mt = Handlebars.compile(mt_html);
|
|
||||||
mt_html = compiled_mt(modal_context);
|
|
||||||
$scope.appendModal(mt_html, modal_id);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -253,7 +313,8 @@ polr.controller('AdminCtrl', function($scope, $compile) {
|
|||||||
apiCall('admin/delete_link', {
|
apiCall('admin/delete_link', {
|
||||||
'link_ending': link_ending,
|
'link_ending': link_ending,
|
||||||
}, function(new_status) {
|
}, function(new_status) {
|
||||||
$scope.hideRow(el, 'Link successfully deleted.');
|
toastr.success('Link successfully deleted.', 'Success');
|
||||||
|
$scope.reloadLinkTables();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -278,6 +339,18 @@ polr.controller('AdminCtrl', function($scope, $compile) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Edit links' long_url
|
||||||
|
$scope.editLongLink = function(link_ending, old_long_link) {
|
||||||
|
$scope.modals.editLongLink.push({
|
||||||
|
linkEnding: link_ending,
|
||||||
|
oldLongLink: old_long_link,
|
||||||
|
});
|
||||||
|
|
||||||
|
$timeout(function () {
|
||||||
|
$('#edit-long-link-' + link_ending).modal('show');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Initialisation
|
Initialisation
|
||||||
*/
|
*/
|
||||||
@ -285,7 +358,6 @@ polr.controller('AdminCtrl', function($scope, $compile) {
|
|||||||
// Initialise AdminCtrl
|
// Initialise AdminCtrl
|
||||||
$scope.init = function() {
|
$scope.init = function() {
|
||||||
var modal_source = $("#modal-template").html();
|
var modal_source = $("#modal-template").html();
|
||||||
$scope.modal_template = Handlebars.compile(modal_source);
|
|
||||||
|
|
||||||
$('.admin-nav a').click(function(e) {
|
$('.admin-nav a').click(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
@ -6,7 +6,7 @@ polr.directive('setupTooltip', function() {
|
|||||||
replace: true,
|
replace: true,
|
||||||
template: '<button data-content="{{ content }}" type="button" class="btn btn-xs btn-default setup-qmark" data-toggle="popover">?</button>'
|
template: '<button data-content="{{ content }}" type="button" class="btn btn-xs btn-default setup-qmark" data-toggle="popover">?</button>'
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
polr.controller('SetupCtrl', function($scope) {
|
polr.controller('SetupCtrl', function($scope) {
|
||||||
$scope.init = function () {
|
$scope.init = function () {
|
||||||
|
29
public/js/handlebars-v4.0.5.min.js
vendored
29
public/js/handlebars-v4.0.5.min.js
vendored
File diff suppressed because one or more lines are too long
@ -65,11 +65,11 @@
|
|||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr id="new-user-form">
|
<tr id="new-user-form">
|
||||||
<td><input type="text" class="form-control" id="new-username"></td>
|
<td><input type="text" class="form-control" ng-model="newUserParams.username"></td>
|
||||||
<td><input type="password" class="form-control" id="new-user-password"></td>
|
<td><input type="password" class="form-control" ng-model="newUserParams.userPassword"></td>
|
||||||
<td><input type="email" class="form-control" id="new-user-email"></td>
|
<td><input type="email" class="form-control" ng-model="newUserParams.userEmail"></td>
|
||||||
<td>
|
<td>
|
||||||
<select class="form-control new-user-role" id="new-user-role">
|
<select class="form-control new-user-role" ng-model="newUserParams.userRole">
|
||||||
@foreach ($user_roles as $role_text => $role_val)
|
@foreach ($user_roles as $role_text => $role_val)
|
||||||
<option value="{{$role_val}}">{{$role_text}}</option>
|
<option value="{{$role_val}}">{{$role_text}}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
@ -123,6 +123,14 @@
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="angular-modals">
|
||||||
|
<edit-long-link-modal ng-repeat="modal in modals.editLongLink" link-ending="modal.linkEnding"
|
||||||
|
old-long-link="modal.oldLongLink" clean-modals="cleanModals"></edit-long-link-modal>
|
||||||
|
<edit-user-api-info-modal ng-repeat="modal in modals.editUserApiInfo" user-id="modal.userId"
|
||||||
|
api-quota="modal.apiQuota" api-active="modal.apiActive" api-key="modal.apiKey"
|
||||||
|
generate-new-api-key="generateNewAPIKey" clean-modals="cleanModals"></edit-user-api-info>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@ -133,31 +141,7 @@
|
|||||||
@include('snippets.modals')
|
@include('snippets.modals')
|
||||||
|
|
||||||
{{-- Include extra JS --}}
|
{{-- Include extra JS --}}
|
||||||
<script src='/js/handlebars-v4.0.5.min.js'></script>
|
|
||||||
<script src='/js/datatables.min.js'></script>
|
<script src='/js/datatables.min.js'></script>
|
||||||
<script src='/js/api.js'></script>
|
<script src='/js/api.js'></script>
|
||||||
<script src='/js/AdminCtrl.js'></script>
|
<script src='/js/AdminCtrl.js'></script>
|
||||||
|
|
||||||
{{-- Extra templating --}}
|
|
||||||
<script id="api-modal-template" type="text/x-handlebars-template">
|
|
||||||
<div>
|
|
||||||
<p>
|
|
||||||
<span>API Active</span>:
|
|
||||||
|
|
||||||
<code class='status-display'>
|
|
||||||
@{{#if api_active}}True@{{else}}False@{{/if}}</code>
|
|
||||||
|
|
||||||
<a ng-click="toggleAPIStatus($event, '@{{user_id}}')" class='btn btn-xs btn-success'>toggle</a>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<span>API Key: </span><code class='status-display'>@{{api_key}}</code>
|
|
||||||
<a ng-click="generateNewAPIKey($event, '@{{user_id}}', false)" class='btn btn-xs btn-danger'>reset</a>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<span>API Quota (req/min, -1 for unlimited):</span> <input type='number' class='form-control api-quota' value='@{{api_quota}}'>
|
|
||||||
<a ng-click="updateAPIQuota($event, '@{{user_id}}')" class='btn btn-xs btn-warning'>change</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
@endsection
|
@endsection
|
||||||
|
@ -50,13 +50,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- Load header JavaScript --}}
|
{{-- Load JavaScript dependencies --}}
|
||||||
<script src='/js/constants.js'></script>
|
<script src="/js/constants.js"></script>
|
||||||
<script src="/js/jquery-1.11.3.min.js"></script>
|
<script src="/js/jquery-1.11.3.min.js"></script>
|
||||||
<script src="/js/bootstrap.min.js"></script>
|
<script src="/js/bootstrap.min.js"></script>
|
||||||
<script src='/js/angular.min.js'></script>
|
<script src="/js/angular.min.js"></script>
|
||||||
<script src='/js/toastr.min.js'></script>
|
<script src="/js/toastr.min.js"></script>
|
||||||
<script src='/js/base.js'></script>
|
<script src="/js/base.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@if (Session::has('info'))
|
@if (Session::has('info'))
|
||||||
|
Loading…
Reference in New Issue
Block a user