Browse Source

Merge branch 'master' into beatmapset-rank

pull/4481/head
bakaneko 3 months ago
parent
commit
7faf0f3be8
No account linked to committer's email address

+ 24
- 0
app/Http/Controllers/LegacyInterOpController.php View File

@@ -25,7 +25,9 @@ use App\Libraries\Session\Store as SessionStore;
25 25
 use App\Libraries\UserBestScoresCheck;
26 26
 use App\Models\Beatmap;
27 27
 use App\Models\Beatmapset;
28
+use App\Models\Forum;
28 29
 use App\Models\NewsPost;
30
+use App\Models\Notification;
29 31
 use App\Models\User;
30 32
 use Illuminate\Foundation\Bus\DispatchesJobs;
31 33
 
@@ -43,6 +45,28 @@ class LegacyInterOpController extends Controller
43 45
         return ['success' => true];
44 46
     }
45 47
 
48
+    public function generateNotification()
49
+    {
50
+        $params = request()->all();
51
+
52
+        if (!isset($params['name'])) {
53
+            abort(422, 'missing notification name');
54
+        }
55
+
56
+        if ($params['name'] === Notification::FORUM_TOPIC_REPLY) {
57
+            $post = Forum\Post::find($params['post_id'] ?? null);
58
+            $user = optional($post)->user;
59
+
60
+            if ($post === null || $user === null) {
61
+                abort(422, 'post is missing or it contains invalid user');
62
+            }
63
+
64
+            broadcast_notification($params['name'], $post, $user);
65
+
66
+            return response(null, 204);
67
+        }
68
+    }
69
+
46 70
     public function news()
47 71
     {
48 72
         $newsPosts = NewsPost::default()->limit(5)->get();

+ 5
- 1
app/Http/Controllers/NotificationsController.php View File

@@ -38,16 +38,20 @@ class NotificationsController extends Controller
38 38
 
39 39
     public function index()
40 40
     {
41
+        $withRead = get_bool(request('with_read')) ?? false;
41 42
         $hasMore = false;
42 43
         $userNotificationsQuery = auth()
43 44
             ->user()
44 45
             ->userNotifications()
45 46
             ->with('notification.notifiable')
46 47
             ->with('notification.source')
47
-            ->where('is_read', false)
48 48
             ->orderBy('notification_id', 'DESC')
49 49
             ->limit(static::LIMIT);
50 50
 
51
+        if (!$withRead) {
52
+            $userNotificationsQuery->where('is_read', false);
53
+        }
54
+
51 55
         $maxId = get_int(request('max_id'));
52 56
         if (isset($maxId)) {
53 57
             $userNotificationsQuery->where('notification_id', '<=', $maxId);

+ 1
- 1
app/Http/Controllers/UsersController.php View File

@@ -365,7 +365,7 @@ class UsersController extends Controller
365 365
 
366 366
     private function sanitizedLimitParam()
367 367
     {
368
-        return clamp(get_int(request('limit')) ?? 5, 1, 21);
368
+        return clamp(get_int(request('limit')) ?? 5, 1, 51);
369 369
     }
370 370
 
371 371
     private function getExtra($user, $page, $options, $perPage = 10, $offset = 0)

+ 1
- 0
app/Libraries/OsuAuthorize.php View File

@@ -364,6 +364,7 @@ class OsuAuthorize
364 364
     public function checkBeatmapsetNominate($user, $beatmapset)
365 365
     {
366 366
         $this->ensureLoggedIn($user);
367
+        $this->ensureCleanRecord($user);
367 368
 
368 369
         static $prefix = 'beatmap_discussion.nominate.';
369 370
 

+ 9
- 1
resources/assets/coffee/react/_components/comment.coffee View File

@@ -427,7 +427,14 @@ export class Comment extends React.PureComponent
427 427
     @setState showNewReply: !@state.showNewReply
428 428
 
429 429
 
430
-  voteToggle: =>
430
+  voteToggle: (e) =>
431
+    target = e.target
432
+
433
+    if !currentUser.id?
434
+      userLogin.show target
435
+
436
+      return
437
+
431 438
     @setState postingVote: true
432 439
 
433 440
     if @hasVoted()
@@ -447,6 +454,7 @@ export class Comment extends React.PureComponent
447 454
       $.publish "commentVote:#{voteAction}", id: @props.comment.id
448 455
     .fail (xhr, status) =>
449 456
       return if status == 'abort'
457
+      return $(target).trigger('ajax:error', [xhr, status]) if xhr.status == 401
450 458
 
451 459
       osu.ajaxError xhr
452 460
 

+ 0
- 2
resources/assets/coffee/react/beatmap-discussions/discussion.coffee View File

@@ -137,8 +137,6 @@ export class Discussion extends React.PureComponent
137 137
 
138 138
 
139 139
   doVote: (e) =>
140
-    downvoting = e.currentTarget.dataset.score == '-1'
141
-
142 140
     LoadingOverlay.show()
143 141
 
144 142
     @voteXhr?.abort()

+ 1
- 1
resources/assets/coffee/react/profile-page/main.coffee View File

@@ -296,7 +296,7 @@ export class Main extends React.PureComponent
296 296
         component: AccountStanding
297 297
 
298 298
 
299
-  showMore: (e, {name, url, perPage = 20}) =>
299
+  showMore: (e, {name, url, perPage = 50}) =>
300 300
     offset = @state[name].length
301 301
 
302 302
     paginationState = _.cloneDeep @state.showMorePagination

+ 40
- 7
resources/assets/lib/notification-widget/worker.ts View File

@@ -73,6 +73,8 @@ export default class Worker {
73 73
   userId: number | null = null;
74 74
   @observable private active: boolean = false;
75 75
   @observable private items = observable.map<number, Notification>();
76
+  private refreshing = false;
77
+  private needsRefresh = false;
76 78
   private timeout: TimeoutCollection = {};
77 79
   private endpoint?: string;
78 80
   private ws: WebSocket | null | undefined;
@@ -82,7 +84,6 @@ export default class Worker {
82 84
     this.active = this.userId != null;
83 85
     this.updatePmNotification();
84 86
     this.loadMore();
85
-    this.connectWebSocket();
86 87
     $(document).on('turbolinks:load', this.updatePmNotification);
87 88
   }
88 89
 
@@ -91,10 +92,6 @@ export default class Worker {
91 92
       return;
92 93
     }
93 94
 
94
-    if (this.endpoint == null) {
95
-      return;
96
-    }
97
-
98 95
     if (this.timeout.connectWebSocket != null) {
99 96
       clearTimeout(this.timeout.connectWebSocket);
100 97
     }
@@ -112,6 +109,7 @@ export default class Worker {
112 109
       endpoint = `${protocol}//${window.location.host}${endpoint}`;
113 110
     }
114 111
     this.ws = new WebSocket(`${endpoint}?csrf=${token}`);
112
+    this.ws.onopen = () => this.refresh();
115 113
     this.ws.onclose = this.delayedConnectWebSocket;
116 114
     this.ws.onmessage = this.handleNewEvent;
117 115
   }
@@ -122,7 +120,10 @@ export default class Worker {
122 120
     }
123 121
 
124 122
     this.ws = null;
125
-    this.timeout.connectWebSocket = setTimeout(this.connectWebSocket, 10000);
123
+    this.timeout.connectWebSocket = setTimeout(() => {
124
+      this.needsRefresh = true;
125
+      this.connectWebSocket();
126
+    }, 10000);
126 127
   }
127 128
 
128 129
   delayedRetryInitialLoadMore = () => {
@@ -212,6 +213,38 @@ export default class Worker {
212 213
     }
213 214
   }
214 215
 
216
+  refresh = (maxId?: number) => {
217
+    if (!this.active || this.refreshing || !this.needsRefresh) {
218
+      return;
219
+    }
220
+
221
+    this.refreshing = true;
222
+
223
+    const params = { with_read: true, max_id: maxId };
224
+
225
+    this.xhr.refresh = $.get(laroute.route('notifications.index'), params)
226
+      .always(() => {
227
+        this.refreshing = false;
228
+        this.needsRefresh = false;
229
+      }).done((bundleJson: NotificationBundleJson) => {
230
+        const oldestNotification = _.minBy(bundleJson.notifications, 'id');
231
+        const minLoadedId = this.minLoadedId;
232
+
233
+        bundleJson.notifications.forEach(this.updateFromServer);
234
+        this.actualUnreadCount = bundleJson.unread_count;
235
+        this.hasMore = bundleJson.has_more;
236
+
237
+        if (bundleJson.has_more &&
238
+          oldestNotification != null &&
239
+          minLoadedId != null &&
240
+          oldestNotification.id > minLoadedId
241
+        ) {
242
+          this.needsRefresh = true;
243
+          this.refresh(oldestNotification.id - 1);
244
+        }
245
+      });
246
+  }
247
+
215 248
   sendMarkRead = (ids: number[]) => {
216 249
     const key = `sendMarkRead:${ids.join(':')}`;
217 250
 
@@ -298,6 +331,6 @@ export default class Worker {
298 331
       ret++;
299 332
     }
300 333
 
301
-    return ret;
334
+    return Math.max(ret, 0);
302 335
   }
303 336
 }

+ 1
- 1
resources/assets/lib/osu-core.ts View File

@@ -62,7 +62,7 @@ export default class OsuCore {
62 62
     $.subscribe('user:update', this.setUser);
63 63
   }
64 64
 
65
-  private setUser(event: JQuery.Event, user: UserJSON) {
65
+  private setUser = (event: JQuery.Event, user: UserJSON) => {
66 66
     this.dataStore.userStore.getOrCreate(user.id, user);
67 67
   }
68 68
 }

+ 1
- 0
routes/web.php View File

@@ -391,6 +391,7 @@ Route::group(['as' => 'api.', 'prefix' => 'api', 'middleware' => ['auth:api', 'r
391 391
 
392 392
 // Callbacks for legacy systems to interact with
393 393
 Route::group(['prefix' => '_lio', 'middleware' => 'lio'], function () {
394
+    Route::post('generate-notification', 'LegacyInterOpController@generateNotification');
394 395
     Route::post('/refresh-beatmapset-cache/{beatmapset}', 'LegacyInterOpController@refreshBeatmapsetCache');
395 396
     Route::post('/regenerate-beatmapset-covers/{beatmapset}', 'LegacyInterOpController@regenerateBeatmapsetCovers');
396 397
     Route::post('/user-best-scores-check/{user}', 'LegacyInterOpController@userBestScoresCheck');

Loading…
Cancel
Save