Passed
Push — master ( 5aa5e3...07d8b3 )
by Darko
09:19
created

InvitationController   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 293
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 27
eloc 143
dl 0
loc 293
rs 10
c 1
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A resend() 0 18 3
A create() 0 44 2
B show() 0 58 8
A stats() 0 5 1
A destroy() 0 18 3
A store() 0 30 3
A cleanup() 0 12 2
A index() 0 56 4
A __construct() 0 5 1
1
<?php
2
3
namespace App\Http\Controllers;
4
5
use App\Models\Invitation;
6
use App\Services\InvitationService;
7
use Illuminate\Http\JsonResponse;
8
use Illuminate\Http\RedirectResponse;
9
use Illuminate\Http\Request;
10
11
class InvitationController extends BasePageController
12
{
13
    protected InvitationService $invitationService;
14
15
    public function __construct(InvitationService $invitationService)
16
    {
17
        parent::__construct();
18
        $this->invitationService = $invitationService;
19
        $this->middleware('auth')->except(['show', 'accept']);
20
    }
21
22
    /**
23
     * Display a listing of the user's invitations
24
     */
25
    public function index(Request $request): void
26
    {
27
        $this->setPreferences();
28
29
        $status = $request->get('status');
30
        $user = auth()->user();
31
32
        $invitations = $this->invitationService->getUserInvitations($user->id, $status);
33
        $stats = $this->invitationService->getUserInvitationStats($user->id);
34
35
        // Convert paginated results to array for Smarty
36
        $invitationsArray = [];
37
        foreach ($invitations as $invitation) {
38
            $invitationData = $invitation->toArray();
39
40
            // Add related user data
41
            if ($invitation->usedBy) {
42
                $invitationData['used_by_user'] = $invitation->usedBy->toArray();
43
            }
44
45
            // Convert timestamps for Smarty
46
            $invitationData['created_at'] = strtotime($invitation->created_at);
47
            $invitationData['expires_at'] = strtotime($invitation->expires_at);
48
            if ($invitation->used_at) {
49
                $invitationData['used_at'] = strtotime($invitation->used_at);
50
            }
51
52
            $invitationsArray[] = $invitationData;
53
        }
54
55
        $this->smarty->assign([
56
            'invitations' => $invitationsArray,
57
            'stats' => $stats,
58
            'status' => $status,
59
            'pagination_links' => $invitations->links(),
60
            'csrf_token' => csrf_token(),
61
        ]);
62
63
        // Set meta information
64
        $meta_title = 'My Invitations';
65
        $meta_keywords = 'invitations,invite,users,manage';
66
        $meta_description = 'Manage your sent invitations and send new invitations to friends';
67
68
        // Fetch the template content
69
        $content = $this->smarty->fetch('invitations_index.tpl');
70
71
        // Assign content and meta data for final rendering
72
        $this->smarty->assign([
73
            'content' => $content,
74
            'meta_title' => $meta_title,
75
            'meta_keywords' => $meta_keywords,
76
            'meta_description' => $meta_description,
77
        ]);
78
79
        // Render the page with proper styling
80
        $this->pagerender();
81
    }
82
83
    /**
84
     * Show the form for creating a new invitation
85
     */
86
    public function create(): void
87
    {
88
        $this->setPreferences();
89
90
        $user = auth()->user();
91
92
        // Calculate available invites (total - active pending invitations)
93
        $activeInvitations = Invitation::where('invited_by', $user->id)
94
            ->where('is_active', true)
95
            ->where('used_at', null)
96
            ->where('expires_at', '>', now())
97
            ->count();
98
99
        $availableInvites = $user->invites - $activeInvitations;
100
101
        $this->smarty->assign([
102
            'user_roles' => config('nntmux.user_roles', []),
103
            'csrf_token' => csrf_token(),
104
            'old' => old(),
105
            'errors' => session('errors') ? session('errors')->getBag('default')->getMessages() : [],
106
            'user_invites_left' => $availableInvites,
107
            'user_invites_total' => $user->invites,
108
            'user_invites_pending' => $activeInvitations,
109
            'can_send_invites' => $availableInvites > 0,
110
        ]);
111
112
        // Set meta information
113
        $meta_title = 'Send New Invitation';
114
        $meta_keywords = 'invitation,invite,send,new,user';
115
        $meta_description = 'Send a new invitation to invite someone to join the site';
116
117
        // Fetch the template content
118
        $content = $this->smarty->fetch('invitations_create.tpl');
119
120
        // Assign content and meta data for final rendering
121
        $this->smarty->assign([
122
            'content' => $content,
123
            'meta_title' => $meta_title,
124
            'meta_keywords' => $meta_keywords,
125
            'meta_description' => $meta_description,
126
        ]);
127
128
        // Render the page with proper styling
129
        $this->pagerender();
130
    }
131
132
    /**
133
     * Store a newly created invitation
134
     */
135
    public function store(Request $request): RedirectResponse
136
    {
137
        $request->validate([
138
            'email' => 'required|email|unique:users,email',
139
            'expiry_days' => 'sometimes|integer|min:1|max:30',
140
            'role' => 'sometimes|integer|in:'.implode(',', array_keys(config('nntmux.user_roles', []))),
141
        ]);
142
143
        try {
144
            $expiryDays = $request->get('expiry_days', Invitation::DEFAULT_INVITE_EXPIRY_DAYS);
145
            $metadata = [];
146
147
            if ($request->has('role')) {
148
                $metadata['role'] = $request->get('role');
149
            }
150
151
            $invitation = $this->invitationService->createAndSendInvitation(
0 ignored issues
show
Unused Code introduced by
The assignment to $invitation is dead and can be removed.
Loading history...
152
                $request->email,
153
                auth()->id(),
154
                $expiryDays,
155
                $metadata
156
            );
157
158
            return redirect()->route('invitations.index')
159
                ->with('success', 'Invitation sent successfully to '.$request->email);
160
161
        } catch (\Exception $e) {
162
            return redirect()->back()
163
                ->withInput()
164
                ->with('error', $e->getMessage());
165
        }
166
    }
167
168
    /**
169
     * Display the specified invitation
170
     */
171
    public function show(string $token): void
172
    {
173
        // For public invitation page, we need to handle both logged in and guest users
174
        if (auth()->check()) {
175
            $this->setPreferences();
176
        } else {
177
            // Set up basic Smarty configuration for guests
178
            $this->smarty->setTemplateDir([
179
                'user' => config('ytake-laravel-smarty.template_path').'/Gentele',
180
                'shared' => config('ytake-laravel-smarty.template_path').'/shared',
181
                'default' => config('ytake-laravel-smarty.template_path').'/Gentele',
182
            ]);
183
184
            $this->smarty->assign([
185
                'isadmin' => false,
186
                'ismod' => false,
187
                'loggedin' => false,
188
                'theme' => 'Gentele',
189
                'site' => $this->settings,
190
            ]);
191
        }
192
193
        $preview = $this->invitationService->getInvitationPreview($token);
194
195
        // Convert timestamps for Smarty
196
        if ($preview && isset($preview['expires_at'])) {
197
            $preview['expires_at'] = strtotime($preview['expires_at']);
198
        }
199
200
        // Add role name if role is set
201
        if ($preview && isset($preview['metadata']['role'])) {
202
            $roles = config('nntmux.user_roles', []);
203
            $preview['role_name'] = $roles[$preview['metadata']['role']] ?? 'Default';
204
        }
205
206
        $this->smarty->assign([
207
            'preview' => $preview,
208
            'token' => $token,
209
        ]);
210
211
        // Set meta information
212
        $meta_title = $preview ? 'Invitation to Join' : 'Invalid Invitation';
213
        $meta_keywords = 'invitation,join,register,signup';
214
        $meta_description = $preview ? 'You have been invited to join our community' : 'This invitation link is invalid or expired';
215
216
        // Fetch the template content
217
        $content = $this->smarty->fetch('invitations_show.tpl');
218
219
        // Assign content and meta data for final rendering
220
        $this->smarty->assign([
221
            'content' => $content,
222
            'meta_title' => $meta_title,
223
            'meta_keywords' => $meta_keywords,
224
            'meta_description' => $meta_description,
225
        ]);
226
227
        // Render the page with proper styling
228
        $this->pagerender();
229
    }
230
231
    /**
232
     * Resend an invitation
233
     */
234
    public function resend(int $id): RedirectResponse
235
    {
236
        try {
237
            $invitation = Invitation::findOrFail($id);
238
239
            // Check if user owns this invitation
240
            if ($invitation->invited_by !== auth()->id()) {
0 ignored issues
show
Bug introduced by
The property invited_by does not seem to exist on Illuminate\Database\Eloq...gHasThroughRelationship.
Loading history...
241
                abort(403, 'Unauthorized');
242
            }
243
244
            $this->invitationService->resendInvitation($id);
245
246
            return redirect()->route('invitations.index')
247
                ->with('success', 'Invitation resent successfully');
248
249
        } catch (\Exception $e) {
250
            return redirect()->back()
251
                ->with('error', $e->getMessage());
252
        }
253
    }
254
255
    /**
256
     * Cancel an invitation
257
     */
258
    public function destroy(int $id): RedirectResponse
259
    {
260
        try {
261
            $invitation = Invitation::findOrFail($id);
262
263
            // Check if user owns this invitation
264
            if ($invitation->invited_by !== auth()->id()) {
0 ignored issues
show
Bug introduced by
The property invited_by does not seem to exist on Illuminate\Database\Eloq...gHasThroughRelationship.
Loading history...
265
                abort(403, 'Unauthorized');
266
            }
267
268
            $this->invitationService->cancelInvitation($id);
269
270
            return redirect()->route('invitations.index')
271
                ->with('success', 'Invitation cancelled successfully');
272
273
        } catch (\Exception $e) {
274
            return redirect()->back()
275
                ->with('error', $e->getMessage());
276
        }
277
    }
278
279
    /**
280
     * Get invitation statistics (API endpoint)
281
     */
282
    public function stats(): JsonResponse
283
    {
284
        $stats = $this->invitationService->getUserInvitationStats(auth()->id());
285
286
        return response()->json($stats);
287
    }
288
289
    /**
290
     * Clean up expired invitations (admin only)
291
     */
292
    public function cleanup(): JsonResponse
293
    {
294
        // Check if user is admin
295
        if (! auth()->user()->hasRole('admin')) {
296
            abort(403, 'Unauthorized');
297
        }
298
299
        $cleanedCount = $this->invitationService->cleanupExpiredInvitations();
300
301
        return response()->json([
302
            'message' => "Cleaned up {$cleanedCount} expired invitations",
303
            'count' => $cleanedCount,
304
        ]);
305
    }
306
}
307