Fix FLEXIAPI-386 Move the Contacts Lists in Spaces

This commit is contained in:
Timothée Jaussoin 2025-10-09 16:59:37 +02:00
parent abcc9c1c7b
commit a53910d364
22 changed files with 256 additions and 167 deletions

View file

@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/).
## [2.1]
### Changed
- **Contacts Lists** The Contacts Lists are now handled per Space. During the migration, if there is only one Space present, existing Contacts Lists are automatically attached to it, otherwise the first Super Space available is used. If they are then attached to the wrong Space you'll have to change directly their `space_id` value in the `contacts_lists` database table.
## [2.0]
### Added

View file

@ -15,4 +15,9 @@ class ContactsList extends Model
{
return $this->belongsToMany(Account::class, 'contacts_list_contact', 'contacts_list_id', 'contact_id');
}
public function space()
{
return $this->belongsTo(Space::class);
}
}

View file

@ -17,18 +17,19 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\Space;
use App\Account;
use App\ContactsList;
use App\Space;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class ContactsListContactController extends Controller
{
public function add(Request $request, int $contactsListId)
public function add(Request $request, Space $space, int $contactsListId)
{
$accounts = Account::orderBy('updated_at', $request->get('updated_at_order', 'desc'));
$accounts = $space->accounts()->orderBy('updated_at', $request->get('updated_at_order', 'desc'));
if ($request->has('search')) {
$accounts = $accounts->where('username', 'like', '%' . $request->get('search') . '%');
@ -38,9 +39,9 @@ class ContactsListContactController extends Controller
$accounts = $accounts->where('domain', $request->get('domain'));
}
return view('admin.contacts_list.contacts.add', [
'domains' => Account::groupBy('domain')->pluck('domain'),
'contacts_list' => ContactsList::findOrFail($contactsListId),
return view('admin.space.contacts_list.contacts.add', [
'space' => $space,
'contacts_list' => $space->contactsLists()->findOrFail($contactsListId),
'params' => [
'contacts_list_id' => $contactsListId
],
@ -52,33 +53,33 @@ class ContactsListContactController extends Controller
]);
}
public function search(Request $request, int $contactsListId)
public function search(Request $request, Space $space, int $contactsListId)
{
return redirect()->route('admin.contacts_lists.contacts.add', ['contacts_list_id' => $contactsListId] + $request->except('_token'));
return redirect()->route('admin.spaces.contacts_lists.contacts.add', ['contacts_list_id' => $contactsListId] + $request->except('_token'));
}
public function store(Request $request, int $contactsListId)
public function store(Request $request, Space $space, int $contactsListId)
{
$request->validate([
'contacts_ids' => 'required|exists:accounts,id'
]);
$contactsList = ContactsList::findOrFail($contactsListId);
$contactsList = $space->contactsLists()->findOrFail($contactsListId);
$contactsList->contacts()->detach($request->get('contacts_ids')); // Just in case
$contactsList->contacts()->attach($request->get('contacts_ids'));
return redirect()->route('admin.contacts_lists.edit', $contactsList->id);
return redirect()->route('admin.spaces.contacts_lists.edit', [$space, $contactsList->id]);
}
public function destroy(Request $request, int $contactsListId)
public function destroy(Request $request, Space $space, int $contactsListId)
{
$request->validate([
'contacts_ids' => 'required|exists:accounts,id'
]);
$contactsList = ContactsList::findOrFail($contactsListId);
$contactsList = $space->contactsLists()->findOrFail($contactsListId);
$contactsList->contacts()->detach($request->get('contacts_ids'));
return redirect()->route('admin.contacts_lists.edit', $contactsList->id);
return redirect()->route('admin.spaces.contacts_lists.edit', [$space, $contactsList->id]);
}
}

View file

@ -17,61 +17,67 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\Space;
use App\Account;
use App\ContactsList;
use App\Space;
use App\Http\Controllers\Controller;
use Illuminate\Validation\Rule;
use Illuminate\Http\Request;
class ContactsListController extends Controller
{
public function index(Request $request)
public function index(Request $request, Space $space)
{
$request->validate([
'order_by' => 'in:title,updated_at,contacts_count',
'order_sort' => 'in:asc,desc',
]);
$contactsLists = ContactsList::orderBy($request->get('order_by', 'updated_at'), $request->get('order_sort', 'desc'));
$contactsLists = $space->contactsLists()->orderBy($request->get('order_by', 'updated_at'), $request->get('order_sort', 'desc'));
return view('admin.contacts_list.index', [
return view('admin.space.contacts_list.index', [
'space' => $space,
'contacts_lists' => $contactsLists
->paginate(20)
->appends($request->query()),
]);
}
public function create(Request $request)
public function create(Request $request, Space $space)
{
return view('admin.contacts_list.create_edit', [
return view('admin.space.contacts_list.create_edit', [
'space' => $space,
'contacts_list' => new ContactsList,
]);
}
public function store(Request $request)
public function store(Request $request, Space $space)
{
$request->validate([
'title' => 'required|unique:contacts_lists'
]);
$contactsList = new ContactsList;
$contactsList->space_id = $space->id;
$contactsList->title = $request->get('title');
$contactsList->description = $request->get('description');
$contactsList->save();
return redirect()->route('admin.contacts_lists.edit', $contactsList->id);
return redirect()->route('admin.spaces.contacts_lists.edit', [$space, $contactsList->id]);
}
public function search(Request $request, int $contactsListId)
public function search(Request $request, Space $space, int $contactsListId)
{
return redirect()->route('admin.contacts_lists.edit', ['contacts_list_id' => $contactsListId] + $request->except('_token'));
return redirect()->route('admin.spaces.contacts_lists.edit', [
'space' => $space,
'contacts_list_id' => $contactsListId] + $request->except('_token'));
}
public function edit(Request $request, int $id)
public function edit(Request $request, Space $space, int $id)
{
$contacts = ContactsList::findOrFail($id)->contacts();
$contacts = $space->contactsLists()->findOrFail($id)->contacts();
if ($request->has('search')) {
$contacts = $contacts->where('username', 'like', '%' . $request->get('search') . '%');
@ -83,14 +89,15 @@ class ContactsListController extends Controller
$contacts = $contacts->get();
return view('admin.contacts_list.create_edit', [
return view('admin.space.contacts_list.create_edit', [
'space' => $space,
'domains' => Account::groupBy('domain')->pluck('domain'),
'contacts_list' => ContactsList::findOrFail($id),
'contacts_list' => $space->contactsLists()->findOrFail($id),
'contacts' => $contacts
]);
}
public function update(Request $request, int $id)
public function update(Request $request, Space $space, int $id)
{
$request->validate([
'title' => [
@ -99,26 +106,27 @@ class ContactsListController extends Controller
],
]);
$contactsList = ContactsList::findOrFail($id);
$contactsList = $space->contactsLists()->findOrFail($id);
$contactsList->title = $request->get('title');
$contactsList->description = $request->get('description');
$contactsList->save();
return redirect()->route('admin.contacts_lists.index');
return redirect()->route('admin.spaces.contacts_lists.index', $space);
}
public function delete(int $id)
public function delete(Space $space, int $id)
{
return view('admin.contacts_list.delete', [
'contacts_list' => ContactsList::findOrFail($id),
return view('admin.space.contacts_list.delete', [
'space' => $space,
'contacts_list' => $space->contactsLists()->findOrFail($id),
]);
}
public function destroy(Request $request)
public function destroy(Request $request, Space $space)
{
$contactsList = ContactsList::findOrFail($request->get('contacts_lists_id'));
$contactsList = $space->contactsLists()->findOrFail($request->get('contacts_lists_id'));
$contactsList->delete();
return redirect()->route('admin.contacts_lists.index');
return redirect()->route('admin.spaces.contacts_lists.index', $space);
}
}

View file

@ -17,7 +17,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace App\Http\Controllers\Api\Admin;
namespace App\Http\Controllers\Api\Admin\Space;
use App\Account;
use App\ContactsList;
@ -28,12 +28,12 @@ class ContactsListController extends Controller
{
public function index(Request $request)
{
return ContactsList::all();
return $request->space->contactsLists;
}
public function get(int $contactsListId)
public function get(Request $request, int $contactsListId)
{
return ContactsList::findOrFail($contactsListId);
return $request->space->contactsLists()->findOrFail($contactsListId);
}
public function store(Request $request)
@ -44,6 +44,7 @@ class ContactsListController extends Controller
]);
$contactsList = new ContactsList;
$contactsList->space_id = $request->space->id;
$contactsList->title = $request->get('title');
$contactsList->description = $request->get('description');
$contactsList->save();
@ -59,6 +60,7 @@ class ContactsListController extends Controller
]);
$contactsList = ContactsList::findOrFail($contactsListId);
$contactsList->space_id = $request->space->id;
$contactsList->title = $request->get('title');
$contactsList->description = $request->get('description');
$contactsList->save();
@ -66,15 +68,15 @@ class ContactsListController extends Controller
return $contactsList;
}
public function destroy(int $contactsListId)
public function destroy(Request $request, int $contactsListId)
{
return ContactsList::where('id', $contactsListId)
return $request->space->contactsLists()->where('id', $contactsListId)
->delete();
}
public function contactAdd(int $id, int $contactId)
public function contactAdd(Request $request, int $id, int $contactId)
{
$contactsList = ContactsList::findOrFail($id);
$contactsList = $request->space->contactsLists()->findOrFail($id);
$contactsList->contacts()->detach($contactId);
if (Account::findOrFail($contactId)) {
@ -82,9 +84,9 @@ class ContactsListController extends Controller
}
}
public function contactRemove(int $id, int $contactId)
public function contactRemove(Request $request, int $id, int $contactId)
{
$contactsList = ContactsList::findOrFail($id);
$contactsList = $request->space->contactsLists()->findOrFail($id);
if (!$contactsList->contacts()->pluck('id')->contains($contactId)) {
abort(404);

View file

@ -102,6 +102,11 @@ class Space extends Model
return $this->hasMany(SpaceCardDavServer::class);
}
public function contactsLists()
{
return $this->hasMany(ContactsList::class);
}
public function scopeNotFull(Builder $query)
{
return $query->where('max_accounts', 0)

View file

@ -0,0 +1,47 @@
<?php
use App\Space;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::disableForeignKeyConstraints();
/**
* We have to make a choice to run the migration ¯\_()_/¯
*/
$space = (Space::count() == 1)
? Space::first()
: Space::where('super', true)->first();
Schema::table('contacts_lists', function (Blueprint $table) use ($space) {
if ($space) {
$table->bigInteger('space_id')->unsigned()->default($space->id);
} else {
$table->bigInteger('space_id')->unsigned()->nullable();
}
$table->foreign('space_id')->references('id')
->on('spaces')->onDelete('cascade');
});
Schema::table('contacts_lists', function (Blueprint $table) use ($space) {
$table->bigInteger('space_id')->unsigned()->change();
});
Schema::enableForeignKeyConstraints();
}
public function down(): void
{
Schema::table('contacts_lists', function (Blueprint $table) {
$table->dropForeign('contacts_lists_space_id_foreign');
$table->dropColumn('space_id');
});
}
};

View file

@ -49,7 +49,7 @@
@foreach ($account->contactsLists as $contactsList)
<tr>
<td>
<a href="{{ route('admin.contacts_lists.edit', ['contacts_list_id' => $contactsList->id]) }}">{{ $contactsList->title }}</a>
<a href="{{ route('admin.spaces.contacts_lists.edit', [$space, $contactsList->id]) }}">{{ $contactsList->title }}</a>
<small>{{ $contactsList->contacts_count }} {{ __('Contacts') }}</small>
</td>
<td class="actions">

View file

@ -1,45 +0,0 @@
@extends('layouts.main')
@section('content')
<header>
<h1><i class="ph ph-user-rectangle"></i> {{ __('Contacts Lists') }}</h1>
<a class="btn oppose" href="{{ route('admin.contacts_lists.create') }}">
<i class="ph ph-plus"></i>
{{ __('Create') }}
</a>
</header>
<table>
<thead>
<tr>
@include('parts.column_sort', ['key' => 'title', 'title' => __('Name')])
<th>{{ __('Description') }}</th>
@include('parts.column_sort', ['key' => 'contacts_count', 'title' => __('Contacts')])
@include('parts.column_sort', ['key' => 'updated_at', 'title' => __('Updated')])
</tr>
</thead>
<tbody>
@if ($contacts_lists->isEmpty())
<tr class="empty">
<td colspan="4">{{ __('Empty') }}</td>
</tr>
@endif
@foreach ($contacts_lists as $contacts_list)
<tr>
<td>
<a href="{{ route('admin.contacts_lists.edit', $contacts_list->id) }}">
{{ $contacts_list->title }}
</a>
</td>
<td class="line">{{ $contacts_list->description }}</td>
<td>{{ $contacts_list->contacts_count }}</td>
<td>{{ $contacts_list->updated_at}}</td>
</tr>
@endforeach
</tbody>
</table>
{{ $contacts_lists->links('pagination::bootstrap-4') }}
@endsection

View file

@ -6,10 +6,7 @@
@endsection
@section('content')
<header>
<h1><i class="ph ph-globe-hemisphere-west"></i> {{ $space->name }}</h1>
</header>
@include('admin.space.head')
@include('admin.space.tabs')
<form method="POST"

View file

@ -14,10 +14,7 @@
@endsection
@section('content')
<header>
<h1><i class="ph ph-globe-hemisphere-west"></i> {{ $space->name }}</h1>
</header>
@include('admin.space.head')
@include('admin.space.tabs')
<form method="POST"

View file

@ -1,11 +1,12 @@
@extends('layouts.main')
@section('breadcrumb')
@include('admin.parts.breadcrumb.spaces.show')
<li class="breadcrumb-item">
<a href="{{ route('admin.contacts_lists.index') }}">{{ __('Contacts Lists') }}</a>
<a href="{{ route('admin.spaces.contacts_lists.index', $space) }}">{{ __('Contacts Lists') }}</a>
</li>
<li class="breadcrumb-item">
<a href="{{ route('admin.contacts_lists.edit', $contacts_list->id) }}">{{ $contacts_list->title }}</a>
<a href="{{ route('admin.spaces.contacts_lists.edit', [$space, $contacts_list->id]) }}">{{ $contacts_list->title }}</a>
</li>
<li class="breadcrumb-item active" aria-current="page">{{ __('Add') }}</li>
@endsection
@ -14,9 +15,9 @@
<header>
<h1><i class="ph ph-user-rectangle"></i> {{ $contacts_list->title }}</h1>
<a href="{{ route('admin.contacts_lists.edit', $contacts_list->id) }}" class="btn secondary oppose">{{ __('Cancel') }}</a>
<a href="{{ route('admin.spaces.contacts_lists.edit', [$space, $contacts_list->id]) }}" class="btn secondary oppose">{{ __('Cancel') }}</a>
<form method="POST" action="{{ route('admin.contacts_lists.contacts.store', $contacts_list->id) }}"
<form method="POST" action="{{ route('admin.spaces.contacts_lists.contacts.store', [$space, $contacts_list->id]) }}"
name="contacts_lists_contacts_store" accept-charset="UTF-8">
@csrf
@method('post')
@ -27,7 +28,7 @@
</header>
<div>
<form class="inline" method="POST" action="{{ route('admin.contacts_lists.contacts.search', $params) }}"
<form class="inline" method="POST" action="{{ route('admin.spaces.contacts_lists.contacts.search', [$space] + $params) }}"
accept-charset="UTF-8">
@csrf
<div class="search">
@ -35,14 +36,15 @@
value="{{ request()->get('search', '') }}">
<label for="search">{{ __('Search') }}</label>
</div>
@include('admin.account.parts.forms.select_domain')
<div>
<a href="{{ route('admin.contacts_lists.contacts.add', $contacts_list->id) }}" type="reset"
<div class="large">
<button type="submit" class="btn" title="{{ __('Search') }}">
<i class="ph ph-magnifying-glass"></i>
</button>
<a href="{{ route('admin.spaces.contacts_lists.contacts.add', [$space, $contacts_list->id]) }}" type="reset"
class="btn secondary">{{ __('Reset') }}</a>
<button type="submit" class="btn">{{ __('Search') }}</button>
</div>
<div class="oppose">
<a class="btn"
<a class="btn "
onclick="Utils.clearStorageList('a{{ $contacts_list->id }}'); document.querySelector('form[name=contacts_lists_contacts_store]').submit()">
<i class="ph ph-plus"></i>
Add <span class="list_toggle" data-list-id="a{{ $contacts_list->id }}"></span> contacts
@ -54,7 +56,7 @@
<table>
<thead>
<tr>
<th width="1%">
<th style="width:1%;">
<input type="checkbox" onchange="Utils.toggleAll(this)">
</th>
<th>{{ __('Username') }}</th>

View file

@ -1,19 +1,29 @@
@extends('layouts.main')
@section('breadcrumb')
@include('admin.parts.breadcrumb.spaces.show')
<li class="breadcrumb-item">
<a href="{{ route('admin.contacts_lists.index') }}">{{ __('Contacts Lists') }}</a>
<a href="{{ route('admin.spaces.contacts_lists.index', $space) }}">{{ __('Contacts Lists') }}</a>
</li>
<li class="breadcrumb-item active" aria-current="page">
@if ($contacts_list->id)
{{ __('Edit') }}
@else
{{ __('Create') }}
@endif
</li>
<li class="breadcrumb-item active" aria-current="page">{{ __('Edit') }}</li>
@endsection
@section('content')
@include('admin.space.head')
@include('admin.space.tabs')
<header>
@if ($contacts_list->id)
<h1><i class="ph ph-user-rectangle"></i> {{ $contacts_list->title }}</h1>
<a class="btn secondary oppose" href="{{ route('admin.contacts_lists.delete', $contacts_list->id) }}">
<a class="btn secondary oppose" title="{{ __('Delete') }}"
href="{{ route('admin.spaces.contacts_lists.delete', [$space, $contacts_list->id]) }}">
<i class="ph ph-trash"></i>
{{ __('Delete') }}
</a>
<input form="create_edit_contacts_list" class="btn" type="submit" value="{{ __('Update') }}">
@else
@ -27,7 +37,7 @@
@endif
<form method="POST" id="create_edit_contacts_list"
action="{{ $contacts_list->id ? route('admin.contacts_lists.update', $contacts_list->id) : route('admin.contacts_lists.store') }}"
action="{{ $contacts_list->id ? route('admin.spaces.contacts_lists.update', [$space, $contacts_list->id]) : route('admin.spaces.contacts_lists.store', $space) }}"
accept-charset="UTF-8">
@csrf
@method($contacts_list->id ? 'put' : 'post')
@ -48,12 +58,8 @@
@if ($contacts_list->id)
<hr>
<a class="btn secondary oppose" href="{{ route('admin.contacts_lists.contacts.add', $contacts_list->id) }}">
<i class="ph ph-plus"></i> {{ __('Add contacts') }}
</a>
<form method="POST"
action="{{ route('admin.contacts_lists.contacts.destroy', $contacts_list->id) }}"
action="{{ route('admin.spaces.contacts_lists.contacts.destroy', [$space, $contacts_list->id]) }}"
name="contacts_lists_contacts_destroy" accept-charset="UTF-8">
@csrf
@method('delete')
@ -62,7 +68,7 @@
<input type="hidden" name="contacts_list_id" value="{{ $contacts_list->id }}">
</form>
<form class="inline" method="POST" action="{{ route('admin.contacts_lists.search', $contacts_list->id) }}"
<form class="inline" method="POST" action="{{ route('admin.spaces.contacts_lists.search', [$space, $contacts_list->id]) }}"
name="contacts_lists_contacts_search" accept-charset="UTF-8">
@csrf
@ -71,18 +77,15 @@
value="{{ request()->get('search', '') }}">
<label for="search">{{ __('Search') }}</label>
</div>
@include('admin.account.parts.forms.select_domain')
<div>
<a href="{{ route('admin.contacts_lists.edit', $contacts_list->id) }}" type="reset"
<div class="large">
<button type="submit" class="btn" title="{{ __('Search') }}"><i class="ph ph-magnifying-glass"></i></button>
<a href="{{ route('admin.spaces.contacts_lists.edit', [$space, $contacts_list->id]) }}" type="reset"
class="btn secondary">{{ __('Reset') }}</a>
<button type="submit" class="btn">{{ __('Search') }}</button>
</div>
<div>
<a class="btn tertiary oppose"
onclick="Utils.clearStorageList('d{{ $contacts_list->id }}'); document.querySelector('form[name=contacts_lists_contacts_destroy]').submit()">
<i class="ph ph-trash"></i>
{{ __('Remove') }} <span class="list_toggle" data-list-id="d{{ $contacts_list->id }}"></span>
<a class="btn secondary oppose" href="{{ route('admin.spaces.contacts_lists.contacts.add', [$space, $contacts_list->id]) }}">
<i class="ph ph-plus"></i> {{ __('Add contacts') }}
</a>
</div>
</form>
@ -93,7 +96,14 @@
<th style="width:1%;">
<input type="checkbox" onchange="Utils.toggleAll(this)">
</th>
<th>{{ __('Username') }}</th>
<th>
{{ __('Username') }}
<a class="btn small tertiary oppose"
onclick="Utils.clearStorageList('d{{ $contacts_list->id }}'); document.querySelector('form[name=contacts_lists_contacts_destroy]').submit()">
<i class="ph ph-trash"></i>
{{ __('Remove') }} <span class="list_toggle" data-list-id="d{{ $contacts_list->id }}"></span>
</a>
</th>
</tr>
</thead>
<tbody>

View file

@ -1,19 +1,24 @@
@extends('layouts.main')
@section('breadcrumb')
@include('admin.parts.breadcrumb.spaces.integration')
<li class="breadcrumb-item">
<a href="{{ route('admin.contacts_lists.index') }}">{{ __('Contacts Lists') }}</a>
<a href="{{ route('admin.spaces.contacts_lists.index', $space) }}">{{ __('Contacts Lists') }}</a>
</li>
<li class="breadcrumb-item active" aria-current="page">{{ __('Delete') }}</li>
@endsection
@section('content')
@include('admin.space.head')
@include('admin.space.tabs')
<header>
<h1><i class="ph ph-trash"></i> {{ __('Delete') }}</h1>
<a href="{{ route('admin.contacts_lists.edit', $contacts_list->id) }}" class="btn secondary oppose">{{ __('Cancel') }}</a>
<a href="{{ route('admin.spaces.contacts_lists.edit', [$space, $contacts_list->id]) }}" class="btn secondary oppose">{{ __('Cancel') }}</a>
<input form="delete" class="btn" type="submit" value="{{ __('Delete') }}">
</header>
<form id="delete" method="POST" action="{{ route('admin.contacts_lists.destroy', $contacts_list->id) }}" accept-charset="UTF-8">
<form id="delete" method="POST" action="{{ route('admin.spaces.contacts_lists.destroy', [$space, $contacts_list->id]) }}" accept-charset="UTF-8">
@csrf
@method('delete')

View file

@ -0,0 +1,51 @@
@extends('layouts.main')
@section('breadcrumb')
@include('admin.parts.breadcrumb.spaces.show')
<li class="breadcrumb-item active" aria-current="page">{{ __('Contacts Lists') }}</li>
@endsection
@section('content')
@include('admin.space.head')
@include('admin.space.tabs')
<header>
<h1><i class="ph ph-user-rectangle"></i> {{ __('Contacts Lists') }}</h1>
<a class="btn oppose" href="{{ route('admin.spaces.contacts_lists.create', $space) }}">
<i class="ph ph-plus"></i>
{{ __('Create') }}
</a>
</header>
<table>
<thead>
<tr>
@include('parts.column_sort', ['key' => 'title', 'title' => __('Name')])
<th>{{ __('Description') }}</th>
@include('parts.column_sort', ['key' => 'contacts_count', 'title' => __('Contacts')])
@include('parts.column_sort', ['key' => 'updated_at', 'title' => __('Updated')])
</tr>
</thead>
<tbody>
@if ($contacts_lists->isEmpty())
<tr class="empty">
<td colspan="4">{{ __('Empty') }}</td>
</tr>
@endif
@foreach ($contacts_lists as $contacts_list)
<tr>
<td>
<a href="{{ route('admin.spaces.contacts_lists.edit', [$space, $contacts_list->id]) }}">
{{ $contacts_list->title }}
</a>
</td>
<td class="line">{{ $contacts_list->description }}</td>
<td>{{ $contacts_list->contacts_count }}</td>
<td>{{ $contacts_list->updated_at}}</td>
</tr>
@endforeach
</tbody>
</table>
{{ $contacts_lists->links('pagination::bootstrap-4') }}
@endsection

View file

@ -6,10 +6,7 @@
@endsection
@section('content')
<header>
<h1><i class="ph ph-globe-hemisphere-west"></i> {{ $space->name }}</h1>
</header>
@include('admin.space.head')
@include('admin.space.tabs')
<form method="POST"

View file

@ -0,0 +1,3 @@
<header>
<h1><i class="ph ph-globe-hemisphere-west"></i> {{ $space->name }}</h1>
</header>

View file

@ -5,10 +5,7 @@
@endsection
@section('content')
<header>
<h1><i class="ph ph-globe-hemisphere-west"></i> {{ $space->name }}</h1>
</header>
@include('admin.space.head')
@include('admin.space.tabs')
<div class="grid third">

View file

@ -6,9 +6,11 @@
$items[route('admin.spaces.administration', $space->id)] = __('Administration');
$items[route('admin.spaces.edit', $space->id)] = __('App Configuration');
$items[route('admin.spaces.integration', $space->id)] = __('Integration');
$items[route('admin.spaces.contacts_lists.index', $space->id)] = __('Contacts Lists');
} else if (auth()->user()->admin) {
$items[route('admin.spaces.me')] = __('Information');
$items[route('admin.spaces.integration', $space->id)] = __('Integration');
$items[route('admin.spaces.contacts_lists.index', $space->id)] = __('Contacts Lists');
}
$items[route('admin.spaces.configuration', $space->id)] = __('Configuration');

View file

@ -10,7 +10,6 @@
}
$items['admin.account.index'] = ['title' => __('Users'), 'icon' => 'users'];
$items['admin.contacts_lists.index'] = ['title' => __('Contacts Lists'), 'icon' => 'user-rectangle'];
$items['admin.statistics.show'] = ['title' => __('Statistics'), 'icon' => 'chart-donut'];
$items['admin.api_keys.index'] = ['title' => __('Settings'), 'icon' => 'gear'];
}

View file

@ -37,10 +37,10 @@ use App\Http\Controllers\Api\Admin\Account\CreationTokenController as AdminCreat
use App\Http\Controllers\Api\Admin\Account\DictionaryController;
use App\Http\Controllers\Api\Admin\Account\TypeController;
use App\Http\Controllers\Api\Admin\AccountController as AdminAccountController;
use App\Http\Controllers\Api\Admin\ContactsListController;
use App\Http\Controllers\Api\Admin\ExternalAccountController;
use App\Http\Controllers\Api\Admin\MessageController;
use App\Http\Controllers\Api\Admin\Space\CardDavServerController;
use App\Http\Controllers\Api\Admin\Space\ContactsListController;
use App\Http\Controllers\Api\Admin\Space\EmailServerController;
use App\Http\Controllers\Api\Admin\SpaceController;
use App\Http\Controllers\Api\Admin\VcardsStorageController as AdminVcardsStorageController;

View file

@ -32,7 +32,6 @@ use App\Http\Controllers\Account\ProvisioningController;
use App\Http\Controllers\Account\RecoveryController;
use App\Http\Controllers\Account\RegisterController;
use App\Http\Controllers\Account\VcardsStorageController;
use App\Http\Controllers\Admin\AccountController as AdminAccountController;
use App\Http\Controllers\Admin\Account\AccountTypeController;
use App\Http\Controllers\Admin\Account\ActionController;
use App\Http\Controllers\Admin\Account\ActivityController;
@ -43,15 +42,16 @@ use App\Http\Controllers\Admin\Account\DictionaryController;
use App\Http\Controllers\Admin\Account\ImportController;
use App\Http\Controllers\Admin\Account\StatisticsController as AdminAccountStatisticsController;
use App\Http\Controllers\Admin\Account\TypeController;
use App\Http\Controllers\Admin\AccountController as AdminAccountController;
use App\Http\Controllers\Admin\ApiKeyController as AdminApiKeyController;
use App\Http\Controllers\Admin\ContactsListContactController;
use App\Http\Controllers\Admin\ContactsListController;
use App\Http\Controllers\Admin\ExternalAccountController;
use App\Http\Controllers\Admin\PhoneCountryController;
use App\Http\Controllers\Admin\ProvisioningEmailController;
use App\Http\Controllers\Admin\ResetPasswordEmailController;
use App\Http\Controllers\Admin\Space\EmailServerController;
use App\Http\Controllers\Admin\Space\CardDavServerController;
use App\Http\Controllers\Admin\Space\ContactsListContactController;
use App\Http\Controllers\Admin\Space\ContactsListController;
use App\Http\Controllers\Admin\Space\EmailServerController;
use App\Http\Controllers\Admin\SpaceController;
use App\Http\Controllers\Admin\StatisticsController;
use Illuminate\Support\Facades\Route;
@ -179,6 +179,24 @@ Route::middleware(['feature.web_panel_enabled'])->group(function () {
});
Route::resource('{space}/carddavs', CardDavServerController::class, ['except' => ['index', 'show']]);
Route::get('{space}/carddavs/{carddav}/delete', [CardDavServerController::class, 'delete'])->name('carddavs.delete');
Route::name('contacts_lists.')->prefix('{space}/contacts_lists')->controller(ContactsListController::class)->group(function () {
Route::get('/', 'index')->name('index');
Route::get('create', 'create')->name('create');
Route::post('/', 'store')->name('store');
Route::post('{contacts_list_id}/search', 'search')->name('search');
Route::get('{contacts_list_id}/edit', 'edit')->name('edit');
Route::put('{contacts_list_id}', 'update')->name('update');
Route::get('{contacts_list_id}/delete', 'delete')->name('delete');
Route::delete('{contacts_list_id}', 'destroy')->name('destroy');
Route::name('contacts.')->prefix('{contacts_list_id}/contacts')->controller(ContactsListContactController::class)->group(function () {
Route::get('add', 'add')->name('add');
Route::post('search', 'search')->name('search');
Route::post('/', 'store')->name('store');
Route::delete('/', 'destroy')->name('destroy');
});
});
});
Route::name('api_keys.')->prefix('api_keys')->controller(AdminApiKeyController::class)->group(function () {
@ -321,23 +339,5 @@ Route::middleware(['feature.web_panel_enabled'])->group(function () {
Route::post('/', 'edit')->name('edit');
});
});
Route::name('contacts_lists.')->prefix('contacts_lists')->controller(ContactsListController::class)->group(function () {
Route::get('/', 'index')->name('index');
Route::get('create', 'create')->name('create');
Route::post('/', 'store')->name('store');
Route::post('{contacts_list_id}/search', 'search')->name('search');
Route::get('{contacts_list_id}/edit', 'edit')->name('edit');
Route::put('{contacts_list_id}', 'update')->name('update');
Route::get('{contacts_list_id}/delete', 'delete')->name('delete');
Route::delete('{contacts_list_id}', 'destroy')->name('destroy');
Route::name('contacts.')->prefix('{contacts_list_id}/contacts')->controller(ContactsListContactController::class)->group(function () {
Route::get('add', 'add')->name('add');
Route::post('search', 'search')->name('search');
Route::post('/', 'store')->name('store');
Route::delete('/', 'destroy')->name('destroy');
});
});
});
});