Skip to content

Commit

Permalink
Merge branch 'master' into team-leaderboard
Browse files Browse the repository at this point in the history
  • Loading branch information
notbakaneko authored Feb 14, 2025
2 parents 9fd6a91 + 28e6db6 commit 931abdc
Show file tree
Hide file tree
Showing 12 changed files with 267 additions and 22 deletions.
93 changes: 83 additions & 10 deletions app/Http/Controllers/Forum/ForumsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,43 @@
use App\Models\Forum\Topic;
use App\Models\Forum\TopicTrack;
use App\Transformers\Forum\ForumCoverTransformer;
use App\Transformers\Forum\ForumTransformer;
use App\Transformers\Forum\TopicTransformer;
use Auth;

/**
* @group Forum
*/
class ForumsController extends Controller
{
public function __construct()
{
parent::__construct();

$this->middleware('require-scopes:public', ['only' => ['index', 'show']]);
}

/**
* Get Forum Listing
*
* Get top-level forums, their subforums (max 2 deep), and their last topics.
*
* ---
*
* ### Response Format
*
* Field | Type |
* ----------- | ---------------------------- |
* forums | [Forum](#forum)[] |
* last_topics | [ForumTopic](#forum-topic)[] |
*
* @response {
* "forums": [
* { "forum_id": 1, "...": "..." },
* { "forum_id": 2, "...": "..." }
* ]
* }
*/
public function index()
{
$forums = Forum
Expand All @@ -27,12 +55,18 @@ public function index()
->orderBy('left_id')
->get();

$lastTopics = Forum::lastTopics();

$forums = $forums->filter(function ($forum) {
return priv_check('ForumView', $forum)->can();
});

if (is_api_request()) {
return [
'forums' => json_collection($forums, new ForumTransformer(), ['subforums.subforums']),
];
}

$lastTopics = Forum::lastTopics();

return ext_view('forum.forums.index', compact('forums', 'lastTopics'));
}

Expand All @@ -53,6 +87,35 @@ public function markAsRead()
return ext_view('layout.ujs-reload', [], 'js');
}

/**
* Get Forum and Topics
*
* Get a forum by id, its pinned topics, recent topics, and its subforums.
*
* ---
*
* ### Response Format
*
* Field | Type |
* ------------- | ---------------------------- |
* forum | [Forum](#forum) |
* topics | [ForumTopic](#forum-topic)[] |
* pinned_topics | [ForumTopic](#forum-topic)[] |
*
* @urlParam forum integer required Id of the forum. Example: 1
*
* @response {
* "forum": { "id": 1, "...": "..." },
* "topics": [
* { "id": 1, "...": "..." },
* { "id": 2, "...": "..." },
* ],
* "pinned_topics": [
* { "id": 1, "...": "..." },
* { "id": 2, "...": "..." },
* ]
* }
*/
public function show($id)
{
$params = get_params(request()->all(), null, [
Expand All @@ -63,18 +126,12 @@ public function show($id)
$user = auth()->user();

$forum = Forum::with('subforums.subforums')->findOrFail($id);
$lastTopics = Forum::lastTopics($forum);

$sort = $params['sort'] ?? Topic::DEFAULT_SORT;
$withReplies = $params['with_replies'] ?? null;

priv_check('ForumView', $forum)->ensureCan();

$cover = json_item(
$forum->cover()->firstOrNew([]),
new ForumCoverTransformer()
);

$showDeleted = priv_check('ForumModerate', $forum)->can();

$pinnedTopics = $forum->topics()
Expand All @@ -88,8 +145,19 @@ public function show($id)
->with('forum')
->normal()
->showDeleted($showDeleted)
->recent(compact('sort', 'withReplies'))
->paginate();
->recent(compact('sort', 'withReplies'));

if (is_api_request()) {
return [
'forum' => json_item($forum, new ForumTransformer(), ['subforums.subforums']),
'topics' => json_collection($topics->limit(Topic::PER_PAGE)->get(), new TopicTransformer()),
'pinned_topics' => json_collection($pinnedTopics, new TopicTransformer()),
];
}

$topics = $topics->paginate();

$lastTopics = Forum::lastTopics($forum);

$allTopics = array_merge($pinnedTopics->all(), $topics->all());
$topicReadStatus = TopicTrack::readStatus($user, $allTopics);
Expand All @@ -103,6 +171,11 @@ public function show($id)
->get()
->keyBy('topic_id');

$cover = json_item(
$forum->cover()->firstOrNew([]),
new ForumCoverTransformer()
);

$noindex = !$forum->enable_indexing;

set_opengraph($forum);
Expand Down
57 changes: 56 additions & 1 deletion app/Http/Controllers/Forum/TopicsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use App\Models\Forum\TopicWatch;
use App\Models\UserProfileCustomization;
use App\Transformers\Forum\TopicCoverTransformer;
use App\Transformers\Forum\TopicTransformer;
use Auth;
use DB;
use Request;
Expand Down Expand Up @@ -50,7 +51,7 @@ public function __construct()
'store',
]]);

$this->middleware('require-scopes:public', ['only' => ['show']]);
$this->middleware('require-scopes:public', ['only' => ['index', 'show']]);
$this->middleware('require-scopes:forum.write', ['only' => ['reply', 'store', 'update']]);
}

Expand Down Expand Up @@ -279,6 +280,60 @@ public function reply($id)
}
}

/**
* Get Topic Listing
*
* Get a sorted list of topics, optionally from a specific forum
*
* ---
*
* ### Response Format
*
* Field | Type | Notes
* ------------- | ----------------------------- | -----
* topics | [ForumTopic](#forum-topic)[] | |
* cursor_string | [CursorString](#cursorstring) | |
*
* @usesCursor
* @queryParam forum_id Id of a specific forum to get topics from. No-example
* @queryParam sort Topic sorting option. Valid values are `new` (default) and `old`. Both sort by the topic's last post time. No-example
* @queryParam limit Maximum number of topics to be returned (50 at most and by default). No-example
*
* @response {
* "topics": [
* { "id": 1, "...": "..." },
* { "id": 2, "...": "..." }
* ],
* "cursor_string": "eyJoZWxsbyI6IndvcmxkIn0"
* }
*/
public function index()
{
$params = get_params(request()->all(), null, [
'limit:int',
'sort',
'forum_id:int',
], ['null_missing' => true]);

$limit = \Number::clamp($params['limit'] ?? Topic::PER_PAGE, 1, Topic::PER_PAGE);
$cursorHelper = Topic::makeDbCursorHelper($params['sort']);

$topics = Topic::cursorSort($cursorHelper, cursor_from_params($params))
->limit($limit);

$forum_id = $params['forum_id'];
if ($forum_id !== null) {
$topics->where('forum_id', $forum_id);
}

[$topics, $hasMore] = $topics->getWithHasMore();

return [
'topics' => json_collection($topics, new TopicTransformer()),
...cursor_for_response($cursorHelper->next($topics, $hasMore)),
];
}

/**
* Get Topic and Posts
*
Expand Down
11 changes: 11 additions & 0 deletions app/Models/Forum/Topic.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use App\Models\Beatmapset;
use App\Models\Log;
use App\Models\Notification;
use App\Models\Traits\WithDbCursorHelper;
use App\Models\User;
use App\Traits\Memoizes;
use App\Traits\Validatable;
Expand Down Expand Up @@ -79,8 +80,18 @@ class Topic extends Model implements AfterCommit
use SoftDeletes {
restore as private origRestore;
}
use WithDbCursorHelper;

const DEFAULT_SORT = 'new';
const SORTS = [
'new' => [
// type 'timestamp' because the values are stored as integer in the database
['column' => 'topic_last_post_time', 'order' => 'DESC', 'type' => 'timestamp'],
],
'old' => [
['column' => 'topic_last_post_time', 'order' => 'ASC', 'type' => 'timestamp'],
],
];

const STATUS_LOCKED = 1;
const STATUS_UNLOCKED = 0;
Expand Down
34 changes: 34 additions & 0 deletions app/Transformers/Forum/ForumTransformer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?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\Transformers\Forum;

use App\Models\Forum\Forum;
use App\Transformers\TransformerAbstract;
use League\Fractal\Resource\ResourceInterface;

class ForumTransformer extends TransformerAbstract
{
protected array $availableIncludes = [
'subforums',
];

public function transform(Forum $forum): array
{
return [
'id' => $forum->getKey(),
'name' => $forum->forum_name,
'description' => $forum->forum_desc,
];
}

public function includeSubforums(Forum $forum): ResourceInterface
{
return $this->collection(
$forum->subforums,
new static()
);
}
}
2 changes: 1 addition & 1 deletion app/Transformers/TeamTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ class TeamTransformer extends TransformerAbstract
public function transform(Team $team): array
{
return [
'flag_url' => $team->logo()->url(),
'id' => $team->getKey(),
'logo' => $team->logo()->url(),
'name' => $team->name,
'short_name' => $team->short_name,
];
Expand Down
7 changes: 7 additions & 0 deletions app/helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -1610,6 +1610,8 @@ function get_param_value($input, $type)
return get_arr($input, 'get_int');
case 'time':
return parse_time_to_carbon($input);
case 'timestamp':
return parse_time_to_timestamp($input);
default:
return presence(get_string($input));
}
Expand Down Expand Up @@ -1731,6 +1733,11 @@ function parse_time_to_carbon($value)
}
}

function parse_time_to_timestamp(mixed $value): ?int
{
return parse_time_to_carbon($value)?->timestamp;
}

function format_duration_for_display(int $seconds)
{
return floor($seconds / 60).':'.str_pad((string) ($seconds % 60), 2, '0', STR_PAD_LEFT);
Expand Down
20 changes: 13 additions & 7 deletions resources/css/bem/menu-images.less
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
&__arrow {
.reset-input();
.fade-element(@hover-transition-duration);
--padding: 10px;
height: 100%;
padding: 10px;
padding: var(--padding) calc(var(--page-gutter) + var(--padding));
position: absolute;
top: 0;

Expand All @@ -33,12 +34,14 @@

&--left {
--icon: @fa-var-chevron-left;
left: var(--page-gutter);
left: 0;
padding-right: var(--padding);
}

&--right {
--icon: @fa-var-chevron-right;
right: var(--page-gutter);
right: 0;
padding-left: var(--padding);
}

&::before {
Expand Down Expand Up @@ -97,8 +100,8 @@
display: flex;

width: 40px;
height: 11px;
padding: 0 5px 5px;
height: 16px;
padding: 5px;

--content-height: 2px;
--content-opacity: 0.5;
Expand Down Expand Up @@ -128,12 +131,15 @@
}

&__indicators {
position: relative;
align-items: center;
bottom: 0;
display: flex;
flex-wrap: wrap;
justify-content: center;
padding: 0 var(--page-gutter);
opacity: var(--indicators-opacity);
padding: 0 var(--page-gutter);
position: absolute;
transform: translateY(50%);
width: 100%;
}
}
2 changes: 1 addition & 1 deletion resources/js/components/flag-team.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default function FlagTeam({ team }: { team: TeamJson }) {
return (
<span
className='flag-team'
style={{ backgroundImage: urlPresence(team.logo) }}
style={{ backgroundImage: urlPresence(team.flag_url) }}
title={team.name}
/>
);
Expand Down
Loading

0 comments on commit 931abdc

Please sign in to comment.