Skip to content

[3.0] Don't treat a new topic as an unapproved topic - #9320

Open
albertlast wants to merge 1 commit into
SimpleMachines:release-3.0from
albertlast:fix/post2-unapproved-flag-new-topic
Open

[3.0] Don't treat a new topic as an unapproved topic#9320
albertlast wants to merge 1 commit into
SimpleMachines:release-3.0from
albertlast:fix/post2-unapproved-flag-new-topic

Conversation

@albertlast

Copy link
Copy Markdown
Collaborator

Note

This change was produced by an LLM. The code, the commit message and this
description were all written by Claude (Anthropic), driven by @albertlast. It has
not yet had human code review.

Everything stated below was verified by actually running it against a PostgreSQL
install of this branch, rather than only reasoned about. Even so, please review it
as untrusted work: the diagnosis may be right while the fix is not what SMF would
prefer stylistically or architecturally.

Description

An ordinary member who starts a new topic is told, on the page they land on
afterwards:

Your message was not approved because it was posted in an unapproved topic. Once
the topic is approved your message will be approved too.

The topic is in fact approved. Post2::submit() decides this before it knows which
kind of post it is dealing with:

// Replies to unapproved topics are unapproved by default (but not for moderators)
if (empty(Topic::$info->is_approved) && !$this->can_approve) {
    $this->becomes_approved = false;

    // Set a nice session var...
    $_SESSION['becomesUnapproved'] = true;
}

When a new topic is being started there is no topic yet. Post2::execute() only
loads one when there is something to load:

// If there is an existing topic, load it.
if ($this->intent !== self::INTENT_NEW_TOPIC) {
    $this->loadTopic();
}

So Topic::$info is null, empty(null->is_approved) is true under empty()'s
isset semantics, and every non-approver who starts a topic gets
$_SESSION['becomesUnapproved'] set. MessageIndex and Display pick that up on
the next page and show the notice.

The post itself is unaffected — prepareNewTopic() runs immediately afterwards and
sets $becomes_approved = true again — so this is purely a bogus message. It also
fires with post moderation switched off entirely, since the check never consults
postmod_active.

In 2.1 the whole block sat inside if (!empty($topic)) (Sources/Post.php, ~1789),
so it only ever applied to replies. That guard was lost when the code moved into
Post2. This restores it in the form Post2 uses to express the same thing, which
is $this->intent !== self::INTENT_NEW_TOPIC.

How this was verified

PostgreSQL 17 / PHP 8.4.23, as an ordinary member with no moderation permissions.

Worth noting up front: the test install has post moderation entirely off —
postmod_active is not even present in smf_settings — which is what shows the
check is misfiring rather than doing its job.

  • Before: member starts a new topic, is redirected to the board index, and the
    "posted in an unapproved topic" notice is shown. Meanwhile the database has
    topics.approved = 1 and messages.approved = 1 for what was just posted, so the
    message contradicts what actually happened.
  • After: same steps, notice not shown, post still stored approved.
  • Regression check on the case the code is actually for: marked a topic unapproved,
    then replied to it as the same member. The notice is still shown and the reply
    is stored with approved = 0, so genuine replies to unapproved topics behave
    exactly as before.

php -l clean.

Relationship to other PRs

Sources/Actions/Post2.php is not touched by any of the other open PRs
(#9310#9317), so this one stands alone.

Issues References (Fixes|Related|Closes)

  1. No existing issue found for this.

Post2::submit() marked a post as unapproved whenever
Topic::$info->is_approved was empty. When starting a new topic there is
no topic yet, so Topic::$info is null and empty() reports it as an
unapproved topic. Every non-approver who started a topic therefore got
$_SESSION['becomesUnapproved'] set, and was greeted with "Your message
was not approved because it was posted in an unapproved topic" even
though the topic was in fact approved.

The post itself was unaffected, because prepareNewTopic() resets
$becomes_approved afterwards. Only the message was wrong.

In 2.1 this block lived inside "if (!empty($topic))". Restores that
guard, which was lost when the code was moved into Post2.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants