############################################################################### # MemberGroups.pm # # $Date: 01 Sep 2026 $ # ############################################################################### # YaBB: Yet another Bulletin Board # # Open-Source Community Software for Webmasters # # Version: YaBBForum 3.2 # # Packaged: 01 Sep 2026 # # Distributed by: https://yabbforum.nz # # =========================================================================== # # Copyright (c) 2000-2026 YaBB (yabbforum.nz) - All Rights Reserved. # # Software by: The YaBB Development Team # # with assistance from the YaBB community. # ############################################################################### use CGI::Carp qw(fatalsToBrowser); our $VERSION = '3.2'; $membergroupspmver = 'YaBBForum 3.2'; if ( $action eq 'detailedversion' ) { return 1; } $admin_images = "$yyhtml_root/Templates/Admin/default"; sub EditMemberGroups { is_admin_or_gmod(); # ( # $title, $stars, $starpic, $color, # $noshow, $viewperms, $topicperms, $replyperms, # $pollperms, $attachperms, $additional # ) $yymain .= qq~
$admin_img{'guest'} $admin_txt{'8'}
$admin_txt{'11'}
~; my @grps = sort keys %Group; my @memstats = (); for ( @grps ) { @memstats = split /\|/xsm, $Group{$_}; $memstats[4] = ( $memstats[4] == 1 ) ? "$admin_txt{'164'}" : "$admin_txt{'163'}"; $yymain .= qq~ ~; if ( $memstats[3] ) { $thecolname = hextoname($memstats[3]); $yymain .= qq~ ~; } else { $yymain .= q~ ~; } $mgrp = $_; $mgrp =~ s/\ /%20/gsm; $yymain .= qq~ ~; } $yymain .= q~
$admin_img{'guest'} $admin_txt{'12'}
$amgtxt{'03'} $amgtxt{'19'} $amgtxt{'08'} $amgtxt{'01'} $admin_txt{'53'}  
$memstats[0] x $memstats[1]$thecolname $memstats[4] $admin_txt{'53'}  
~; my $colspan = 6; my $colgroup = q~ ~; if ( $addmemgroup_enabled > 0 ) { $additional_tablehead = qq~$amgtxt{'83'}~; $colspan = 7; $colgroup = q~ ~; } my $reorderlink = q{}; if ($#nopostorder) { $reorderlink = qq~ | $admintxt{'reordergroups'}~; } $yymain .= qq~
$colgroup $additional_tablehead ~; $count = 0; for (@nopostorder) { @memstats = split /\|/xsm, $NoPost{$_}; $memstats[4] = ( $memstats[4] == 1 ) ? "$admin_txt{'164'}" : "$admin_txt{'163'}"; $memstats[10] = ( $memstats[10] == 0 ) ? "$admin_txt{'164'}" : "$admin_txt{'163'}"; if ( !$stars ) { $stars = 0; } $yymain .= qq~~; if ($memstats[3]) { $thecolname = hextoname($memstats[3]); $yymain .= qq~ ~; } else { $yymain .= q~ ~; } $yymain .= qq~ ~; if ( $addmemgroup_enabled > 0 ) { $yymain .= qq~ ~; } $yymain .= qq~ ~; $count++; } if ( $count == 0 ) { $yymain .= qq~~; } $yymain .= qq~
$admin_img{'guest'} $amgtxt{'37'} ($admintxt{'18c'}$reorderlink)
$amgtxt{'03'} $amgtxt{'19'} $amgtxt{'08'} $amgtxt{'01'}$admin_txt{'53'} $admin_txt{'54'}
$memstats[0] x $memstats[1]$thecolname $memstats[4]$memstats[10]$admin_txt{'53'} $admin_txt{'54'}
$amgtxt{'35'}
~; my $count = 0; for ( reverse sort { $a <=> $b } keys %Post ) { @memstats = split /\|/xsm, $Post{$_}; $memstats[4] = ( $memstats[4] == 1 ) ? "$admin_txt{'164'}" : "$admin_txt{'163'}"; if ( !$memstats[1] ) { $memstats[1] = 0; } if ( $memstats[2] !~ /\//xsm ) { $memstats[2] = "$imagesdir/$memstats[2]"; } $yymain .= qq~~; if ($memstats[3]) { $thecolname = hextoname($memstats[3]); $yymain .= qq~ ~; } else { $yymain .= q~ ~; } $yymain .= qq~ ~; $count++; } if ( $count == 0 ) { $yymain .= qq~~; } $yymain .= q~
$admin_img{'guest'} $amgtxt{'40'} ($admintxt{'18c'})
$amgtxt{'03'} $amgtxt{'19'} $amgtxt{'08'} $admin_txt{'21'} $admin_txt{'53'} $admin_txt{'54'}
$memstats[0] x $memstats[1]$thecolname $_ $admin_txt{'53'} $admin_txt{'54'}
$amgtxt{'36'}
~; $yytitle = $admin_txt{'8'}; $action_area = 'modmemgr'; AdminTemplate(); return; } sub hextoname { ($colorname) = @_; $colorname =~ s/aqua|\x2300FFFF/$amgtxt{'56'}/ism; $colorname =~ s/black|\x23000000/$amgtxt{'57'}/ism; $colorname =~ s/blue|\x230000FF/$amgtxt{'58'}/ism; $colorname =~ s/fuchsia|\x23FF00FF/$amgtxt{'59'}/ism; $colorname =~ s/gray|\x23808080/$amgtxt{'60'}/ism; $colorname =~ s/green|\x23008000/$amgtxt{'61'}/ism; $colorname =~ s/lime|\x2300FF00/$amgtxt{'62'}/ism; $colorname =~ s/maroon|\x23800000/$amgtxt{'63'}/ism; $colorname =~ s/navy|\x23000080/$amgtxt{'64'}/ism; $colorname =~ s/olive|\x23808000/$amgtxt{'65'}/ism; $colorname =~ s/purple|\x23800080/$amgtxt{'66'}/ism; $colorname =~ s/red|\x23FF0000/$amgtxt{'67'}/ism; $colorname =~ s/silver|\x23C0C0C0/$amgtxt{'68'}/ism; $colorname =~ s/teal|\x23008080/$amgtxt{'69'}/ism; $colorname =~ s/white|\x23FFFFFF/$amgtxt{'70'}/ism; $colorname =~ s/yellow|\x23FFFF00/$amgtxt{'71'}/ism; $colorname =~ s/\x23DEB887/$amgtxt{'75'}/ism; $colorname =~ s/\x23FFD700/$amgtxt{'76'}/ism; $colorname =~ s/\x23FFA500/$amgtxt{'77'}/ism; $colorname =~ s/\x23A0522D/$amgtxt{'78'}/ism; $colorname =~ s/\x2387CEEB/$amgtxt{'79'}/ism; $colorname =~ s/\x236A5ACD/$amgtxt{'80'}/ism; $colorname =~ s/\x234682B4/$amgtxt{'81'}/ism; $colorname =~ s/\x239ACD32/$amgtxt{'82'}/ism; return $colorname; } sub editAddGroup { is_admin_or_gmod(); my @memstats = (); if ( $INFO{'group'} ) { $viewtitle = $admintxt{'18a'}; ( $type, $element ) = split /\|/xsm, $INFO{'group'}; if ( $element ne q{} ) { if ( $type eq 'P' ) { $posts = $element; @memstats = split /\|/xsm, $Post{$element}; } else { $noposts = $element; $choosable = 1; @memstats = split /\|/xsm, $NoPost{$element}; } } else { @memstats = split /\|/xsm, $Group{ $INFO{'group'} }; } } else { $viewtitle = $admintxt{'18b'}; $memstats[0] = q{}; $memstats[1] = q{}; $memstats[2] = q{}; $memstats[3] = q{}; $posts = q{}; $noposts = 1; for ( sort { $a <=> $b } keys %NoPost ) { $noposts = $_ + 1; } } if ( $stars !~ /\A[0-9]+\Z/xsm ) { $stars = 0; } $otherdisable = q~ disabled="disabled"~; # Get star selected if needed. my @starsgif = ( q{}, 'staradmin.png', 'stargmod.png', 'starfmod.png', 'starmod.png', 'starblue.png', 'starsilver.png', 'stargold.png', ); my @starstxt = ( q{}, "$amgtxt{'20'}","$amgtxt{'21'}","$amgtxt{'21a'}","$amgtxt{'22'}", "$amgtxt{'23'}","$amgtxt{'24'}","$amgtxt{'25'}", ); my @stara = (); $pick = $memstats[2]; $otherdisable = q{}; my $stsel = 0; foreach my $i ( 1 .. 7 ) { if ( $memstats[2] eq $starsgif[$i] ) { $stara[$i] = q{ selected="selected"}; $stsel++; } } if ( $stsel == 0 ) { $stara[8] = q{ selected="selected"}; } my $starurl = ( $memstats[2] !~ m{https://}xsm ? "$imagesdir/" : q{} ) . ( $memstats[2] ? $memstats[2] : 'blank.gif' ); $memstats[3] =~ s/\#//gxsm; $pc = q~ checked="checked"~; $pd = q{}; $pt = q{}; if ($memstats[4]) { $pc = q{}; } if ($memstats[10]) { $admg = q~ checked="checked"~; } if ( $posts eq q{} && $action ne 'editgroup1' ) { $post2 = q{ checked="checked"}; $pt = q{ disabled="disabled"}; } else { $post1 = q~ checked="checked"~; $pd = q~ disabled="disabled"~; } if ( $memstats[5] == 1 ) { $vc = q~ checked="checked"~; } if ( $memstats[6] == 1 ) { $tc = q~ checked="checked"~; } if ( $memstats[7] == 1 ) { $rc = q~ checked="checked"~; } if ( $memstats[8] == 1 ) { $poc = q~ checked="checked"~; } if ( $memstats[9] == 1 ) { $ac = q~ checked="checked"~; } $yymain .= qq~
~; # Get color selected $yymain =~ s/(~; } else { $yymain .= qq~~; } if ( $addmemgroup_enabled > 0 ) { if ( $choosable || ( !$choosable && $action ne 'editgroup1' && !$INFO{'group'} ) ) { $yymain .= qq~~; } } if ( $INFO{'group'} ne 'Administrator' ) { $yymain .= qq~
$admin_img{'prefimg'} $viewtitle
  X  
  #  



~; } $yymain .= qq~
$admin_img{'prefimg'} $amgtxt{'44'}
$admin_img{'prefimg'} $admin_txt{'10'}
~; $yytitle = $admin_txt{'8'}; $action_area = 'modmemgr'; AdminTemplate(); return; } sub editAddGroup2 { is_admin_or_gmod(); # Additional checks are: # If post independent -> post dependent, then need to kill off post independent # If post dependent -> post independent, then need to kill off post dependent. # If post dependent -> NEW post dependent, then need to kill off OLD post dependent. $newpostdep = 0; if ( !$FORM{'title'} ) { fatal_error('no_group_name'); } $name = $FORM{'title'}; $name =~ s/\x27/&\x2339;/gxsm; $name =~ s/,/&\x2344;/gxsm; $name =~ s/\|/&\x23124;/gxsm; $lcname = lc $name; if ( $FORM{'starsadmin'} eq 'other' ) { $cur_otherstar = $FORM{'cur_otherstar'}; if ( $FORM{'otherstar'} ne q{} ) { $star = UploadFile('otherstar', 'Templates/Forum/default', 'png jpg jpeg gif', '250', '0'); if ( $cur_otherstar !~ /^(staradmin|stargmod|starfmod|starmod|starsilver|starblue|stargold).png$/ ) { unlink "$htmldir/Templates/Forum/default/$cur_otherstar"; } } else { $star = $cur_otherstar; } } else { $star = $FORM{'starsadmin'}; } $color = $FORM{'color2'} ne q{} ? "#$FORM{'color2'}" : q{}; $postdepend = $FORM{'postdepend'}; if ( $FORM{'posts'} !~ /\d+/xsm && $postdepend eq 'Yes' ) { fatal_error('no_post_number'); } else { $posts = $FORM{'posts'} } if ( $postdepend eq 'No' ) { $noposts = $FORM{'noposts'}; } if ( $FORM{'viewpublic'} ) { $viewpublic = 0 } else { $viewpublic = 1 } $view = $FORM{'view'} || 0; $topics = $FORM{'topics'} || 0; $reply = $FORM{'reply'} || 0; $polls = $FORM{'polls'} || 0; $attach = $FORM{'attach'} || 0; $additional = $FORM{'additional'} || 0; $original = $FORM{'original'}; # all the checks. if ( $original ne q{} ) { ( $type, $element ) = split /\|/xsm, $original; # Ignoring Administrative groups. if ( $element ne q{} ) { if ( $type eq 'P' ) { if ( $element != $posts || $postdepend eq 'No' ) { if ($iamgmod) { fatal_error('newpostdep_gmod'); } delete $Post{$element}; $newpostdep = 1; $noposts = 1; foreach ( sort { $a <=> $b } keys %NoPost ) { $noposts = $_ + 1; } } } elsif ( $type eq 'NP' ) { if ( $element != $noposts || $postdepend eq 'Yes' ) { delete $NoPost{$element}; for my $i ( 0 .. ( @nopostorder - 1 ) ) { if ( $nopostorder[$i] == $element ) { splice @nopostorder, $i, 1; last; } } } } } } if ( ( split /\|/xsm, $Group{$original}, 2 )[0] ne $name ) { if ( $lcname eq lc( ( split /\|/xsm, $Group{'Administrator'}, 2 )[0] ) ) { fatal_error( 'double_group', $lcname ); } if ( $lcname eq lc( ( split /\|/xsm, $Group{'Global Moderator'}, 2 )[0] ) ) { fatal_error( 'double_group', $lcname ); } if ( $lcname eq lc( ( split /\|/xsm, $Group{'Mid Moderator'}, 2 )[0] ) ) { fatal_error( 'double_group', $lcname ); } if ( $lcname eq lc( ( split /\|/xsm, $Group{'Moderator'}, 2 )[0] ) ) { fatal_error( 'double_group', $lcname ); } } # Check Post Independent foreach my $key ( keys %NoPost ) { if ( $type eq 'NP' && $key eq $element ) { next; } ( $value, undef ) = split /\|/xsm, $NoPost{$key}, 2; $lcvalue = lc $value; if ( $lcname eq $lcvalue ) { fatal_error( 'double_group', $lcname ); } } # Check Post Dependent foreach my $key ( keys %Post ) { if ( $type eq 'P' && $key eq $element ) { next; } ( $value, undef ) = split /\|/xsm, $Post{$key}, 2; $lcvalue = lc $value; if ( $lcname eq $lcvalue ) { fatal_error( 'double_group', $lcname ); } } if ( $FORM{'numstars'} !~ /\A[0-9]+\Z/xsm ) { $FORM{'numstars'} = 0; } # Now, we must deliberate on what type of thing this group is, and add/read(when editing) it. # First, using original variable, we check to see it's not a perma-group. ( $type, $element ) = split /\|/xsm, $original; if ( $element eq q{} && $original ne q{} ) { # We have a perma-group! $type is now equal to the perma group or key for the hash. # add in code to actually set the line. $Group{"$type"} = "$name|$FORM{'numstars'}|$star|$color|$viewpublic|$view|$topics|$reply|$polls|$attach|$additional"; } else { # post dependent group. if ( $postdepend eq 'Yes' ) { foreach my $key ( keys %Post ) { if ( $posts == $key && ( $FORM{'origin'} eq 'editgroup1' || $original ne "P|$posts" ) ) { fatal_error( 'double_count', "($posts)" ); } } if ($iamgmod) { fatal_error('newpostdep_gmod'); } $Post{$posts} = "$name|$FORM{'numstars'}|$star|$color|0|$view|$topics|$reply|$polls|$attach|$additional"; $newpostdep = 1; # no post group } else { $NoPost{$noposts} = "$name|$FORM{'numstars'}|$star|$color|$viewpublic|$view|$topics|$reply|$polls|$attach|$additional"; my $isinorder; for my $i ( 0 .. ( @nopostorder - 1 ) ) { if ( $NoPost{ $nopostorder[$i] } && $nopostorder[$i] == $noposts ) { $isinorder = 1; last; } } if ( !$isinorder ) { push @nopostorder, $noposts; } } } require Admin::NewSettings; SaveSettingsTo('Settings.pm'); # save @nopostorder, %Group, %NoPost and %Post if ($newpostdep) { $yySetLocation = qq~$adminurl?action=rebuildmemlist;actiononfinish=modmemgr~; } else { $yySetLocation = qq~$adminurl?action=modmemgr~; } redirectexit(); return; } sub permImage { my @x = @_; my $viewperms = ( $x[0] != 1 ) ? qq~~ : q{}; my $topicperms = ( $x[1] != 1 ) ? qq~~ : q{}; my $replyperms = ( $x[2] != 1 ) ? qq~~ : q{}; my $pollperms = ( $x[3] != 1 ) ? qq~~ : q{}; my $attachperms = ( $x[4] != 1 ) ? qq~~ : q{}; return "$viewperms $topicperms $replyperms $pollperms $attachperms"; } sub deleteGroup { if ( $INFO{'group'} ) { ( $type, $element ) = split /\|/xsm, $INFO{'group'}; if ( $element ne q{} ) { if ( $type eq 'P' ) { delete $Post{$element}; } elsif ( $type eq 'NP' ) { delete $NoPost{$element}; KillModeratorGroup($element); } } } else { fatal_error('no_info'); } my @new_nopostorder; foreach (@nopostorder) { if ( $NoPost{$_} ) { push @new_nopostorder, $_; } } @nopostorder = @new_nopostorder; require Admin::NewSettings; SaveSettingsTo('Settings.pm'); # save @nopostorder, %Group, %NoPost and %Post $yySetLocation = qq~$adminurl?action=rebuildmemlist;actiononfinish=modmemgr~; redirectexit(); return; } sub reorderGroups { $selsize = 0; foreach (@nopostorder) { if ( $NoPost{$_} ) { ( $title, undef ) = split /\|/xsm, $NoPost{$_}, 2; if ( $_ eq $INFO{'thegroup'} ) { $orderopt .= qq~~; } else { $orderopt .= qq~~; } $selsize++; } } $rowspan = $#nopostorder + 2; $yymain .= qq~
~; foreach (@nopostorder) { ( $title, $stars, $starpic, $color, undef ) = split /\|/xsm, $NoPost{$_}, 5; if ( !$stars ) { $stars = '0'; } $yymain .= q~~; } $yymain .= q~
 $admintxt{'reordergroups2'}
$amgtxt{'03'} $amgtxt{'19'}

~; if ($color) { $yymain .= qq~$title~; } else { $yymain .= qq~$title~; } $yymain .= q~ ~; for ( 1 .. $stars ) { $yymain .= qq~~; } $yymain .= q~
~; $yytitle = $admintxt{'reordergroups'}; $action_area = 'modmemgr'; AdminTemplate(); return; } sub reorderGroups2 { my $moveitem = $FORM{'ordergroups'}; if ($moveitem) { for my $i ( 0 .. ( @nopostorder - 1 ) ) { if ( $nopostorder[$i] == $moveitem && ( ( $FORM{'moveup'} && $i > 0 && $i <= $#nopostorder ) || ( $FORM{'movedown'} && $i < $#nopostorder && $i >= 0 ) ) ) { my $j = $FORM{'moveup'} ? $i - 1 : $i + 1; $nopostorder[$i] = $nopostorder[$j]; $nopostorder[$j] = $moveitem; last; } } } require Admin::NewSettings; SaveSettingsTo('Settings.pm'); # save @nopostorder $yySetLocation = qq~$adminurl?action=reordergroup;thegroup=$moveitem~; redirectexit(); return; } 1;