1<?php
2
3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0.
4// See the LICENCE file in the repository root for full licence text.
5
6namespace App\Http\Controllers;
7
8use App\Libraries\Notification\BatchIdentities;
9use App\Libraries\NotificationsBundle;
10use App\Models\UserNotification;
11
12/**
13 * @group Notification
14 */
15class NotificationsController extends Controller
16{
17 const LIMIT = 51;
18
19 public function __construct()
20 {
21 parent::__construct();
22
23 $this->middleware('auth');
24 }
25
26 public function batchDestroy()
27 {
28 UserNotification::batchDestroy(
29 auth()->id(),
30 BatchIdentities::fromParams(request()->all())
31 );
32
33 return response(null, 204);
34 }
35
36 public function endpoint()
37 {
38 return ['url' => $this->endpointUrl()];
39 }
40
41 /**
42 * Get Notifications
43 *
44 * This endpoint returns a list of the user's unread notifications. Sorted descending by `id` with limit of 50.
45 *
46 * ---
47 *
48 * ### Response Format
49 *
50 * Returns an object containing [Notification](#notification) and other related attributes.
51 *
52 * Field | Type
53 * --------------------- | ---------------------------------------------------
54 * has_more | boolean whether or not there are more notifications
55 * notifications | array of [Notification](#notification)
56 * unread_count | total unread notifications
57 * notification_endpoint | url to connect to websocket server
58 *
59 * @queryParam max_id Maximum `id` fetched. Can be used to load earlier notifications. Defaults to no limit (fetch latest notifications)
60 *
61 * @response {
62 * "has_more": true,
63 * "notifications": [
64 * {
65 * "id": 1,
66 * "name": "forum_topic_reply",
67 * "created_at": "2019-04-24T07:12:43+00:00",
68 * "object_type": "forum_topic",
69 * "object_id": 1,
70 * "source_user_id": 1,
71 * "is_read": false,
72 * "details": {
73 * "title": "A topic",
74 * "post_id": 2,
75 * "username": "User",
76 * "cover_url": "https://..."
77 * }
78 * }
79 * ],
80 * "unread_count": 100,
81 * "notification_endpoint": "wss://notify.ppy.sh"
82 * }
83 */
84 public function index()
85 {
86 $bundle = new NotificationsBundle(auth()->user(), request()->all());
87 $bundleJson = $bundle->toArray();
88
89 if (is_json_request()) {
90 $bundleJson['notification_endpoint'] = $this->endpointUrl();
91
92 return response($bundleJson)->header('Cache-Control', 'no-store');
93 }
94
95 return ext_view('notifications.index', compact('bundleJson'));
96 }
97
98 /**
99 * Mark Notifications as Read
100 *
101 * This endpoint allows you to mark notifications read.
102 *
103 * ---
104 *
105 * ### Response Format
106 *
107 * _empty response_
108 *
109 * @bodyParam identities[].category string Notification category. Example: beatmapset_state
110 * @bodyParam identities[].object_id string Id of the object triggered the notification. Example: 1
111 * @bodyParam identities[].object_type string Type of the object triggered the notification. Example: beatmapset
112 * @bodyParam notifications[].category string Notification category. Example: beatmapset_state
113 * @bodyParam notifications[].id integer Id of notifications to be marked as read. Example: 1
114 * @bodyParam notifications[].object_id string Id of the object triggered the notification. Example: 1
115 * @bodyParam notifications[].object_type string Type of the object triggered the notification. Example: beatmapset
116 *
117 * @response 204
118 */
119 public function markRead()
120 {
121 UserNotification::batchMarkAsRead(
122 auth()->user(),
123 BatchIdentities::fromParams(request()->all())
124 );
125
126 return response(null, 204);
127 }
128
129 private function endpointUrl()
130 {
131 $url = $GLOBALS['cfg']['osu']['notification']['endpoint'];
132
133 if (($url[0] ?? null) === '/') {
134 $host = request()->getHttpHost();
135 $protocol = request()->secure() ? 'wss' : 'ws';
136 $url = "{$protocol}://{$host}{$url}";
137 }
138
139 return $url;
140 }
141}