Banlist.tsx (11560B)
1 import { PureComponent } from 'react'; 2 import { 3 CanonicalAliasEvent, 4 CANONICAL_ALIAS, 5 DEV_NORDGEDANKEN_MJOLNIR_BANLISTS, 6 MembershipEvent, 7 MJjolnirBanlists, 8 M_POLICY_RULE_ROOM, 9 M_POLICY_RULE_ROOM_ALT, 10 M_POLICY_RULE_ROOM_OLD, 11 M_POLICY_RULE_SERVER, 12 M_POLICY_RULE_SERVER_ALT, 13 M_POLICY_RULE_SERVER_OLD, 14 M_POLICY_RULE_USER, 15 M_POLICY_RULE_USER_ALT, 16 M_POLICY_RULE_USER_OLD, 17 RuleEvent 18 } from '../windowExt'; 19 20 type Props = Record<string, unknown>; 21 type State = { 22 user_rules: RuleEvent[]; 23 server_rules: RuleEvent[]; 24 room_rules: RuleEvent[]; 25 roomId?: string; 26 filter?: string; 27 memberships: MembershipEvent[]; 28 bantype: "user" | "server" | "room"; 29 aliases: CanonicalAliasEvent[]; 30 }; 31 32 class BanList extends PureComponent<Props, State> { 33 constructor(props: Props) { 34 super(props); 35 const urlParams = (new URL(window.location.href)).searchParams; 36 const roomId = urlParams.get("room_id") ?? undefined; 37 this.state = { 38 bantype: "user", 39 roomId: roomId, 40 user_rules: [], 41 server_rules: [], 42 room_rules: [], 43 memberships: [], 44 aliases:[] 45 }; 46 } 47 48 async componentDidMount() { 49 const user_rules = await window.widget_api.readStateEvents(M_POLICY_RULE_USER, 250_000_000_000, undefined, ["*"]) as RuleEvent[]; 50 const server_rules = await window.widget_api.readStateEvents(M_POLICY_RULE_SERVER, 250_000_000_000, undefined, ["*"]) as RuleEvent[]; 51 const room_rules = await window.widget_api.readStateEvents(M_POLICY_RULE_ROOM, 250_000_000_000, undefined, ["*"]) as RuleEvent[]; 52 const user_rules_old = await window.widget_api.readStateEvents(M_POLICY_RULE_USER_OLD, 250_000_000_000, undefined, ["*"]) as RuleEvent[]; 53 const server_rules_old = await window.widget_api.readStateEvents(M_POLICY_RULE_SERVER_OLD, 250_000_000_000, undefined, ["*"]) as RuleEvent[]; 54 const room_rules_old = await window.widget_api.readStateEvents(M_POLICY_RULE_ROOM_OLD, 250_000_000_000, undefined, ["*"]) as RuleEvent[]; 55 const user_rules_alt = await window.widget_api.readStateEvents(M_POLICY_RULE_USER_ALT, 250_000_000_000, undefined, ["*"]) as RuleEvent[]; 56 const server_rules_alt = await window.widget_api.readStateEvents(M_POLICY_RULE_SERVER_ALT, 250_000_000_000, undefined, ["*"]) as RuleEvent[]; 57 const room_rules_alt = await window.widget_api.readStateEvents(M_POLICY_RULE_ROOM_ALT, 250_000_000_000, undefined, ["*"]) as RuleEvent[]; 58 const user_rules_all = [...user_rules, ...user_rules_old, ...user_rules_alt]; 59 const server_rules_all = [...server_rules, ...server_rules_old, ...server_rules_alt]; 60 const room_rules_all = [...room_rules, ...room_rules_old, ...room_rules_alt]; 61 const list_rooms = [...new Set([...user_rules_all.map(element => element.room_id), ...server_rules_all.map(element => element.room_id)])]; 62 const sender = new Set([...user_rules_all.map(element => element.sender), ...server_rules_all.map(element => element.sender)]); 63 const memberships = await window.widget_api.readStateEvents("m.room.member", 250_000_000_000, undefined, list_rooms) as MembershipEvent[]; 64 const memberships_needed = memberships.filter(member => sender.has(member.state_key)); 65 const banlist_codes = await window.widget_api.readStateEvents(DEV_NORDGEDANKEN_MJOLNIR_BANLISTS, 250_000_000_000, undefined, [this.state.roomId ?? "*"]) as MJjolnirBanlists[]; 66 const aliases = await window.widget_api.readStateEvents(CANONICAL_ALIAS, list_rooms.length, undefined, list_rooms) as CanonicalAliasEvent[]; 67 68 this.setState({ 69 aliases, 70 user_rules: user_rules_all.filter(rules => { 71 if (banlist_codes.length > 0) { 72 return banlist_codes.some(banlist_codes_event => ((aliases.find(aliases_event => aliases_event.room_id === rules.room_id)?.content?.alias ?? "") in (banlist_codes_event.content?.banlists ?? {})) || (rules.room_id in (banlist_codes_event.content?.banlists ?? {}))); 73 } else { 74 return true; 75 } 76 }), 77 server_rules: server_rules_all.filter(rules => { 78 if (banlist_codes.length > 0) { 79 return banlist_codes.some(banlist_codes_event => ((aliases.find(aliases_event => aliases_event.room_id === rules.room_id)?.content?.alias ?? "") in (banlist_codes_event.content?.banlists ?? {})) || (rules.room_id in (banlist_codes_event.content?.banlists ?? {}))); 80 } else { 81 return true; 82 } 83 }), 84 room_rules: room_rules_all.filter(rules => { 85 if (banlist_codes.length > 0) { 86 return banlist_codes.some(banlist_codes_event => ((aliases.find(aliases_event => aliases_event.room_id === rules.room_id)?.content?.alias ?? "") in (banlist_codes_event.content?.banlists ?? {})) || (rules.room_id in (banlist_codes_event.content?.banlists ?? {}))); 87 } else { 88 return true; 89 } 90 }), 91 memberships: memberships_needed 92 }); 93 } 94 95 onSearch(ev: { target: { value: string; }; }) { 96 this.setState({ 97 filter: ev.target.value 98 }); 99 } 100 101 handleInputChange(event: { target: { type: string, checked?: boolean, value: string | boolean, name: string; }; }) { 102 const target = event.target; 103 const value = target.type === 'checkbox' ? target.checked : target.value; 104 const name = target.name; 105 this.setState({ 106 [name]: value 107 } as unknown as State); 108 } 109 110 render() { 111 const { user_rules, server_rules, filter, memberships, bantype, room_rules,aliases } = this.state; 112 const filtered_user_rules = filter ? user_rules.filter(element => element.content && Object.keys(element.content).length > 0 && element.content?.entity.includes(filter)) : user_rules; 113 const filtered_server_rules = filter ? server_rules.filter(element => element.content && Object.keys(element.content).length > 0 && element.content?.entity.includes(filter)) : server_rules; 114 const filtered_room_rules = filter ? room_rules.filter(element => element.content && Object.keys(element.content).length > 0 && element.content?.entity.includes(filter)) : room_rules; 115 116 const rules = bantype === "user" ? filtered_user_rules : (bantype === "server" ? filtered_server_rules : filtered_room_rules); 117 return ( 118 <main className="m-8 flex items-start flex-col"> 119 <div className='flex flex-row justify-between content-between w-full'> 120 <h1 className="text-3xl font-bold underline text-gray-900 dark:text-gray-200 mb-4">Banlist data</h1> 121 <div className='flex flex-row'> 122 <select required defaultValue="" name="bantype" value={bantype} className="placeholder:text-gray-900 text-gray-900 rounded py-1.5 px-2" onChange={this.handleInputChange.bind(this)}> 123 <option value="" disabled>Select an Bantype</option> 124 <option value="user">User</option> 125 <option value="server">Server</option> 126 <option value="room">Room</option> 127 </select> 128 <input onChange={this.onSearch.bind(this)} value={filter} placeholder="Search for user or server" className='ml-2 py-1.5 px-2 rounded border-none placeholder:text-gray-900 text-gray-9000'></input> 129 </div> 130 </div> 131 <div className='flex flex-row w-full mb-4'> 132 <h5 className="text-lg font-medium text-gray-900 dark:text-gray-200 mr-2">User Bans ({user_rules.length})</h5> 133 <h5 className="text-lg font-medium text-gray-900 dark:text-gray-200 mx-2">Server Bans ({server_rules.length})</h5> 134 <h5 className="text-lg font-medium text-gray-900 dark:text-gray-200 mx-2">Room Bans ({room_rules.length})</h5> 135 </div> 136 <div className='flex flex-row w-full mb-4'> 137 <h3 className="text-2xl font-bold text-gray-900 dark:text-gray-200">{bantype === "room" ? "Room Bans" : (bantype === "server" ? "Server Bans" : "User Bans")}</h3> 138 </div> 139 <div className='flex flex-row justify-between content-between w-full'> 140 <table className='p-16 table-auto border-collapse border-2 border-slate-500 text-gray-900 dark:text-gray-200 text-base font-normal break-words w-full'> 141 <thead> 142 <tr> 143 <th className='border-2 border-slate-600 p-1'>Entity</th> 144 <th className='border-2 border-slate-600 p-1'>Recommendation</th> 145 <th className='border-2 border-slate-600 p-1'>Reason</th> 146 <th className='border-2 border-slate-600 p-1'>Sender</th> 147 <th className='border-2 border-slate-600 p-1'>Room</th> 148 </tr> 149 </thead> 150 <tbody> 151 { 152 rules.length > 0 ? 153 rules.map(element => { 154 if (element.content && Object.keys(element.content).length > 0) { 155 const recommendation = element.content.recommendation === "m.ban" || element.content.recommendation === "org.matrix.mjolnir.ban" ? "Ban" : element.content.recommendation; 156 157 // Entity is intentionally left as a mxid 158 const sender_dp = memberships.find(membership => membership.state_key === element.sender)?.content?.displayname ?? element.sender; 159 return ( 160 <tr key={`${element.event_id}`} className='border-2 border-slate-600'> 161 <td className='p-1 min-w-[8rem] max-w-[14rem]'>{element.content.entity}</td> 162 <td className='p-1 min-w-[1rem] max-w-[14rem]'>{recommendation}</td> 163 <td className='p-1 min-w-[8rem] max-w-[14rem]'>{element.content.reason}</td> 164 <td className='p-1 min-w-[12rem] max-w-[14rem]'>{sender_dp}</td> 165 <td className='p-1 min-w-[12rem] max-w-[14rem]'>{aliases.find(aliases_event => aliases_event.room_id === element.room_id)?.content?.alias ?? element.room_id}</td> 166 </tr> 167 ); 168 } 169 }) : ( 170 <tr className='border-2 border-slate-600'> 171 <td className='p-1'>No user ban found</td> 172 </tr> 173 ) 174 } 175 </tbody> 176 </table> 177 </div> 178 </main> 179 ); 180 } 181 } 182 183 export default BanList;