Skip to content

Commit

Permalink
Merge branch 'master' into news-announcements
Browse files Browse the repository at this point in the history
  • Loading branch information
notbakaneko authored Oct 7, 2024
2 parents 254ce39 + 659347f commit 1ae898e
Show file tree
Hide file tree
Showing 71 changed files with 322 additions and 198 deletions.
5 changes: 4 additions & 1 deletion app/Http/Controllers/AccountController.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,11 @@ public function __construct()
'updateOptions',
]]);

$this->middleware('throttle:60,10', ['only' => [
$this->middleware('throttle:3,5', ['only' => [
'reissueCode',
]]);

$this->middleware('throttle:60,10', ['only' => [
'updateEmail',
'updatePassword',
'verify',
Expand Down
48 changes: 48 additions & 0 deletions app/Http/Controllers/Chat/Channels/UsersController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the GNU Affero General Public License v3.0.
// See the LICENCE file in the repository root for full licence text.

namespace App\Http\Controllers\Chat\Channels;

use App\Http\Controllers\Chat\Controller;
use App\Models\Chat\Channel;
use App\Models\Chat\UserChannel;
use App\Models\User;
use App\Transformers\UserCompactTransformer;

class UsersController extends Controller
{
public function index($channelId)
{
$channel = Channel::findOrFail($channelId);

if (!priv_check('ChatChannelListUsers', $channel)->can()) {
return [
'users' => [],
...cursor_for_response(null),
];
}

$channel = Channel::findOrFail($channelId);
$cursorHelper = UserChannel::makeDbCursorHelper();
[$userChannels, $hasMore] = $channel
->userChannels()
->select('user_id')
->limit(UserChannel::PER_PAGE)
->cursorSort($cursorHelper, cursor_from_params(\Request::all()))
->getWithHasMore();
$users = User
::with(UserCompactTransformer::CARD_INCLUDES_PRELOAD)
->find($userChannels->pluck('user_id'));

return [
'users' => json_collection(
$users,
new UserCompactTransformer(),
UserCompactTransformer::CARD_INCLUDES,
),
...cursor_for_response($cursorHelper->next($userChannels, $hasMore)),
];
}
}
2 changes: 1 addition & 1 deletion app/Libraries/SessionVerification/State.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

class State
{
private const KEY_VALID_DURATION = 5 * 3600;
private const KEY_VALID_DURATION = 600;

public readonly CarbonImmutable $expiresAt;
public readonly string $key;
Expand Down
8 changes: 1 addition & 7 deletions app/Models/BeatmapDiscussion.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,8 @@ class BeatmapDiscussion extends Model
// FIXME: This and other static search functions should be extracted out.
public static function search($rawParams = [])
{
$pagination = pagination(cursor_from_params($rawParams) ?? $rawParams);
[$query, $params] = static::searchQueryAndParams(cursor_from_params($rawParams) ?? $rawParams);

$params = [
'limit' => $pagination['limit'],
'page' => $pagination['page'],
];

$query = static::limit($params['limit'])->offset($pagination['offset']);
$isModerator = $rawParams['is_moderator'] ?? false;

if (present($rawParams['user'] ?? null)) {
Expand Down
8 changes: 1 addition & 7 deletions app/Models/BeatmapDiscussionPost.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,8 @@ class BeatmapDiscussionPost extends Model implements Traits\ReportableInterface

public static function search($rawParams = [])
{
$pagination = pagination(cursor_from_params($rawParams) ?? $rawParams);
[$query, $params] = static::searchQueryAndParams(cursor_from_params($rawParams) ?? $rawParams);

$params = [
'limit' => $pagination['limit'],
'page' => $pagination['page'],
];

$query = static::limit($params['limit'])->offset($pagination['offset']);
$isModerator = $rawParams['is_moderator'] ?? false;

if (isset($rawParams['user'])) {
Expand Down
8 changes: 1 addition & 7 deletions app/Models/BeatmapDiscussionVote.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,8 @@ public static function recentlyGivenByUser($userId, $timeframeMonths = 3)

public static function search($rawParams = [])
{
$pagination = pagination(cursor_from_params($rawParams) ?? $rawParams);
[$query, $params] = static::searchQueryAndParams(cursor_from_params($rawParams) ?? $rawParams);

$params = [
'limit' => $pagination['limit'],
'page' => $pagination['page'],
];

$query = static::limit($params['limit'])->offset($pagination['offset']);
$isModerator = $rawParams['is_moderator'] ?? false;

if (isset($rawParams['user'])) {
Expand Down
8 changes: 1 addition & 7 deletions app/Models/BeatmapsetEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,8 @@ public static function log($type, $user, $object, $extraData = [])

public static function search($rawParams = [])
{
$pagination = pagination($rawParams);
[$query, $params] = static::searchQueryAndParams($rawParams);

$params = [
'limit' => $pagination['limit'],
'page' => $pagination['page'],
];

$query = static::limit($params['limit'])->offset($pagination['offset']);
$searchByUser = present($rawParams['user'] ?? null);
$isModerator = $rawParams['is_moderator'] ?? false;

Expand Down
9 changes: 9 additions & 0 deletions app/Models/Chat/UserChannel.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
namespace App\Models\Chat;

use App\Libraries\Notification\BatchIdentities;
use App\Models\Traits\WithDbCursorHelper;
use App\Models\User;
use App\Models\UserNotification;
use DB;
Expand All @@ -20,6 +21,14 @@
*/
class UserChannel extends Model
{
use WithDbCursorHelper;

const DEFAULT_SORT = 'user_id_asc';

const SORTS = [
'user_id_asc' => [['column' => 'user_id', 'order' => 'ASC']],
];

public $incrementing = false;
public $timestamps = false;

Expand Down
13 changes: 13 additions & 0 deletions app/Models/Model.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,19 @@ public static function booted()
static::addGlobalScope(new MacroableModelScope());
}

protected static function searchQueryAndParams(array $params)
{
$limit = clamp(get_int($params['limit'] ?? null) ?? static::PER_PAGE, 5, 50);
$page = max(get_int($params['page'] ?? null), 1);

$offset = max_offset($page, $limit);
$page = 1 + $offset / $limit;

$query = static::limit($limit)->offset($offset);

return [$query, compact('limit', 'page')];
}

public function getForeignKey()
{
if ($this->primaryKey === null || $this->primaryKey === 'id') {
Expand Down
2 changes: 1 addition & 1 deletion app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ class User extends Model implements AfterCommit, AuthenticatableContract, HasLoc

const MAX_FIELD_LENGTHS = [
'user_discord' => 37, // max 32char username + # + 4-digit discriminator
'user_from' => 30,
'user_from' => 25,
'user_interests' => 30,
'user_occ' => 30,
'user_sig' => 3000,
Expand Down
11 changes: 10 additions & 1 deletion app/Singletons/OsuAuthorize.php
Original file line number Diff line number Diff line change
Expand Up @@ -863,7 +863,7 @@ public function checkChatAnnounce(?User $user): string
return 'ok';
}

return $prefix.'annnonce_only';
return $prefix.'no_announce';
}

/**
Expand Down Expand Up @@ -919,6 +919,15 @@ public function checkChatChannelCanMessage(?User $user, Channel $channel): strin
return 'ok';
}

public function checkChatChannelListUsers(?User $user, Channel $channel): ?string
{
if ($channel->isAnnouncement() && $this->doCheckUser($user, 'ChatAnnounce', $channel)->can()) {
return 'ok';
}

return null;
}

/**
* TODO: always use a channel for this check?
*
Expand Down
1 change: 1 addition & 0 deletions app/Transformers/Chat/ChannelTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public function includeCurrentUserAttributes(Channel $channel)
$result = $channel->checkCanMessage($this->user);

return $this->primitive([
'can_list_users' => priv_check_user($this->user, 'ChatChannelListUsers', $channel)->can(),
'can_message' => $result->can(),
'can_message_error' => $result->message(),
'last_read_id' => $channel->lastReadIdFor($this->user),
Expand Down
19 changes: 6 additions & 13 deletions app/helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -651,17 +651,6 @@ function pack_str($str)
return pack('ccH*', 0x0b, strlen($str), bin2hex($str));
}

function pagination($params, $defaults = null)
{
$limit = clamp(get_int($params['limit'] ?? null) ?? $defaults['limit'] ?? 20, 5, 50);
$page = max(get_int($params['page'] ?? null) ?? 1, 1);

$offset = max_offset($page, $limit);
$page = 1 + $offset / $limit;

return compact('limit', 'page', 'offset');
}

function product_quantity_options($product, $selected = null)
{
if ($product->stock === null) {
Expand Down Expand Up @@ -1605,9 +1594,13 @@ function get_params($input, $namespace, $keys, $options = [])

$params = [];

if (Arr::accessible($input)) {
$options['null_missing'] = $options['null_missing'] ?? false;
$options['null_missing'] ??= false;

if (!Arr::accessible($input) && $options['null_missing']) {
$input = [];
}

if (Arr::accessible($input)) {
foreach ($keys as $keyAndType) {
$keyAndType = explode(':', $keyAndType);

Expand Down
2 changes: 1 addition & 1 deletion database/factories/UserFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public function definition(): array
'user_interests' => fn () => mb_substr($this->faker->bs(), 0, 30),
'user_occ' => fn () => mb_substr($this->faker->catchPhrase(), 0, 30),
'user_sig' => fn () => $this->faker->realText(155),
'user_from' => fn () => mb_substr($this->faker->country(), 0, 30),
'user_from' => fn () => mb_substr($this->faker->country(), 0, 25),
'user_regdate' => fn () => $this->faker->dateTimeBetween('-6 years'),
];
}
Expand Down
16 changes: 15 additions & 1 deletion resources/css/bem/chat-conversation.less
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@
margin-top: 10px;
}

&__more-users {
width: 100%;
display: flex;
justify-content: center;
}

&__unread-marker {
border-bottom: 1px solid @osu-colour-h1;
color: @osu-colour-h1;
Expand Down Expand Up @@ -106,10 +112,18 @@
gap: 2px;
align-content: center;
justify-content: center;
margin: 10px;

&--loading {
gap: 5px;
}
}

&__users-container {
.default-border-radius();
background-color: hsl(var(--hsl-b5));
padding: 5px;
display: grid;
gap: 5px;
margin: 10px;
}
}
4 changes: 4 additions & 0 deletions resources/css/bem/forum-poll-option.less
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@
&__input {
margin-right: 10px;
}

&__label {
min-width: 0;
}
}
12 changes: 12 additions & 0 deletions resources/js/chat/chat-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ interface GetChannelResponse {
users: UserJson[];
}

interface GetChannelUsersResponse {
cursor_string: null | string;
users: UserJson[];
}

interface GetMessagesResponse {
messages: MessageJson[];
users: UserJson[];
Expand Down Expand Up @@ -56,6 +61,13 @@ export function getChannel(channelId: number) {
}));
}

export function getChannelUsers(channelId: number, cursor: string) {
return $.get(route('chat.channels.users.index', {
channel: channelId,
cursor_string: cursor,
})) as JQuery.jqXHR<GetChannelUsersResponse>;
}

export function getMessages(channelId: number, params?: { until?: number }) {
const request = $.get(route('chat.channels.messages.index', { channel: channelId, return_object: 1, ...params })) as JQuery.jqXHR<GetMessagesResponse>;

Expand Down
35 changes: 26 additions & 9 deletions resources/js/chat/conversation-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -259,16 +259,33 @@ export default class ConversationView extends React.Component<Props> {
renderUsers() {
if (this.currentChannel?.type !== 'ANNOUNCE') return null;

const users = this.currentChannel.users;

if (users != null && users.length === 0) {
return null;
}

return (
<div className={classWithModifiers('chat-conversation__users', { loading: this.currentChannel.announcementUsers == null })}>
{this.currentChannel.announcementUsers == null ? (
<>
<Spinner modifiers='self-center' /><span>{trans('chat.loading_users')}</span>
</>
) : (
this.currentChannel.announcementUsers.map((user) => (
<UserCardBrick key={user.id} user={user.toJson()} />
))
<div className='chat-conversation__users-container'>
<div className={classWithModifiers('chat-conversation__users', { loading: users == null })}>
{users == null ? (
<>
<Spinner modifiers='self-center' /><span>{trans('chat.loading_users')}</span>
</>
) : (
users.map((user) => (
<UserCardBrick key={user.id} user={user} />
))
)}
</div>
{users != null && this.currentChannel.usersCursor != null && (
<div className='chat-conversation__more-users'>
<ShowMoreLink
callback={this.currentChannel.loadUsers}
hasMore
loading={this.currentChannel.loadUsersXhr != null}
/>
</div>
)}
</div>
);
Expand Down
Loading

0 comments on commit 1ae898e

Please sign in to comment.