Skip to content
Merged
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
15 changes: 11 additions & 4 deletions phpbb-test-board/_board.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,19 @@ def sql(self, query: str, args: tuple = ()) -> list:
finally:
con.close()

def php(self, code: str) -> str:
"""Run PHP inside the board (common.php and functions_user.php loaded)."""
def php(self, code: str, check: bool = False) -> str:
"""Run PHP inside the board (common.php and functions_user.php loaded); return its output.

With check=True a failing script (non-zero exit, such as a fatal
error) raises RuntimeError instead of being ignored.
"""
boot = ("define('IN_PHPBB',1);$phpbb_root_path='./';$phpEx='php';require 'common.php';"
"require 'includes/functions_user.php';$user->session_begin();$auth->acl($user->data);$user->setup();")
return subprocess.run(["php", "-d", "opcache.enable_cli=0", "-r", boot + code],
cwd=self.root, capture_output=True, text=True).stdout
r = subprocess.run(["php", "-d", "opcache.enable_cli=0", "-r", boot + code],
cwd=self.root, capture_output=True, text=True)
if check and r.returncode != 0:
raise RuntimeError(f"PHP failed: {(r.stderr or r.stdout).strip()[-300:]}")
return r.stdout

def reset(self) -> None:
"""Restore the clean database and cache."""
Expand Down
66 changes: 66 additions & 0 deletions phpbb-test-board/screenshots.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,74 @@ def shots_prominodeux(board: Board, shoot: Shooter, args: argparse.Namespace) ->
shoot.shot("prominodeux-viewtopic-phone", f"viewtopic.php?t={topic}", phone=True)


# Made-up values for the StopForumSpam screenshots. Nothing is ever sent to
# stopforumspam.com: the pages shown only read the board's own data and logs.
SFS_EXAMPLE_API_KEY = "0123456789abcdef"
SFS_EXAMPLE_POSTER_IP = "93.184.216.34" # a public address, so posts can be reported


def enable_stopforumspam(board: Board) -> None:
"""Turn StopForumSpam on with an example API key, and give posts a public poster IP."""
for name, value in (("allow_sfs", "1"), ("sfs_api_key", SFS_EXAMPLE_API_KEY)):
board.sql("UPDATE phpbb_config SET config_value = ? WHERE config_name = ?", (value, name))
board.sql("UPDATE phpbb_posts SET poster_ip = ?", (SFS_EXAMPLE_POSTER_IP,))
board.purge_cache()
# The admins-and-moderators list the ACP asks for when an API key is set;
# built locally from the board's own groups, so staff can't be reported.
board.php("$phpbb_container->get('phpbbmodders.stopforumspam.core.sfsgroups')->build_adminsmods_cache();", check=True)


def shots_stopforumspam(board: Board, shoot: Shooter, args: argparse.Namespace) -> None:
"""phpbbmodders/stopforumspam: its ACP settings and the report button on posts. Use --seed."""
enable_stopforumspam(board)
shoot.shot("stopforumspam-acp-settings",
"adm/index.php?i=-phpbbmodders-stopforumspam-acp-stopforumspam_module&mode=settings&sid={sid}",
admin=True)
_, topic = busiest_forum_and_topic(board)
def highlight_button(p) -> None:
p.add_style_tag(content="li[id^='sfs'] .button { outline: 3px solid #d31141; outline-offset: 2px; }")
shoot.shot("stopforumspam-report-button", f"viewtopic.php?t={topic}&sid={{sid}}", admin=True,
selector=".post:has(li[id^='sfs'])", prepare=highlight_button)


def shots_sfscompanion(board: Board, shoot: Shooter, args: argparse.Namespace) -> None:
"""phpbbmodders/sfscompanion: its ACP logs and settings, and the profile link.

Needs --with phpbbmodders/stopforumspam; use --seed. The lookup and scan
pages are left out because opening them queries stopforumspam.com.
"""
enable_stopforumspam(board)
# Example log entries in the shape phpbbmodders/stopforumspam writes them:
# logged by the guest (user 1) who was registering or posting.
entries = (
("user", "203.0.113.9", "LOG_SFS_MESSAGE", "['reportee_id' => 1, 'casino_deals', '203.0.113.9', 'deals@example.com']"),
("user", "203.0.113.24", "LOG_SFS_MESSAGE", "['reportee_id' => 1, 'cheap_pills_now', '203.0.113.24', 'pills@example.net']"),
("user", "198.51.100.41", "LOG_SFS_MESSAGE", "['reportee_id' => 1, 'seo_expert_99', '198.51.100.41', 'seo@example.org']"),
("user", "192.0.2.77", "LOG_SFS_MESSAGE", "['reportee_id' => 1, 'free_followers', '192.0.2.77', 'followers@example.com']"),
("admin", "198.51.100.7", "LOG_SFS_DOWN", "[]"),
("admin", "198.51.100.8", "LOG_SFS_DOWN", "[]"),
)
board.php("".join(f"$phpbb_log->add('{mode}', 1, '{ip}', '{op}', false, {data});"
for mode, ip, op, data in entries), check=True)
board.sql("UPDATE phpbb_config SET config_value = '30' WHERE config_name = 'sfsc_expire_days'")
board.purge_cache()
page = "adm/index.php?i=-phpbbmodders-sfscompanion-acp-main_module&sid={sid}&mode="
shoot.shot("sfscompanion-acp-blocks", page + "blocks", admin=True)
shoot.shot("sfscompanion-acp-errors", page + "errors", admin=True)
shoot.shot("sfscompanion-acp-settings", page + "settings", admin=True)
member = board.sql("SELECT user_id FROM phpbb_users WHERE user_type = 0 AND user_id <> 2 "
"ORDER BY user_posts DESC, user_id LIMIT 1")
member_id = member[0][0] if member else 2
def highlight_link(p) -> None:
p.add_style_tag(content="a[href*='sfs-companion/finder'] { background: #ffd54f; border-radius: 3px; padding: 2px 3px; }")
shoot.shot("sfscompanion-profile-link", f"memberlist.php?mode=viewprofile&u={member_id}&sid={{sid}}",
admin=True, selector=".panel:has(a[href*='sfs-companion/finder'])", prepare=highlight_link)


SHOTS = {
"phpbbmodders/documentation": shots_documentation,
"phpbbmodders/sfscompanion": shots_sfscompanion,
"phpbbmodders/stopforumspam": shots_stopforumspam,
"ProMinoDeux": shots_prominodeux,
}

Expand Down
Loading