Skip to content
This repository was archived by the owner on Oct 15, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
push:
branches:
- master
- distro/*
tags:
- v*
workflow_dispatch:
Expand Down
3 changes: 3 additions & 0 deletions config/packages/twig.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ twig:
globals:
umami_domain: "%env(UMAMI_DOMAIN)%"
umami_website_id: "%env(UMAMI_WEBSITE_ID)%"
appfeatures:
hint: "%app.features.hint%"
comment: "%app.features.comment%"

when@test:
twig:
Expand Down
4 changes: 4 additions & 0 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ parameters:
app.redis_uri: "%env(REDIS_URI)%"
app.openai_api_key: "%env(OPENAI_API_KEY)%"

app.features.hint: true
app.features.editable-profile: true
app.features.comment: true

services:
# default configuration for services in *this* file
_defaults:
Expand Down
18 changes: 18 additions & 0 deletions src/Controller/CommentsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ class CommentsController extends AbstractController
#[Route('/', name: '')]
public function index(#[CurrentUser] User $user, CommentRepository $commentRepository): Response
{
if (!$this->isCommentFeatureEnabled()) {
throw $this->createNotFoundException('"Comment" feature is disabled.');
}

$comments = $commentRepository->findUserComments($user);
$likes = array_reduce($comments, fn (int $carry, Comment $comment) => $carry + $comment->getCommentLikeEvents()->count(), 0);

Expand All @@ -47,6 +51,10 @@ public function likes(
ChartBuilderInterface $chartBuilder,
TranslatorInterface $translator,
): Response {
if (!$this->isCommentFeatureEnabled()) {
throw $this->createNotFoundException('"Comment" feature is disabled.');
}

$q = $commentRepository->createQueryBuilder('c')
->select('c.id AS id, COUNT(cle.id) AS count')
->leftJoin('c.commentLikeEvents', 'cle')
Expand Down Expand Up @@ -88,4 +96,14 @@ public function likes(
'chart' => $chart,
]);
}

private function isCommentFeatureEnabled(): bool
{
$comment = $this->getParameter('app.features.comment');
if (!\is_bool($comment)) {
throw new \RuntimeException('The "app.features.comment" parameter must be a boolean.');
}

return $comment;
}
}
17 changes: 17 additions & 0 deletions src/Controller/ProfileController.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,20 @@

class ProfileController extends AbstractController
{
public function isProfileEditable(): bool
{
$isProfileEditable = $this->getParameter('app.features.editable-profile');
\assert(\is_bool($isProfileEditable));

return $isProfileEditable;
}

#[Route('/profile', name: 'app_profile')]
public function index(#[CurrentUser] User $user): Response
{
return $this->render('profile/index.html.twig', [
'user' => $user,
'isProfileEditable' => $this->isProfileEditable(),
]);
}

Expand All @@ -35,6 +44,10 @@ public function editPassword(
Request $request,
#[CurrentUser] User $user,
): Response {
if (!$this->isProfileEditable()) {
throw $this->createNotFoundException('Feature "Editable Profile" is disabled.');
}

$passwordChangeModel = new PasswordChangeModel();
$passwordChangeForm = $formFactory->createBuilder(PasswordChangeFormType::class, $passwordChangeModel)
->setAction($this->generateUrl('app_profile_edit_password'))
Expand Down Expand Up @@ -66,6 +79,10 @@ public function editUsername(
Request $request,
#[CurrentUser] User $user,
): Response {
if (!$this->isProfileEditable()) {
throw $this->createNotFoundException('Feature "Editable Profile" is disabled.');
}

$usernameChangeForm = $formFactory->createBuilder(NameChangeFormType::class, $user)
->setAction($this->generateUrl('app_profile_edit_username'))
->getForm();
Expand Down
11 changes: 10 additions & 1 deletion src/Twig/Components/Challenge/CommentModule/CommentForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
use App\Entity\User as UserEntity;
use App\Form\CommentCreateFormType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveAction;
use Symfony\UX\LiveComponent\Attribute\LiveProp;
Expand Down Expand Up @@ -52,8 +54,15 @@ protected function instantiateForm(): FormInterface
}

#[LiveAction]
public function save(EntityManagerInterface $entityManager): void
public function save(EntityManagerInterface $entityManager, ParameterBagInterface $parameterBag): void
{
$appFeatureComment = $parameterBag->get('app.features.comment');
\assert(\is_bool($appFeatureComment));

if (!$appFeatureComment) {
throw new BadRequestHttpException('Comment feature is disabled.');
}

$this->submitForm();

$comment = $this->getForm()->getData();
Expand Down
10 changes: 10 additions & 0 deletions src/Twig/Components/Challenge/Instruction/Modal.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
use App\Service\PointCalculationService;
use App\Service\PromptService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
Expand Down Expand Up @@ -51,7 +53,15 @@ public function instruct(
TranslatorInterface $translator,
SerializerInterface $serializer,
EntityManagerInterface $entityManager,
ParameterBagInterface $parameterBag,
): void {
$appFeatureHint = $parameterBag->get('app.features.hint');
\assert(\is_bool($appFeatureHint));

if (!$appFeatureHint) {
throw new BadRequestHttpException('Hint feature is disabled.');
}

if ('' === $this->query) {
return;
}
Expand Down
24 changes: 13 additions & 11 deletions templates/components/Challenge/Comment.html.twig
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
<div {{ attributes.defaults({class: 'app-challenge-comments'}) }}>
<div class="app-challenge-comments__new mb-4">
<twig:Challenge:CommentModule:CommentForm :question="question" :commenter="currentUser" />
</div>
<div {{ attributes.defaults({class: 'app-challenge-comments', 'aria-hidden': not appfeatures.comment}) }}>
{% if appfeatures.comment %}
<div class="app-challenge-comments__new mb-4">
<twig:Challenge:CommentModule:CommentForm :question="question" :commenter="currentUser" />
</div>

<div class="app-challenge-comments__comments vstack gap-2">
{% for comment in this.comments %}
<twig:Challenge:CommentModule:Comment key="app-question-{{ question.id }}-comment-{{ comment.id }}" :comment="comment" :currentUser="currentUser" />
{% else %}
<div class="text-muted">尚無留言。成為第一個留言者吧!</div>
{% endfor %}
</div>
<div class="app-challenge-comments__comments vstack gap-2">
{% for comment in this.comments %}
<twig:Challenge:CommentModule:Comment key="app-question-{{ question.id }}-comment-{{ comment.id }}" :comment="comment" :currentUser="currentUser" />
{% else %}
<div class="text-muted">尚無留言。成為第一個留言者吧!</div>
{% endfor %}
</div>
{% endif %}
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{% if not this.result.answer %}
{% if this.result.same %}
<div class="alert alert-success" role="alert">
答案正確 🎉!可以到 <a href="#comments">留言區</a> 和其他人分享你的寫法!
答案正確 🎉!{% if appfeatures.comment %}可以到 <a href="#comments">留言區</a> 和其他人分享你的寫法!{% endif %}
</div>
{% else %}
<div class="alert alert-danger" role="alert">
Expand Down
18 changes: 12 additions & 6 deletions templates/components/Challenge/Ui.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
{% if question.solutionVideo %}
<twig:Challenge:SolutionVideoModal class="challenge-solution-video-modal" :question="question" :user="user" />
{% endif %}
<twig:Challenge:Instruction:Modal class="challenge-instruction-modal" :question="question" :currentUser="user" :query="query" />
{% if appfeatures.hint %}
<twig:Challenge:Instruction:Modal class="challenge-instruction-modal" :question="question" :currentUser="user" :query="query" />
{% endif %}

<main>
<twig:Challenge:Header class="mb-2" :question="question" :limit="limit" :user="user" />
Expand All @@ -13,7 +15,9 @@
<twig:Challenge:Executor class="mt-2" data-model="query:query" :question="question" :user="user">
<twig:block name="actions">
<div class="btn-group">
<button type="button" class="btn btn-outline-secondary" data-bs-toggle="modal" data-bs-target=".challenge-instruction-modal">提示</button>
{% if appfeatures.hint %}
<button type="button" class="btn btn-outline-secondary" data-bs-toggle="modal" data-bs-target=".challenge-instruction-modal">提示</button>
{% endif %}
{% if question.solutionVideo %}
<button type="button" class="btn btn-outline-secondary" data-bs-toggle="modal" data-bs-target=".challenge-solution-video-modal">解答影音</button>
{% endif %}
Expand All @@ -31,9 +35,11 @@
</div>
</section>

<section class="app-challenge-primary__comments mt-4" id="comments">
<h3 class="mb-3">留言區</h3>
<twig:Challenge:Comment :question="question" :currentUser="user" loading="lazy" />
</section>
{% if appfeatures.comment %}
<section class="app-challenge-primary__comments mt-4" id="comments">
<h3 class="mb-3">留言區</h3>
<twig:Challenge:Comment :question="question" :currentUser="user" loading="lazy" />
</section>
{% endif %}
</main>
</div>
6 changes: 5 additions & 1 deletion templates/components/Navbar.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,30 @@
name: '學習概況',
icon: 'bi bi-bar-chart-fill',
path: path('app_overview'),
disabled: false,
},
{
pageId: 'questions',
name: '練習題目',
icon: 'bi bi-pencil-fill',
path: path('app_questions'),
disabled: false,
},
{
pageId: 'comments',
name: '留言一覽',
icon: 'bi bi-chat-left-text-fill',
path: path('app_comments'),
disabled: not appfeatures.comment,
},
{
pageId: 'complementary',
name: '補充資料',
icon: 'bi bi-book-fill',
path: path('app_complementary'),
disabled: false,
},
] %}
]|filter(el => not el.disabled) %}

<nav{{ attributes.defaults({class: 'app-navbar navbar navbar-expand-lg bg-light'}) }}>
<div class="container-fluid">
Expand Down
2 changes: 2 additions & 0 deletions templates/profile/index.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
</ul>
</turbo-frame>

{% if isProfileEditable %}
<section class="app-profile__update col-12 col-md-6">
<h2 class="mb-4">更新帳號資訊</h2>

Expand All @@ -64,5 +65,6 @@
</turbo-frame>
</div>
</section>
{% endif %}
</div>
{% endblock %}