"""FT — post.html gear menu (NVM / DEL / BYE). User-authored Posts grow a #id_gear_btn that opens #id_post_menu with: - NVM (everyone) → navigates to billboard:my_posts - DEL (owner) → hard-deletes the Post - BYE (invitee) → removes the viewer from post.shared_with Admin-Posts (kind=NOTE_UNLOCK) get the gear menu too but with NVM only — DEL + BYE don't apply to system-authored threads. Mirrors apps/gameboard/_partials/_room_gear.html behaviour; see test_game_room_gatekeeper.py {owner_can_delete_room, gamer_can_abandon_room} for the room-side analogues. """ from selenium.webdriver.common.by import By from apps.billboard.models import Line, Post from apps.drama.models import Note from apps.lyric.models import User from .base import FunctionalTest class OwnerPostGearTest(FunctionalTest): """Owner of a user-Post sees NVM + DEL in the gear menu; DEL nukes the Post and redirects to /billboard/users//.""" def setUp(self): super().setUp() self.owner = User.objects.create(email="owner@test.io") self.post = Post.objects.create( owner=self.owner, kind=Post.KIND_USER_POST, title="Doomed post", ) Line.objects.create(post=self.post, text="line 1", author=self.owner) self.create_pre_authenticated_session("owner@test.io") def test_owner_can_delete_post_via_gear_menu(self): self.browser.get( self.live_server_url + f"/billboard/post/{self.post.id}/" ) self.wait_for( lambda: self.browser.find_element(By.CSS_SELECTOR, ".gear-btn") ).click() self.wait_for( lambda: self.browser.find_element( By.CSS_SELECTOR, "#id_post_menu .btn-danger" ) ).click() self.confirm_guard() self.wait_for(lambda: self.assertIn( f"/billboard/users/{self.owner.id}/", self.browser.current_url )) self.assertFalse(Post.objects.filter(id=self.post.id).exists()) def test_gear_menu_for_owner_shows_NVM_and_DEL_but_not_BYE(self): self.browser.get( self.live_server_url + f"/billboard/post/{self.post.id}/" ) self.wait_for( lambda: self.browser.find_element(By.CSS_SELECTOR, ".gear-btn") ).click() menu = self.wait_for( lambda: self.browser.find_element(By.ID, "id_post_menu") ) self.assertTrue(menu.find_elements(By.CSS_SELECTOR, ".btn-cancel")) self.assertTrue(menu.find_elements(By.CSS_SELECTOR, ".btn-danger")) self.assertFalse(menu.find_elements(By.CSS_SELECTOR, ".btn-abandon")) class InviteePostGearTest(FunctionalTest): """Invitee on a user-Post sees NVM + BYE; BYE removes the viewer from post.shared_with (owner + other invitees keep the Post).""" def setUp(self): super().setUp() self.owner = User.objects.create(email="owner@test.io") self.invitee = User.objects.create(email="invitee@test.io") self.other = User.objects.create(email="other@test.io") self.post = Post.objects.create( owner=self.owner, kind=Post.KIND_USER_POST, title="Shared post", ) Line.objects.create(post=self.post, text="line 1", author=self.owner) self.post.shared_with.add(self.invitee, self.other) self.create_pre_authenticated_session("invitee@test.io") def test_invitee_can_abandon_post_via_gear_menu(self): self.browser.get( self.live_server_url + f"/billboard/post/{self.post.id}/" ) self.wait_for( lambda: self.browser.find_element(By.CSS_SELECTOR, ".gear-btn") ).click() self.wait_for( lambda: self.browser.find_element( By.CSS_SELECTOR, "#id_post_menu .btn-abandon" ) ).click() self.confirm_guard() self.wait_for(lambda: self.assertIn( f"/billboard/users/{self.invitee.id}/", self.browser.current_url )) self.post.refresh_from_db() self.assertNotIn(self.invitee, self.post.shared_with.all()) # Post survives — owner + other invitee unaffected self.assertEqual(self.post.owner, self.owner) self.assertIn(self.other, self.post.shared_with.all()) def test_gear_menu_for_invitee_shows_NVM_and_BYE_but_not_DEL(self): self.browser.get( self.live_server_url + f"/billboard/post/{self.post.id}/" ) self.wait_for( lambda: self.browser.find_element(By.CSS_SELECTOR, ".gear-btn") ).click() menu = self.wait_for( lambda: self.browser.find_element(By.ID, "id_post_menu") ) self.assertTrue(menu.find_elements(By.CSS_SELECTOR, ".btn-cancel")) self.assertTrue(menu.find_elements(By.CSS_SELECTOR, ".btn-abandon")) self.assertFalse(menu.find_elements(By.CSS_SELECTOR, ".btn-danger")) class AdminPostGearTest(FunctionalTest): """Admin-Post (kind=NOTE_UNLOCK) shows the gear menu with NVM only — DEL + BYE don't apply to system-authored threads.""" def setUp(self): super().setUp() self.gamer = User.objects.create(email="gamer@test.io") Note.grant_if_new(self.gamer, "stargazer") self.admin_post = Post.objects.get( owner=self.gamer, kind=Post.KIND_NOTE_UNLOCK, ) self.create_pre_authenticated_session("gamer@test.io") def test_admin_post_gear_menu_has_NVM_but_no_DEL_no_BYE(self): self.browser.get( self.live_server_url + f"/billboard/post/{self.admin_post.id}/" ) self.wait_for( lambda: self.browser.find_element(By.CSS_SELECTOR, ".gear-btn") ).click() menu = self.wait_for( lambda: self.browser.find_element(By.ID, "id_post_menu") ) self.assertTrue(menu.find_elements(By.CSS_SELECTOR, ".btn-cancel")) self.assertFalse(menu.find_elements(By.CSS_SELECTOR, ".btn-danger")) self.assertFalse(menu.find_elements(By.CSS_SELECTOR, ".btn-abandon"))