mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-09 20:52:56 +01:00
Added support for API tokens
This commit is contained in:
parent
29833e6d83
commit
9210e3d578
@ -87,6 +87,8 @@ class AccountController extends \BaseController
|
||||
|
||||
if ($entityType == 'user') {
|
||||
return Redirect::to('company/'.ACCOUNT_ADVANCED_SETTINGS.'/'.ACCOUNT_USER_MANAGEMENT);
|
||||
} elseif ($entityType == 'token') {
|
||||
return Redirect::to('company/'.ACCOUNT_ADVANCED_SETTINGS.'/'.ACCOUNT_TOKEN_MANAGEMENT);
|
||||
} else {
|
||||
return Redirect::to("{$entityType}s");
|
||||
}
|
||||
|
159
app/controllers/TokenController.php
Executable file
159
app/controllers/TokenController.php
Executable file
@ -0,0 +1,159 @@
|
||||
<?php
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Confide Controller Template
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is the default Confide controller template for controlling user
|
||||
| authentication. Feel free to change to your needs.
|
||||
|
|
||||
*/
|
||||
|
||||
use ninja\repositories\AccountRepository;
|
||||
|
||||
class TokenController extends BaseController
|
||||
{
|
||||
public function getDatatable()
|
||||
{
|
||||
$query = DB::table('account_tokens')
|
||||
->where('account_tokens.account_id', '=', Auth::user()->account_id);
|
||||
|
||||
if (!Session::get('show_trash:token')) {
|
||||
$query->where('account_tokens.deleted_at', '=', null);
|
||||
}
|
||||
|
||||
$query->select('account_tokens.public_id', 'account_tokens.name', 'account_tokens.token', 'account_tokens.public_id', 'account_tokens.deleted_at');
|
||||
|
||||
return Datatable::query($query)
|
||||
->addColumn('name', function ($model) { return link_to('tokens/'.$model->public_id.'/edit', $model->name); })
|
||||
->addColumn('token', function ($model) { return $model->token; })
|
||||
->addColumn('dropdown', function ($model) {
|
||||
$actions = '<div class="btn-group tr-action" style="visibility:hidden;">
|
||||
<button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">
|
||||
'.trans('texts.select').' <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" role="menu">';
|
||||
|
||||
if (!$model->deleted_at) {
|
||||
$actions .= '<li><a href="'.URL::to('tokens/'.$model->public_id).'/edit">'.uctrans('texts.edit_token').'</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="javascript:deleteToken('.$model->public_id.')">'.uctrans('texts.delete_token').'</a></li>';
|
||||
}
|
||||
|
||||
$actions .= '</ul>
|
||||
</div>';
|
||||
|
||||
return $actions;
|
||||
})
|
||||
->orderColumns(['name', 'token'])
|
||||
->make();
|
||||
}
|
||||
|
||||
public function edit($publicId)
|
||||
{
|
||||
$token = AccountToken::where('account_id', '=', Auth::user()->account_id)
|
||||
->where('public_id', '=', $publicId)->firstOrFail();
|
||||
|
||||
$data = [
|
||||
'showBreadcrumbs' => false,
|
||||
'token' => $token,
|
||||
'method' => 'PUT',
|
||||
'url' => 'tokens/'.$publicId,
|
||||
'title' => trans('texts.edit_token'),
|
||||
];
|
||||
|
||||
return View::make('accounts.token', $data);
|
||||
}
|
||||
|
||||
public function update($publicId)
|
||||
{
|
||||
return $this->save($publicId);
|
||||
}
|
||||
|
||||
public function store()
|
||||
{
|
||||
return $this->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the form for account creation
|
||||
*
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
if (!Auth::user()->confirmed) {
|
||||
Session::flash('error', trans('texts.register_to_add_user'));
|
||||
return Redirect::to('company/advanced_settings/user_management');
|
||||
}
|
||||
|
||||
$data = [
|
||||
'showBreadcrumbs' => false,
|
||||
'token' => null,
|
||||
'method' => 'POST',
|
||||
'url' => 'tokens',
|
||||
'title' => trans('texts.add_token'),
|
||||
];
|
||||
|
||||
return View::make('accounts.token', $data);
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
$tokenPublicId = Input::get('tokenPublicId');
|
||||
$token = AccountToken::where('account_id', '=', Auth::user()->account_id)
|
||||
->where('public_id', '=', $tokenPublicId)->firstOrFail();
|
||||
|
||||
$token->delete();
|
||||
|
||||
Session::flash('message', trans('texts.deleted_token'));
|
||||
|
||||
return Redirect::to('company/advanced_settings/token_management');
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores new account
|
||||
*
|
||||
*/
|
||||
public function save($tokenPublicId = false)
|
||||
{
|
||||
$rules = [
|
||||
'name' => 'required',
|
||||
];
|
||||
|
||||
if ($tokenPublicId) {
|
||||
$token = AccountToken::where('account_id', '=', Auth::user()->account_id)
|
||||
->where('public_id', '=', $tokenPublicId)->firstOrFail();
|
||||
}
|
||||
|
||||
$validator = Validator::make(Input::all(), $rules);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return Redirect::to($tokenPublicId ? 'tokens/edit' : 'tokens/create')->withInput()->withErrors($validator);
|
||||
}
|
||||
|
||||
if ($tokenPublicId) {
|
||||
$token->name = trim(Input::get('name'));
|
||||
} else {
|
||||
$lastToken = AccountToken::withTrashed()->where('account_id', '=', Auth::user()->account_id)
|
||||
->orderBy('public_id', 'DESC')->first();
|
||||
|
||||
$token = AccountToken::createNew();
|
||||
$token->name = trim(Input::get('name'));
|
||||
$token->token = str_random(RANDOM_KEY_LENGTH);
|
||||
$token->public_id = $lastToken ? $lastToken->public_id + 1 : 1;
|
||||
}
|
||||
|
||||
$token->save();
|
||||
|
||||
if ($tokenPublicId) {
|
||||
$message = trans('texts.updated_token');
|
||||
} else {
|
||||
$message = trans('texts.created_token');
|
||||
}
|
||||
|
||||
Session::flash('message', $message);
|
||||
|
||||
return Redirect::to('company/advanced_settings/token_management');
|
||||
}
|
||||
|
||||
}
|
54
app/database/migrations/2015_03_03_140259_add_tokens.php
Normal file
54
app/database/migrations/2015_03_03_140259_add_tokens.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddTokens extends Migration {
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('account_tokens', function($table)
|
||||
{
|
||||
$table->increments('id');
|
||||
$table->unsignedInteger('account_id')->index();
|
||||
$table->unsignedInteger('user_id');
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->string('name')->nullable();
|
||||
$table->string('token')->unique();
|
||||
|
||||
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
|
||||
$table->unsignedInteger('public_id')->nullable();
|
||||
$table->unique(['account_id', 'public_id']);
|
||||
});
|
||||
|
||||
Schema::table('activities', function($table)
|
||||
{
|
||||
$table->unsignedInteger('token_id')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::drop('account_tokens');
|
||||
|
||||
Schema::table('activities', function($table)
|
||||
{
|
||||
$table->dropColumn('token_id');
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -176,6 +176,16 @@ Route::filter('auth.basic', function()
|
||||
Route::filter('api.access', function()
|
||||
{
|
||||
$headers = Utils::getApiHeaders();
|
||||
|
||||
// check for a valid token
|
||||
$token = AccountToken::where('token', '=', Request::header('X-Ninja-Token'))->first(['id', 'user_id']);
|
||||
|
||||
if ($token) {
|
||||
Auth::loginUsingId($token->user_id);
|
||||
Session::set('token_id', $token->id);
|
||||
} else {
|
||||
return Response::make('Invalid token', 403, $headers);
|
||||
}
|
||||
|
||||
if (!Utils::isPro()) {
|
||||
return Response::make('API requires pro plan', 403, $headers);
|
||||
|
@ -539,4 +539,15 @@ return array(
|
||||
'invoice_footer' => 'Invoice footer',
|
||||
'save_as_default_footer' => 'Save as default footer',
|
||||
|
||||
'token_management' => 'Token Management',
|
||||
'tokens' => 'Tokens',
|
||||
'add_token' => 'Add Token',
|
||||
'show_deleted_tokens' => 'Show deleted tokens',
|
||||
'deleted_token' => 'Successfully deleted token',
|
||||
'created_token' => 'Successfully created token',
|
||||
'edit_token' => 'Edit Token',
|
||||
'delete_token' => 'Delete Token',
|
||||
'token' => 'Token',
|
||||
|
||||
|
||||
);
|
||||
|
@ -529,4 +529,15 @@ return array(
|
||||
'invoice_footer' => 'Invoice footer',
|
||||
'save_as_default_footer' => 'Save as default footer',
|
||||
|
||||
'token_management' => 'Token Management',
|
||||
'tokens' => 'Tokens',
|
||||
'add_token' => 'Add Token',
|
||||
'show_deleted_tokens' => 'Show deleted tokens',
|
||||
'deleted_token' => 'Successfully deleted token',
|
||||
'created_token' => 'Successfully created token',
|
||||
'edit_token' => 'Edit Token',
|
||||
'delete_token' => 'Delete Token',
|
||||
'token' => 'Token',
|
||||
|
||||
|
||||
);
|
||||
|
@ -537,4 +537,15 @@ return array(
|
||||
'invoice_footer' => 'Invoice footer',
|
||||
'save_as_default_footer' => 'Save as default footer',
|
||||
|
||||
'token_management' => 'Token Management',
|
||||
'tokens' => 'Tokens',
|
||||
'add_token' => 'Add Token',
|
||||
'show_deleted_tokens' => 'Show deleted tokens',
|
||||
'deleted_token' => 'Successfully deleted token',
|
||||
'created_token' => 'Successfully created token',
|
||||
'edit_token' => 'Edit Token',
|
||||
'delete_token' => 'Delete Token',
|
||||
'token' => 'Token',
|
||||
|
||||
|
||||
);
|
||||
|
@ -509,4 +509,15 @@ return array(
|
||||
'invoice_footer' => 'Invoice footer',
|
||||
'save_as_default_footer' => 'Save as default footer',
|
||||
|
||||
'token_management' => 'Token Management',
|
||||
'tokens' => 'Tokens',
|
||||
'add_token' => 'Add Token',
|
||||
'show_deleted_tokens' => 'Show deleted tokens',
|
||||
'deleted_token' => 'Successfully deleted token',
|
||||
'created_token' => 'Successfully created token',
|
||||
'edit_token' => 'Edit Token',
|
||||
'delete_token' => 'Delete Token',
|
||||
'token' => 'Token',
|
||||
|
||||
|
||||
);
|
@ -530,4 +530,14 @@ return array(
|
||||
'invoice_footer' => 'Invoice footer',
|
||||
'save_as_default_footer' => 'Save as default footer',
|
||||
|
||||
'token_management' => 'Token Management',
|
||||
'tokens' => 'Tokens',
|
||||
'add_token' => 'Add Token',
|
||||
'show_deleted_tokens' => 'Show deleted tokens',
|
||||
'deleted_token' => 'Successfully deleted token',
|
||||
'created_token' => 'Successfully created token',
|
||||
'edit_token' => 'Edit Token',
|
||||
'delete_token' => 'Delete Token',
|
||||
'token' => 'Token',
|
||||
|
||||
);
|
@ -531,5 +531,15 @@ return array(
|
||||
'default_invoice_footer' => 'Set default invoice footer',
|
||||
'invoice_footer' => 'Invoice footer',
|
||||
'save_as_default_footer' => 'Save as default footer',
|
||||
|
||||
'token_management' => 'Token Management',
|
||||
'tokens' => 'Tokens',
|
||||
'add_token' => 'Add Token',
|
||||
'show_deleted_tokens' => 'Show deleted tokens',
|
||||
'deleted_token' => 'Successfully deleted token',
|
||||
'created_token' => 'Successfully created token',
|
||||
'edit_token' => 'Edit Token',
|
||||
'delete_token' => 'Delete Token',
|
||||
'token' => 'Token',
|
||||
|
||||
);
|
||||
|
@ -539,6 +539,16 @@ return array(
|
||||
'default_invoice_footer' => 'Set default invoice footer',
|
||||
'invoice_footer' => 'Invoice footer',
|
||||
'save_as_default_footer' => 'Save as default footer',
|
||||
|
||||
'token_management' => 'Token Management',
|
||||
'tokens' => 'Tokens',
|
||||
'add_token' => 'Add Token',
|
||||
'show_deleted_tokens' => 'Show deleted tokens',
|
||||
'deleted_token' => 'Successfully deleted token',
|
||||
'created_token' => 'Successfully created token',
|
||||
'edit_token' => 'Edit Token',
|
||||
'delete_token' => 'Delete Token',
|
||||
'token' => 'Token',
|
||||
|
||||
);
|
||||
|
||||
|
@ -538,5 +538,15 @@ return array(
|
||||
'invoice_footer' => 'Invoice footer',
|
||||
'save_as_default_footer' => 'Save as default footer',
|
||||
|
||||
'token_management' => 'Token Management',
|
||||
'tokens' => 'Tokens',
|
||||
'add_token' => 'Add Token',
|
||||
'show_deleted_tokens' => 'Show deleted tokens',
|
||||
'deleted_token' => 'Successfully deleted token',
|
||||
'created_token' => 'Successfully created token',
|
||||
'edit_token' => 'Edit Token',
|
||||
'delete_token' => 'Delete Token',
|
||||
'token' => 'Token',
|
||||
|
||||
|
||||
);
|
@ -532,6 +532,16 @@ return array(
|
||||
'default_invoice_footer' => 'Set default invoice footer',
|
||||
'invoice_footer' => 'Invoice footer',
|
||||
'save_as_default_footer' => 'Save as default footer',
|
||||
|
||||
'token_management' => 'Token Management',
|
||||
'tokens' => 'Tokens',
|
||||
'add_token' => 'Add Token',
|
||||
'show_deleted_tokens' => 'Show deleted tokens',
|
||||
'deleted_token' => 'Successfully deleted token',
|
||||
'created_token' => 'Successfully created token',
|
||||
'edit_token' => 'Edit Token',
|
||||
'delete_token' => 'Delete Token',
|
||||
'token' => 'Token',
|
||||
|
||||
|
||||
);
|
@ -519,5 +519,16 @@ return array(
|
||||
'default_invoice_footer' => 'Set default invoice footer',
|
||||
'invoice_footer' => 'Invoice footer',
|
||||
'save_as_default_footer' => 'Save as default footer',
|
||||
|
||||
'token_management' => 'Token Management',
|
||||
'tokens' => 'Tokens',
|
||||
'add_token' => 'Add Token',
|
||||
'show_deleted_tokens' => 'Show deleted tokens',
|
||||
'deleted_token' => 'Successfully deleted token',
|
||||
'created_token' => 'Successfully created token',
|
||||
'edit_token' => 'Edit Token',
|
||||
'delete_token' => 'Delete Token',
|
||||
'token' => 'Token',
|
||||
|
||||
|
||||
);
|
||||
|
@ -466,8 +466,9 @@ class Utils
|
||||
$person = $person ? $person->getDisplayName() : '<i>System</i>';
|
||||
$entity = $entity ? '['.$entity->getActivityKey().']' : '';
|
||||
$otherPerson = $otherPerson ? 'to '.$otherPerson->getDisplayName() : '';
|
||||
$token = Session::get('token_id') ? ' ('.trans('texts.token').')' : '';
|
||||
|
||||
return trim("$person $action $entity $otherPerson");
|
||||
return trim("$person $token $action $entity $otherPerson");
|
||||
}
|
||||
|
||||
public static function decodeActivity($message)
|
||||
|
9
app/models/AccountToken.php
Executable file
9
app/models/AccountToken.php
Executable file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
class AccountToken extends EntityModel
|
||||
{
|
||||
public function account()
|
||||
{
|
||||
return $this->belongsTo('Account');
|
||||
}
|
||||
}
|
@ -34,6 +34,8 @@ class Activity extends Eloquent
|
||||
Utils::fatalError();
|
||||
}
|
||||
|
||||
$activity->token_id = Session::get('token_id', null);
|
||||
|
||||
return $activity;
|
||||
}
|
||||
|
||||
|
@ -82,6 +82,10 @@ Route::group(array('before' => 'auth'), function() {
|
||||
Route::get('send_confirmation/{user_id}', 'UserController@sendConfirmation');
|
||||
Route::get('restore_user/{user_id}', 'UserController@restoreUser');
|
||||
|
||||
Route::get('api/tokens', array('as'=>'api.tokens', 'uses'=>'TokenController@getDatatable'));
|
||||
Route::resource('tokens', 'TokenController');
|
||||
Route::post('tokens/delete', 'TokenController@delete');
|
||||
|
||||
Route::get('api/products', array('as'=>'api.products', 'uses'=>'ProductController@getDatatable'));
|
||||
Route::resource('products', 'ProductController');
|
||||
Route::get('products/{product_id}/archive', 'ProductController@archive');
|
||||
@ -142,7 +146,7 @@ Route::group(array('before' => 'auth'), function() {
|
||||
});
|
||||
|
||||
// Route group for API
|
||||
Route::group(array('prefix' => 'api/v1', 'before' => ['auth.basic', 'api.access']), function()
|
||||
Route::group(array('prefix' => 'api/v1', 'before' => ['api.access']), function()
|
||||
{
|
||||
Route::resource('ping', 'ClientApiController@ping');
|
||||
Route::resource('clients', 'ClientApiController');
|
||||
@ -186,6 +190,7 @@ define('ACCOUNT_CHART_BUILDER', 'chart_builder');
|
||||
define('ACCOUNT_USER_MANAGEMENT', 'user_management');
|
||||
define('ACCOUNT_DATA_VISUALIZATIONS', 'data_visualizations');
|
||||
define('ACCOUNT_EMAIL_TEMPLATES', 'email_templates');
|
||||
define('ACCOUNT_TOKEN_MANAGEMENT', 'token_management');
|
||||
|
||||
define('ACTIVITY_TYPE_CREATE_CLIENT', 1);
|
||||
define('ACTIVITY_TYPE_ARCHIVE_CLIENT', 2);
|
||||
|
@ -4,7 +4,8 @@
|
||||
{{ HTML::nav_link('company/advanced_settings/email_templates', 'email_templates') }}
|
||||
{{ HTML::nav_link('company/advanced_settings/data_visualizations', 'data_visualizations') }}
|
||||
{{ HTML::nav_link('company/advanced_settings/chart_builder', 'chart_builder') }}
|
||||
{{ HTML::nav_link('company/advanced_settings/user_management', 'user_management') }}
|
||||
{{ HTML::nav_link('company/advanced_settings/user_management', 'users') }}
|
||||
{{ HTML::nav_link('company/advanced_settings/token_management', 'tokens') }}
|
||||
</ul>
|
||||
<p> </p>
|
||||
|
||||
|
29
app/views/accounts/token.blade.php
Normal file
29
app/views/accounts/token.blade.php
Normal file
@ -0,0 +1,29 @@
|
||||
@extends('accounts.nav')
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
|
||||
{{ Former::open($url)->method($method)->addClass('col-md-8 col-md-offset-2 warn-on-exit')->rules(array(
|
||||
'name' => 'required',
|
||||
)); }}
|
||||
|
||||
{{ Former::legend($title) }}
|
||||
|
||||
<p> </p>
|
||||
|
||||
@if ($token)
|
||||
{{ Former::populate($token) }}
|
||||
@endif
|
||||
|
||||
{{ Former::text('name') }}
|
||||
|
||||
<p> </p>
|
||||
|
||||
{{ Former::actions(
|
||||
Button::lg_success_submit(trans('texts.save'))->append_with_icon('floppy-disk'),
|
||||
Button::lg_default_link('company/advanced_settings/token_management', 'Cancel')->append_with_icon('remove-circle')
|
||||
) }}
|
||||
|
||||
{{ Former::close() }}
|
||||
|
||||
@stop
|
67
app/views/accounts/token_management.blade.php
Normal file
67
app/views/accounts/token_management.blade.php
Normal file
@ -0,0 +1,67 @@
|
||||
@extends('accounts.nav')
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
@include('accounts.nav_advanced')
|
||||
|
||||
{{ Former::open('tokens/delete')->addClass('user-form') }}
|
||||
{{ Former::legend('token_management') }}
|
||||
|
||||
<div style="display:none">
|
||||
{{ Former::text('tokenPublicId') }}
|
||||
</div>
|
||||
{{ Former::close() }}
|
||||
|
||||
|
||||
@if (Utils::isPro())
|
||||
{{ Button::success_link(URL::to('tokens/create'), trans("texts.add_token"), array('class' => 'pull-right'))->append_with_icon('plus-sign') }}
|
||||
@endif
|
||||
|
||||
<!--
|
||||
<label for="trashed" style="font-weight:normal; margin-left: 10px;">
|
||||
<input id="trashed" type="checkbox" onclick="setTrashVisible()"
|
||||
{{ Session::get('show_trash:token') ? 'checked' : ''}}/> {{ trans('texts.show_deleted_tokens')}}
|
||||
</label>
|
||||
-->
|
||||
|
||||
{{ Datatable::table()
|
||||
->addColumn(
|
||||
trans('texts.name'),
|
||||
trans('texts.token'),
|
||||
trans('texts.action'))
|
||||
->setUrl(url('api/tokens/'))
|
||||
->setOptions('sPaginationType', 'bootstrap')
|
||||
->setOptions('bFilter', false)
|
||||
->setOptions('bAutoWidth', false)
|
||||
->setOptions('aoColumns', [[ "sWidth"=> "40%" ], [ "sWidth"=> "40%" ], ["sWidth"=> "20%"]])
|
||||
->setOptions('aoColumnDefs', [['bSortable'=>false, 'aTargets'=>[2]]])
|
||||
->render('datatable') }}
|
||||
|
||||
<script>
|
||||
window.onDatatableReady = function() {
|
||||
$('tbody tr').mouseover(function() {
|
||||
$(this).closest('tr').find('.tr-action').css('visibility','visible');
|
||||
}).mouseout(function() {
|
||||
$dropdown = $(this).closest('tr').find('.tr-action');
|
||||
if (!$dropdown.hasClass('open')) {
|
||||
$dropdown.css('visibility','hidden');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setTrashVisible() {
|
||||
var checked = $('#trashed').is(':checked');
|
||||
window.location = '{{ URL::to('view_archive/token') }}' + (checked ? '/true' : '/false');
|
||||
}
|
||||
|
||||
function deleteToken(id) {
|
||||
if (!confirm('Are you sure?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$('#tokenPublicId').val(id);
|
||||
$('form.user-form').submit();
|
||||
}
|
||||
</script>
|
||||
|
||||
@stop
|
@ -7,8 +7,6 @@
|
||||
{{ Former::open('users/delete')->addClass('user-form') }}
|
||||
{{ Former::legend('user_management') }}
|
||||
|
||||
|
||||
|
||||
<div style="display:none">
|
||||
{{ Former::text('userPublicId') }}
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user