mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-08-18 07:36:24 -07:00
Finish (mostly) ban page displaying contents according to the database
This commit is contained in:
parent
ad9d0989b2
commit
87628a8d92
14 changed files with 163 additions and 84 deletions
BIN
html/hittheroad.mp3
Normal file
BIN
html/hittheroad.mp3
Normal file
Binary file not shown.
BIN
html/hittheroad.ogg
Normal file
BIN
html/hittheroad.ogg
Normal file
Binary file not shown.
BIN
html/hittheroad.wav
Normal file
BIN
html/hittheroad.wav
Normal file
Binary file not shown.
BIN
html/permabanned.jpg
Normal file
BIN
html/permabanned.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.6 KiB |
|
@ -12,22 +12,34 @@ CREATE TABLE IF NOT EXISTS `DBPREFIXannouncements` (
|
|||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `DBPREFIXappeals` (
|
||||
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`ban` INT(11) UNSIGNED NOT NULL,
|
||||
`message` TEXT NOT NULL,
|
||||
`timestamp` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`denied` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`staff_response` TEXT NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `DBPREFIXbanlist` (
|
||||
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`allow_read` TINYINT(1) DEFAULT '1',
|
||||
`ip` VARCHAR(45) NOT NULL DEFAULT '',
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`tripcode` CHAR(10) NOT NULL,
|
||||
`message` TEXT NOT NULL,
|
||||
`silent_ban` TINYINT(1) DEFAULT '0',
|
||||
`name_is_regex` TINYINT(1) DEFAULT '0',
|
||||
`filename` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
`file_checksum` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
`boards` VARCHAR(255) NOT NULL DEFAULT '*',
|
||||
`banned_by` VARCHAR(50) NOT NULL,
|
||||
`staff` VARCHAR(50) NOT NULL,
|
||||
`timestamp` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`expires` TIMESTAMP NULL,
|
||||
`permaban` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`reason` VARCHAR(255) NOT NULL,
|
||||
`type` TINYINT UNSIGNED NOT NULL DEFAULT '3',
|
||||
`staff_note` VARCHAR(255) NOT NULL,
|
||||
`appeal_message` VARCHAR(255) NOT NULL,
|
||||
`appeal_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`can_appeal` TINYINT(1) NOT NULL DEFAULT '1',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
|
|
|
@ -569,17 +569,17 @@ var manage_functions = map[string]ManageFunction{
|
|||
"bans": {
|
||||
Permissions: 1,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
rows, err := querySQL("SELECT `ip`,`name`,`tripcode`,`reason`,`boards`,`banned_by`,`timestamp`,`expires` FROM `" + config.DBprefix + "banlist`")
|
||||
rows, err := querySQL("SELECT `ip`,`name`,`reason`,`boards`,`staff`,`timestamp`,`expires` FROM `" + config.DBprefix + "banlist`")
|
||||
defer closeRows(rows)
|
||||
if err != nil {
|
||||
html += "<hr />" + handleError(1, err.Error())
|
||||
html += handleError(1, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var banlist []BanlistTable
|
||||
for rows.Next() {
|
||||
var ban BanlistTable
|
||||
rows.Scan(&ban.IP, &ban.Name, &ban.Tripcode, &ban.Reason, &ban.Boards, &ban.BannedBy, &ban.Timestamp, &ban.Expires)
|
||||
rows.Scan(&ban.IP, &ban.Name, &ban.Reason, &ban.Boards, &ban.Staff, &ban.Timestamp, &ban.Expires)
|
||||
banlist = append(banlist, ban)
|
||||
}
|
||||
manageBansBuffer := bytes.NewBufferString("")
|
||||
|
|
|
@ -564,12 +564,16 @@ func bumpThread(postID, boardID int) error {
|
|||
|
||||
// Checks check poster's name/tripcode/file checksum (from PostTable post) for banned status
|
||||
// returns ban table if the user is banned or errNotBanned if they aren't
|
||||
func getBannedStatus(post *PostTable, writer http.ResponseWriter) (BanlistTable, error) {
|
||||
func getBannedStatus(post *PostTable) (BanlistTable, error) {
|
||||
var banEntry BanlistTable
|
||||
err := queryRowSQL("SELECT `ip`, `name`, `reason`, `boards`, `timestamp`, `expires`, `appeal_at` FROM `"+config.DBprefix+"banlist` WHERE `ip` = ? ORDER BY `id` DESC LIMIT 1",
|
||||
[]interface{}{&post.IP},
|
||||
[]interface{}{&banEntry.IP, &banEntry.Name, &banEntry.Reason, &banEntry.Boards, &banEntry.Timestamp, &banEntry.Expires, &banEntry.AppealAt},
|
||||
err := queryRowSQL("SELECT `ip`,`name`,`boards`,`timestamp`,`expires`,`permaban`,`reason`,`type`,`appeal_at`,`can_appeal` FROM `"+config.DBprefix+"banlist` WHERE `ip` = ? OR `name` = ? OR `filename` = ? OR `file_checksum` = ? ORDER BY `id` DESC LIMIT 1",
|
||||
[]interface{}{&post.IP, &post.Name, &post.Filename, &post.FileChecksum},
|
||||
[]interface{}{
|
||||
&banEntry.IP, &banEntry.Name, &banEntry.Boards, &banEntry.Timestamp,
|
||||
&banEntry.Expires, &banEntry.Permaban, &banEntry.Reason, &banEntry.Type,
|
||||
&banEntry.AppealAt, &banEntry.CanAppeal},
|
||||
)
|
||||
println(1, banEntry.Timestamp)
|
||||
return banEntry, err
|
||||
}
|
||||
|
||||
|
@ -1016,13 +1020,12 @@ func makePost(writer http.ResponseWriter, request *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
banStatus, err := getBannedStatus(&post, writer)
|
||||
banStatus, err := getBannedStatus(&post)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
handleError(1, "Error in getBannedStatus: "+err.Error())
|
||||
serveErrorPage(writer, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if banStatus.IsBanned() {
|
||||
var banpage_buffer bytes.Buffer
|
||||
var banpage_html string
|
||||
|
|
|
@ -144,7 +144,7 @@ func initServer() {
|
|||
server.AddNamespace("util", utilHandler)
|
||||
server.AddNamespace("example", func(writer http.ResponseWriter, request *http.Request) {
|
||||
if writer != nil {
|
||||
_, _ = writer.Write([]byte("hahahaha"))
|
||||
http.Redirect(writer, request, "https://www.youtube.com/watch?v=dQw4w9WgXcQ", http.StatusFound)
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -183,7 +183,6 @@ func validReferrer(request *http.Request) bool {
|
|||
|
||||
// register /util handler
|
||||
func utilHandler(writer http.ResponseWriter, request *http.Request) {
|
||||
//writer.Header().Add("Content-Type", "text/css")
|
||||
action := request.FormValue("action")
|
||||
password := request.FormValue("password")
|
||||
board := request.FormValue("board")
|
||||
|
@ -377,7 +376,7 @@ func utilHandler(writer http.ResponseWriter, request *http.Request) {
|
|||
buildThreadPages(&postBoard)
|
||||
|
||||
writer.Header().Add("refresh", "4;url="+request.Referer())
|
||||
fmt.Fprintf(writer, "Attached image from %d deleted successfully\n", post.ID) //<br />\n<meta http-equiv=\"refresh\" content=\"1;url=/"+board+"/\">", post.ID)
|
||||
fmt.Fprintf(writer, "Attached image from %d deleted successfully\n", post.ID)
|
||||
} else {
|
||||
// delete the post
|
||||
if _, err = execSQL(
|
||||
|
|
51
src/sql.go
51
src/sql.go
|
@ -87,7 +87,7 @@ func connectToSQLServer() {
|
|||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
|
||||
checkDeprecatedSchema()
|
||||
println(0, "complete.")
|
||||
}
|
||||
|
||||
|
@ -158,3 +158,52 @@ func getSQLDateTime() string {
|
|||
func getSpecificSQLDateTime(t time.Time) string {
|
||||
return t.Format(mysqlDatetimeFormat)
|
||||
}
|
||||
|
||||
// checkDeprecatedSchema checks the tables for outdated columns and column values
|
||||
// and causes gochan to quit with an error message specific to the needed change
|
||||
func checkDeprecatedSchema() {
|
||||
var hasColumn int
|
||||
var err error
|
||||
|
||||
execSQL("ALTER TABLE `"+config.DBprefix+"banlist` CHANGE COLUMN `id` `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT", nil)
|
||||
|
||||
if err = queryRowSQL(
|
||||
"SELECT COUNT(*) FROM information_schema.COlUMNS WHERE `TABLE_SCHEMA` = '"+config.DBname+"' AND TABLE_NAME = '"+config.DBprefix+"banlist' AND COLUMN_NAME = 'appeal_message'",
|
||||
[]interface{}{}, []interface{}{&hasColumn},
|
||||
); err != nil {
|
||||
println(0, "error checking for deprecated column: "+err.Error())
|
||||
os.Exit(2)
|
||||
return
|
||||
}
|
||||
if hasColumn > 0 {
|
||||
// Running them one at a time, in case we get errors from individual queries
|
||||
execSQL("ALTER TABLE `"+config.DBprefix+"banlist` CHANGE COLUMN `banned_by` `staff` VARCHAR(50) NOT NULL", nil)
|
||||
execSQL("ALTER TABLE `"+config.DBprefix+"banlist` ADD COLUMN `type` TINYINT UNSIGNED NOT NULL DEFAULT '3'", nil)
|
||||
execSQL("ALTER TABLE `"+config.DBprefix+"banlist` ADD COLUMN `name_is_regex` TINYINT(1) DEFAULT '0'", nil)
|
||||
execSQL("ALTER TABLE `"+config.DBprefix+"banlist` ADD COLUMN `filename` VARCHAR(255) NOT NULL DEFAULT ''", nil)
|
||||
execSQL("ALTER TABLE `"+config.DBprefix+"banlist` ADD COLUMN `file_checksum` VARCHAR(255) NOT NULL DEFAULT ''", nil)
|
||||
execSQL("ALTER TABLE `"+config.DBprefix+"banlist` ADD COLUMN `permaban` TINYINT(1) DEFAULT '0'", nil)
|
||||
execSQL("ALTER TABLE `"+config.DBprefix+"banlist` ADD COLUMN `can_appeal` TINYINT(1) DEFAULT '1'", nil)
|
||||
execSQL("ALTER TABLE `"+config.DBprefix+"banlist` DROP COLUMN `message`", nil)
|
||||
|
||||
println(0, "The column `appeal_message` in table "+config.DBprefix+"banlist is deprecated. A new table , `"+config.DBprefix+"appeals` has been created for it, and the banlist table will be modified accordingly.")
|
||||
println(0, "Just to be safe, you may want to check both tables to make sure everything is good.")
|
||||
|
||||
rows, err := querySQL("SELECT `id`,`appeal_message` FROM `" + config.DBprefix + "banlist`")
|
||||
if err != nil {
|
||||
println(0, "Error updating banlist schema: "+err.Error())
|
||||
os.Exit(2)
|
||||
return
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
var id int
|
||||
var appeal_message string
|
||||
rows.Scan(&id, &appeal_message)
|
||||
if appeal_message != "" {
|
||||
execSQL("INSERT INTO `"+config.DBprefix+"appeals` (`ban`,`message`) VALUES(?,?)", &id, &appeal_message)
|
||||
}
|
||||
execSQL("ALTER TABLE `" + config.DBprefix + "banlist` DROP COLUMN `appeal_message`")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -225,6 +225,9 @@ var funcMap = template.FuncMap{
|
|||
tableOut += "</table>\n"
|
||||
return tableOut
|
||||
},
|
||||
"bannedForever": func(ban BanlistTable) bool {
|
||||
return ban.Permaban && !ban.CanAppeal && ban.Type == 3 && ban.Boards == ""
|
||||
},
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
52
src/types.go
52
src/types.go
|
@ -56,22 +56,44 @@ type AnnouncementsTable struct {
|
|||
Timestamp time.Time
|
||||
}
|
||||
|
||||
type BanlistTable struct {
|
||||
ID uint
|
||||
AllowRead bool
|
||||
IP string
|
||||
Name string
|
||||
Tripcode string
|
||||
type AppealsTable struct {
|
||||
ID int
|
||||
Ban int
|
||||
Message string
|
||||
SilentBan uint8
|
||||
Boards string
|
||||
BannedBy string
|
||||
Timestamp time.Time
|
||||
Expires time.Time
|
||||
Reason string
|
||||
StaffNote string
|
||||
AppealMessage string
|
||||
AppealAt time.Time
|
||||
Denied bool
|
||||
StaffResponse string
|
||||
}
|
||||
|
||||
func (a *AppealsTable) GetBan() (BanlistTable, error) {
|
||||
var ban BanlistTable
|
||||
var err error
|
||||
|
||||
err = queryRowSQL("SELECT * FROM `"+config.DBprefix+"banlist` WHERE `id` = ? LIMIT 1",
|
||||
[]interface{}{a.ID}, []interface{}{
|
||||
&ban.ID, &ban.AllowRead, &ban.IP, &ban.Name, &ban.NameIsRegex, &ban.SilentBan,
|
||||
&ban.Boards, &ban.Staff, &ban.Timestamp, &ban.Expires, &ban.Permaban, &ban.Reason,
|
||||
&ban.StaffNote, &ban.AppealAt},
|
||||
)
|
||||
return ban, err
|
||||
}
|
||||
|
||||
type BanlistTable struct {
|
||||
ID uint
|
||||
AllowRead bool
|
||||
IP string
|
||||
Name string
|
||||
NameIsRegex bool
|
||||
SilentBan uint8
|
||||
Boards string
|
||||
Staff string
|
||||
Timestamp time.Time
|
||||
Expires time.Time
|
||||
Permaban bool
|
||||
Reason string
|
||||
Type int
|
||||
StaffNote string
|
||||
AppealAt time.Time
|
||||
CanAppeal bool
|
||||
}
|
||||
|
||||
func (bt *BanlistTable) IsBanned() bool {
|
||||
|
|
14
src/util.go
14
src/util.go
|
@ -582,20 +582,6 @@ func makePostJSON(post PostTable, anonymous string) (postObj PostJSON) {
|
|||
return
|
||||
}
|
||||
|
||||
func getBan(post PostTable) (*BanlistTable, error) {
|
||||
ban := new(BanlistTable)
|
||||
|
||||
if err := queryRowSQL(
|
||||
"SELECT `ip`, `name`, `tripcode`, `message`, `boards`, `banned_by`, `timestamp`, `expires`, `reason` FROM `"+config.DBprefix+"banlist` "+
|
||||
"WHERE ? like `ip` OR ? REGEXP `name` OR ? REGEXP `tripcode`",
|
||||
[]interface{}{post.IP, post.Name, post.Tripcode},
|
||||
[]interface{}{&ban.IP, &ban.Name, &ban.Tripcode},
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ban, nil
|
||||
}
|
||||
|
||||
func ipMatch(newIP, existingIP string) bool {
|
||||
if newIP == existingIP {
|
||||
// both are single IPs and are the same
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<br /><br />
|
||||
<div class="section-block" style="margin: 0px 26px 0px 24px">
|
||||
<div class="section-title-block">
|
||||
<span class="section-title"><b>YOU ARE BANNED :(</b></span>
|
||||
<span class="section-title"><b>{{if bannedForever .ban}}YOUR'E BANNED, IDIOT!{{else}}YOU ARE BANNED :({{end}}</b></span>
|
||||
</div>
|
||||
<div class="section-body" style="padding-top:8px">
|
||||
<div id="ban-info" style="float:left">{{if eq $.ban.Boards ""}}
|
||||
|
@ -30,22 +30,26 @@
|
|||
You are banned from posting on <b>{{.ban.Boards}}</b> for the following reason:{{end}}
|
||||
<br /><br />
|
||||
<b>{{.ban.Reason}}</b>
|
||||
<br /><br />{{$expires_timestamp := formatTimestamp .ban.Expires}}{{$appeal_timestamp := formatTimestamp .ban.AppealAt}}{{if eq $expires_timestamp "Mon, January 01, 0001 00:00 AM"}}
|
||||
Your ban was placed on {{formatTimestamp .ban.Timestamp}} and will <b>not expire.</b><br />{{else}}
|
||||
Your ban was placed on <b>{{formatTimestamp .ban.Timestamp}}</b> and will expire on <b>{{$expires_timestamp}}</b><br />{{end}}
|
||||
<br />{{if eq $appeal_timestamp "Mon, January 01, 0001 00:00 AM"}}
|
||||
You may not appeal this ban.{{else}}
|
||||
You may appeal this ban on <b>{{$appeal_timestamp}}</b>.{{end}}
|
||||
<br /><br />
|
||||
<br /><br />{{$expires_timestamp := formatTimestamp .ban.Expires}}{{$appeal_timestamp := formatTimestamp .ban.AppealAt}}
|
||||
Your ban was placed on {{formatTimestamp .ban.Timestamp}} and will
|
||||
{{if .ban.Permaban}}<b>not expire</b>{{else}}expire on <b>{{$expires_timestamp}}</b>{{end}}.<br />
|
||||
Your IP address is <b>{{.ban.IP}}</b>.<br /><br />
|
||||
<form id="appeal-form">
|
||||
<table id="postbox-static">
|
||||
<tr><th class="postblock">Email</th><td><input type="email" name="email" /><input type="submit" value="Appeal" /></td></tr>
|
||||
<tr><th class="postblock">Message</th><td><textarea rows="4" cols="48" name="postmsg" id="postmsg"></textarea></td></tr>
|
||||
</table>
|
||||
</form>
|
||||
{{if .ban.CanAppeal}}You may appeal this ban:<br />
|
||||
<form id="appeal-form">
|
||||
<textarea rows="4" cols="48" name="postmsg" id="postmsg" placeholder="Appeal message"></textarea><br />
|
||||
<input type="submit" value="Submit" /><br />
|
||||
</form>{{else}}You may <b>not</b> appeal this ban.<br />{{end}}
|
||||
</div>
|
||||
{{if bannedForever .ban}}
|
||||
<img id="banpage-image" src="/permabanned.jpg" style="float:right; margin: 4px 8px 8px 4px"/><br />
|
||||
<audio id="jack" preload="auto" autobuffer loop>
|
||||
<source src="{{.config.SiteWebfolder}}hittheroad.ogg" />
|
||||
<source src="{{.config.SiteWebfolder}}hittheroad.wav" />
|
||||
<source src="{{.config.SiteWebfolder}}hittheroad.mp3" />
|
||||
</audio>
|
||||
<script type="text/javascript">
|
||||
document.getElementById("jack").play();
|
||||
</script>{{else}}<img id="banpage-image" src="/banned.jpg" style="float:right; margin: 4px 8px 8px 4px"/><br />{{end}}
|
||||
</div>
|
||||
<img id="banpage-image" src="/banned.jpg" style="float:right; margin: 4px 8px 8px 4px"/><br />
|
||||
</div>
|
||||
</div>
|
||||
{{template "global_footer.html" .}}
|
|
@ -2,32 +2,33 @@
|
|||
<form method="POST" action="/manage">
|
||||
<input type="hidden" name="action" value="bans" />
|
||||
|
||||
<fieldset><legend>User filter</legend>
|
||||
<b>IP address:</b> <input type="text" name="ip" /><br />
|
||||
"192.168.1.36" will ban posts from that IP address<br />
|
||||
"192.168" will block all IPs starting with 192.168<br /><hr />
|
||||
<b>Name!Tripcode:</b> <input type="text" name="name" /><br />
|
||||
<b>Ban filename:</b> <input type="text" name="filename" /><br />
|
||||
<b>Ban file checksum: </b> <i>3bdffa672fefe458223629815d3b63e1</i> <input type="checkbox" />
|
||||
</fieldset><br />
|
||||
<b>User filter:</b><br />
|
||||
<table>
|
||||
<tr><th>IP address</th><td><input type="text" name="ip" /></td></tr>
|
||||
<tr><th></th><td>"192.168.1.36" will ban posts from that IP address<br />
|
||||
"192.168" will block all IPs starting with 192.168<br /></td></tr>
|
||||
<tr><th>Name!Tripcode</th><td><input type="text" name="name" /> <label>Regex<input type="checkbox" name="nameregex" /></label></td></tr>
|
||||
<tr><th>Ban filename</th><td><input type="text" name="filename" /></td></tr>
|
||||
<tr><th>Ban file checksum</th><td>3bdffa672fefe458223629815d3b63e1 <input type="checkbox" /></td></tr>
|
||||
</table><br /><hr />
|
||||
|
||||
<fieldset><legend>Ban info</legend>
|
||||
<b>Duration:</b><sup title="e.g. '1y2mo3w4d5h6m7s', '1 year 2 months 3 weeks 4 days 5 hours 6 minutes 7 seconds' or 'forever', '0', or '' for a permaban">[?]</sup> <input type="text" name="ban-duration" /><br />
|
||||
<b>Ban type:</b><br />
|
||||
<label>Image ban <input type="checkbox" name="image-ban" /></label><br />
|
||||
<label>Thread starting ban <input type="checkbox" name="thread-ban" /></label><br />
|
||||
<label>Full ban (overrides the above) <input type="checkbox" name="full-ban" /></label><hr />
|
||||
<table class="baninfotable">
|
||||
<tr><td><b>Boards:</b><sup title="Comma-separated list of boards (e.g. board1,board2,board3) or blank for all boards">[?]</sup></td><td><input type="text" name="boards" /></td></tr>
|
||||
<tr><td><b>Reason:</b></td><td><textarea name="reason" rows="5" cols="30"></textarea></td></tr>
|
||||
<tr><td><b>Staff note:</b></td><td><input type="text" name="staff-note" /></td></tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
<b>Ban info</b><br />
|
||||
<table>
|
||||
<tr><th>Duration</th><td><input type="text" name="ban-duration" /></td></tr>
|
||||
<tr><th></th><td>e.g. '1y2mo3w4d5h6m7s',<br />'1 year 2 months 3 weeks 4 days 5 hours 6 minutes 7 seconds',<br /> or 'forever', '0', or '' for a permaban</td></tr>
|
||||
<tr><th>Ban type</th><td><label>Image ban <input type="checkbox" name="image-ban" /></label><br />
|
||||
<label>Thread starting ban <input type="checkbox" name="thread-ban" /></label><br />
|
||||
<label>Full ban (overrides the above) <input type="checkbox" name="full-ban" /></label></tr>
|
||||
<tr><th>Boards</th><td><input type="text" name="boards" /></td></tr>
|
||||
<tr><th></th><td>Comma-separated list of boards (e.g. board1,board2,board3) or blank for all boards</td></tr>
|
||||
<tr><th>Reason</th><td><textarea name="reason" rows="5" cols="30"></textarea></td></tr>
|
||||
<tr><th>Staff note</th><td><input type="text" name="staff-note" /></td></tr>
|
||||
</table>
|
||||
|
||||
<h2>Banlist</h2>
|
||||
<table>
|
||||
<th>IP</th><th>Name!Tripcode</th><th>Reason</th><th>Boards</th><th>Staff</th><th>Set</th><th>Expires</th>
|
||||
{{range $b, $ban := $.banlist}}<tr>
|
||||
<td>{{$ban.IP}}</td><td>{{$ban.Name}}</td><td>{{$ban.Reason}}</td><td>{{$ban.Boards}}</td><td>{{$ban.BannedBy}}</td><td>{{$ban.Timestamp}}</td><td>{{$ban.Expires}}</td>
|
||||
<td>{{$ban.IP}}</td><td>{{$ban.Name}}</td><td>{{$ban.Reason}}</td><td>{{if eq $ban.Boards ""}}<i>all boards</i>{{else}}{{$ban.Boards}}{{end}}</td><td>{{$ban.Staff}}</td><td>{{$ban.Timestamp}}</td><td>{{$ban.Expires}}</td>
|
||||
</tr>{{end}}
|
||||
</table>
|
Loading…
Add table
Add a link
Reference in a new issue