mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-08-02 19:16:23 -07:00
fixed database handling, fixed http handles, fixed configuration handling, added preliminary templating, etc
This commit is contained in:
parent
e6f6124a1f
commit
68b8c03980
45 changed files with 2742 additions and 632 deletions
2
build.sh
2
build.sh
|
@ -1,2 +1,2 @@
|
|||
#!/bin/bash
|
||||
go build -o gochan ./src
|
||||
go build -v -o gochan ./src
|
|
@ -1,95 +1,85 @@
|
|||
[server]
|
||||
domain = gochan.net
|
||||
port = 80
|
||||
document_root = /path/to/document_root/
|
||||
port = 8080
|
||||
first_page = board.html,index.html
|
||||
error_404_path = /error/404.html
|
||||
error_500_path = /error/500.html
|
||||
username = gochan
|
||||
|
||||
[directories]
|
||||
document_root = html
|
||||
template_dir = templates
|
||||
log_dir = log
|
||||
|
||||
[database]
|
||||
type = mysql
|
||||
host =
|
||||
host = unix(/var/run/mysqld/mysqld.sock)
|
||||
name = gochan
|
||||
username = myuser
|
||||
password = mypass
|
||||
prefix = gochan_
|
||||
username = root
|
||||
password = passwd
|
||||
prefix = gochan
|
||||
keepalive = false
|
||||
|
||||
[gochan]
|
||||
lockdown = false
|
||||
lockdown_message = We apologize for the downtime, but we are switching servers. Gochan wil be back up shortly
|
||||
lockdown_message = This is the message displayed to a user if they try to post when lockdown is set to true.
|
||||
sillytags = Admin,Mod,Janitor,Faget,Kick me,Derpy
|
||||
use_sillytags = false
|
||||
mod_board = secretmodfun
|
||||
|
||||
[site]
|
||||
name = Gochan
|
||||
slogan = "Do you like mmmmbananas?"
|
||||
headerurl =
|
||||
irc =
|
||||
banreason =
|
||||
allowdupes = true
|
||||
webfolder = /beta
|
||||
webpath = http://gochan.net/
|
||||
webfolder = /
|
||||
domain = gochan.net
|
||||
root_dir =
|
||||
template_dir = templates
|
||||
|
||||
[styles]
|
||||
styles = burichan,futaba
|
||||
default = burichan
|
||||
switcher = true
|
||||
dropdown_switcher = false
|
||||
styles = pipes,burichan,futaba,braeburn
|
||||
default_style = pipes
|
||||
styles_txt = buritxt,futaba
|
||||
default_txt-style = buritxt
|
||||
txt_style_switcher = true
|
||||
|
||||
menu_type = normal
|
||||
menu_styles = burichan:futaba
|
||||
default_menu_style = burichan
|
||||
menu_style_switcher = true
|
||||
default_txt_style = buritxt
|
||||
|
||||
[posting]
|
||||
allow_duplicate_images = true
|
||||
new_thread_delay = 30
|
||||
reply_delay = 7
|
||||
line_length = 150
|
||||
max_line_length = 150
|
||||
reserved_trips = "#from:To,#changeme2:changeme2"
|
||||
|
||||
[thumbnails]
|
||||
thumb_width = 200
|
||||
thumb_height = 200
|
||||
reply_thumb_width = 125
|
||||
reply_thumb_height = 125
|
||||
catalog_thumb_width = 50
|
||||
catalog_thumb_height = 50
|
||||
animated_thumbs = false
|
||||
|
||||
new_window = true
|
||||
make_links = true
|
||||
no_message_thread =
|
||||
no_message_reply =
|
||||
|
||||
|
||||
[threads]
|
||||
img_threads_per_page = 10
|
||||
txt_threads_per_page = 15
|
||||
replies_on_boardpage = 3
|
||||
sticky_replies_on_boardpage = 1
|
||||
thumb_msg = false
|
||||
ban_colors = Luna:#0000A0,PinkiePie#FF1493,Fleur de Lis:pink,Rainbow Dash:red
|
||||
ban_msg = <br /><span style=\"color: \""+GB_BANCOLOR+"\"><b>(USER WAS BANISHED AND THEN THROWN IN A DUNGEON IN THE PLACE THAT THEY WERE BANISHED TO FOR THIS POST)</b></span>
|
||||
traditional_read = false
|
||||
gen_last50_page = true
|
||||
gen_first100_page = false
|
||||
ban_colors = admin:#0000A0,mod#FF1493
|
||||
ban_msg = <br /><span style=\"color: \""+BANCOLOR+"\"><b>(USER WAS BANNED FOR THIS POST)</b></span>
|
||||
youtube_width = 200
|
||||
youtube_height = 164
|
||||
|
||||
first_page = board.html"
|
||||
use_dir_title = false
|
||||
|
||||
make_rss = true
|
||||
expand = true
|
||||
expand_button = true
|
||||
images_open_new_tab = true
|
||||
make_urls_hyperlinked = true
|
||||
new_tab_on_outlinks = true
|
||||
quick_reply = true
|
||||
watched_threads = true
|
||||
gen_firstlast_pages -= true
|
||||
use_blotter = true
|
||||
make_sitemap = false
|
||||
|
||||
[misc]
|
||||
default_ban_reason =
|
||||
enable_geoip = true
|
||||
max_recent_posts = 10
|
||||
make_rss = true
|
||||
make_sitemap = true
|
||||
enable_appeals = true
|
||||
|
||||
max_modlog_days = 14
|
||||
random_seed = String to use as seed for randomly generated fun
|
||||
use_static_menu = false
|
||||
generate_boardlist = true
|
||||
|
||||
date_format = D, F d, Y g:i A
|
||||
random_seed = DONT Taz3 m3 br0hgyuftyufrtderydrtiygyuigtd5456w53eyrtdughu
|
||||
enable_geoip = true
|
||||
geoip_location = /usr/share/GeoIP/GeoIP.dat
|
BIN
html/135683008384s.png
Normal file
BIN
html/135683008384s.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
html/135693079632s.png
Normal file
BIN
html/135693079632s.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -124,7 +124,8 @@ body {
|
|||
font-family:sans-serif;
|
||||
font-size:75%;
|
||||
margin:8px;
|
||||
width:90%;
|
||||
width:100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body,html {
|
||||
|
|
|
@ -22,6 +22,10 @@
|
|||
font-size:50px;
|
||||
}
|
||||
|
||||
#site-slogan {
|
||||
font-size:25px;
|
||||
}
|
||||
|
||||
#top-pane {
|
||||
height:75px;
|
||||
left:0;
|
||||
|
|
|
@ -4,7 +4,7 @@ body {
|
|||
background: #EEF2FF;
|
||||
color: #000;
|
||||
margin: 0;
|
||||
width: 90%;
|
||||
/*width: 90%;*/
|
||||
}
|
||||
#topmenu li {
|
||||
display: block;
|
||||
|
@ -38,6 +38,8 @@ div#loginbox {
|
|||
top:50%;
|
||||
margin-left: -100px;
|
||||
margin-top: -35px;
|
||||
padding-top:5px;
|
||||
padding-bottom:5px;
|
||||
text-align: center;
|
||||
border: solid 1px;
|
||||
}
|
||||
|
|
127
html/css/global/front.css
Normal file
127
html/css/global/front.css
Normal file
|
@ -0,0 +1,127 @@
|
|||
#footer {
|
||||
clear:both;
|
||||
position:absolute;
|
||||
width: 100%;
|
||||
left: 0px;
|
||||
bottom: 0%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#main {
|
||||
position:absolute;
|
||||
top:124px;
|
||||
left:16%;
|
||||
height: 100%;
|
||||
right:21%;
|
||||
width:auto;
|
||||
}
|
||||
|
||||
#menu {
|
||||
position:absolute;
|
||||
|
||||
}
|
||||
|
||||
#side-pane {
|
||||
position:absolute;
|
||||
top: 106px;
|
||||
width:15%;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
#site-title {
|
||||
font-size:50px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#tab-bar {
|
||||
margin-left: 16px;
|
||||
clear:both;
|
||||
}
|
||||
|
||||
#topmenu {
|
||||
position:absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
display: block;
|
||||
z-index:10;}
|
||||
|
||||
.topmenu-item {
|
||||
display: block;
|
||||
float: left;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.plus {
|
||||
width: 12px;
|
||||
text-align: center;
|
||||
float:right;
|
||||
padding: 0px 4px 0px 4px;
|
||||
}
|
||||
|
||||
.tab {
|
||||
padding-right: 5px;
|
||||
padding-left: 5px;
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.section-body {
|
||||
overflow: hidden;
|
||||
margin-right: 0px;
|
||||
margin-bottom:8px;
|
||||
right:0px;
|
||||
min-height: 48px;
|
||||
}
|
||||
|
||||
.section-block {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
#top-pane {
|
||||
left:0;
|
||||
position:absolute;
|
||||
text-align:center;
|
||||
top:32px;
|
||||
width:100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#content {
|
||||
clear:left;
|
||||
margin-left:0!important;
|
||||
padding-left:0!important;
|
||||
text-align:justify;
|
||||
}
|
||||
|
||||
#recent-posts {
|
||||
float:right;
|
||||
margin-top: 98px;
|
||||
overflow: hidden;
|
||||
right: 8px;
|
||||
width:20%;
|
||||
}
|
||||
|
||||
#recent-posts img {
|
||||
float: left;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
#recent-posts .section-body {
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
.section-title-block {
|
||||
display:block;
|
||||
}
|
||||
|
||||
a.permalink {
|
||||
float: right;
|
||||
}
|
||||
|
||||
ul.boardmenu {
|
||||
list-style:none;
|
||||
margin:0;
|
||||
padding-left:0;
|
||||
}
|
||||
|
0
html/css/global/img.css
Normal file
0
html/css/global/img.css
Normal file
27
html/css/global/manage.css
Normal file
27
html/css/global/manage.css
Normal file
|
@ -0,0 +1,27 @@
|
|||
.loginbox {
|
||||
width:300px;
|
||||
height: 120px;
|
||||
position: absolute;
|
||||
left:50%;
|
||||
top:50%;
|
||||
margin-left: -150px;
|
||||
margin-top: -60px;
|
||||
padding-top:5px;
|
||||
padding-bottom:5px;
|
||||
text-align: center;
|
||||
border: solid 1px;
|
||||
}
|
||||
|
||||
.loginbox input {
|
||||
width:175px;
|
||||
height: 30%;
|
||||
}
|
||||
|
||||
#footer {
|
||||
clear:both;
|
||||
position:absolute;
|
||||
width: 100%;
|
||||
left: 0px;
|
||||
bottom: 0%;
|
||||
text-align: center;
|
||||
}
|
0
html/css/global/txt.css
Normal file
0
html/css/global/txt.css
Normal file
BIN
html/css/int-sprites.png
Normal file
BIN
html/css/int-sprites.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.3 KiB |
|
@ -1,76 +1,52 @@
|
|||
#main {
|
||||
border-bottom:10px!important;
|
||||
height:85%;
|
||||
left:16%;
|
||||
position:absolute;
|
||||
top:96px;
|
||||
width:auto;
|
||||
}
|
||||
|
||||
#menu {
|
||||
border:0;
|
||||
height:100%;
|
||||
left:0;
|
||||
margin-left:5px;
|
||||
padding:0;
|
||||
position:absolute;
|
||||
top:75px;
|
||||
width:15%;
|
||||
#footer {
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
#site-title {
|
||||
background: inherit;
|
||||
clear: both;
|
||||
color: #e1b400;
|
||||
font-family: sans-serif;
|
||||
font-size:50px;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#top-pane {
|
||||
height:75px;
|
||||
left:0;
|
||||
position:absolute;
|
||||
#current-tab {
|
||||
background-color: #404040;
|
||||
}
|
||||
|
||||
.tab {
|
||||
background-color: #202020;
|
||||
border: 1px solid #424242;
|
||||
text-align:center;
|
||||
top:0;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.section-body {
|
||||
background-color:#606060;
|
||||
padding-left:8px;
|
||||
padding-right: 8px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.section-title-block {
|
||||
height:19px;
|
||||
background-color:#202020;
|
||||
border-radius: 4px 4px 0px 0px;
|
||||
padding-left:8px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
#topmenu {
|
||||
left:20%;
|
||||
padding-bottom:5;
|
||||
position:absolute;
|
||||
top:78px;
|
||||
z-index: 2;
|
||||
box-shadow: 0 2px 2px 3px #101010;
|
||||
background-color: #202020;
|
||||
height: 26px;
|
||||
}
|
||||
|
||||
#topmenu li {
|
||||
background-color:#404040;
|
||||
border:1px solid #9295a4;
|
||||
border-left:none;
|
||||
border-bottom: none;
|
||||
display:block;
|
||||
float:left;
|
||||
margin-top:-7px;
|
||||
padding:3px 10px 2px;
|
||||
.topmenu-item {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
#topmenu li.current {
|
||||
background-color:#202020;
|
||||
border-bottom:none;
|
||||
margin-top:-8px;
|
||||
padding-top:2px;
|
||||
.topmenu-item:hover {
|
||||
background-color: #404040;
|
||||
}
|
||||
|
||||
#topmenu li.first {
|
||||
border-left:1px solid #9295a4;
|
||||
}
|
||||
#topmenu a {
|
||||
|
||||
.content {
|
||||
margin-left:0!important;
|
||||
padding-left:0!important;
|
||||
text-align:justify;
|
||||
}
|
||||
|
||||
.menu {
|
||||
|
@ -78,44 +54,26 @@
|
|||
text-align:center;
|
||||
}
|
||||
|
||||
.newssub {
|
||||
position:absolute;
|
||||
background-color: #202020;
|
||||
}
|
||||
|
||||
.permalink {
|
||||
display:block;
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
.permalink a {
|
||||
a.permalink {
|
||||
background: inherit;
|
||||
color: #f90;
|
||||
font-family: sans-serif;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.permalink a:hover {
|
||||
a.permalink:hover {
|
||||
background: inherit;
|
||||
color: #ffd43f;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.plus {
|
||||
background:#404040;
|
||||
border-radius: 15px;
|
||||
color:#000;
|
||||
cursor:pointer;
|
||||
float:right;
|
||||
font-size:12px;
|
||||
height:inherit;
|
||||
font-weight:400;
|
||||
margin:0;
|
||||
padding:1px 4px 2px;
|
||||
}
|
||||
|
||||
.plus:hover {
|
||||
background:#c5c9e0;
|
||||
border:1px solid #c97;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
a {
|
||||
|
@ -132,79 +90,24 @@ a:hover {
|
|||
}
|
||||
|
||||
body {
|
||||
background:#EEF2FF;
|
||||
color:#000;
|
||||
font-family:sans-serif;
|
||||
font-size:75%;
|
||||
margin:8px;
|
||||
width:90%;
|
||||
}
|
||||
|
||||
body,html {
|
||||
margin:0;
|
||||
padding:0;
|
||||
background: #32353d;
|
||||
background: #EEF2FF;
|
||||
background-attachment: fixed;
|
||||
background-image: url(images/pipes_bg.png);
|
||||
color: #d8d0b9;
|
||||
font-family:sans-serif;
|
||||
font-size: 12pt;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color:#000;
|
||||
font-size:150%;
|
||||
margin:0;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
h1,h2 {
|
||||
h2 {
|
||||
background-color: #202020;
|
||||
-moz-box-shadow: 2px 2px 3px 4px #101010;
|
||||
-webkit-box-shadow: 2px 2px 3px 4px #101010;
|
||||
box-shadow: 0 2px 2px 3px #101010;
|
||||
border-radius: 8px;
|
||||
text-align:left;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
h1,h3,.menu {
|
||||
font-family:Verdana,Tahoma,sans-serif;
|
||||
}
|
||||
|
||||
h2 {
|
||||
border-radius: 8px;
|
||||
font-size:100%;
|
||||
margin:1em 0 0;
|
||||
}
|
||||
|
||||
h2 a {
|
||||
color:#550;
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
h3 {
|
||||
color:#800;
|
||||
font-size:medium;
|
||||
font-weight:400;
|
||||
margin:0;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
li {
|
||||
margin:0;
|
||||
}
|
||||
|
||||
li a {
|
||||
display:block;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
ul.boardmenu li:hover,ul.modmenulink li:hover {
|
||||
ul.boardmenu li:hover {
|
||||
background:#404040;
|
||||
}
|
||||
|
||||
ul.boardmenu,ul.modmenulink,div#topmenu ul {
|
||||
list-style:none;
|
||||
margin:0;
|
||||
padding-left:0;
|
||||
}
|
||||
|
||||
|
|
106
html/css/pipes/manage.css
Normal file
106
html/css/pipes/manage.css
Normal file
|
@ -0,0 +1,106 @@
|
|||
#footer {
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
#current-tab {
|
||||
background-color: #404040;
|
||||
}
|
||||
|
||||
.tab {
|
||||
background-color: #202020;
|
||||
border: 1px solid #424242;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.section-body {
|
||||
background-color:#606060;
|
||||
padding-left:8px;
|
||||
padding-right: 8px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.section-title-block {
|
||||
height:19px;
|
||||
background-color:#202020;
|
||||
border-radius: 4px 4px 0px 0px;
|
||||
padding-left:8px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
#topmenu {
|
||||
box-shadow: 0 2px 2px 3px #101010;
|
||||
background-color: #202020;
|
||||
height: 26px;
|
||||
}
|
||||
|
||||
.topmenu-item {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.topmenu-item:hover {
|
||||
background-color: #404040;
|
||||
}
|
||||
|
||||
#topmenu a {
|
||||
|
||||
}
|
||||
|
||||
.loginbox {
|
||||
|
||||
}
|
||||
.loginbox input {
|
||||
height:20%;
|
||||
}
|
||||
|
||||
.menu {
|
||||
margin-top:1em;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.plus {
|
||||
background:#404040;
|
||||
color:#000;
|
||||
height:inherit;
|
||||
font-weight:400;
|
||||
}
|
||||
|
||||
.plus:hover {
|
||||
background:#c5c9e0;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
a {
|
||||
background: inherit;
|
||||
color: #f90;
|
||||
font-family: sans-serif;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
background: inherit;
|
||||
color: #ffd43f;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
background: #EEF2FF;
|
||||
background-attachment: fixed;
|
||||
background-image: url(images/pipes_bg.png);
|
||||
color: #d8d0b9;
|
||||
font-family:sans-serif;
|
||||
font-size: 12pt;
|
||||
}
|
||||
h2 {
|
||||
background-color: #202020;
|
||||
-moz-box-shadow: 2px 2px 3px 4px #101010;
|
||||
-webkit-box-shadow: 2px 2px 3px 4px #101010;
|
||||
box-shadow: 0 2px 2px 3px #101010;
|
||||
border-radius: 8px;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
ul.boardmenu li:hover {
|
||||
background:#404040;
|
||||
}
|
||||
|
13
html/error/404.html
Normal file
13
html/error/404.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Error 404: File not Found</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>404: File not found</h1>
|
||||
<!--<img src="/error.png" border="0" alt=""> -->
|
||||
<p>The requested file could not be found on this server. Are you just typing random stuff in the address bar? If you followed a link from this site here, then post <a href="/site">here</a></p>
|
||||
<audio src="http://dl.dropbox.com/u/10266670/forever.wav" autoplay="autoplay"></audio>
|
||||
<hr><address>http://lunachan.net powered by Gochan v0.1</address>
|
||||
</body>
|
||||
</html>
|
12
html/error/500.html
Normal file
12
html/error/500.html
Normal file
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Error 500: Internal Server error</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>500: Internal Server error</h1>
|
||||
<marquee><img src="/error/derpy server.gif" border="0" alt=""></marquee>
|
||||
<p>Someone let Derpy into the server room again...sorry about that. Please try reloading the page. If that doesn't fix the problem, you can email me <a href="mailto:admin@lunachan.net">here</a>, noting the time and the page you tried to access.
|
||||
<hr><address>http://lunachan.net powered by Gochan v0.2</address>
|
||||
</body>
|
||||
</html>
|
11
html/error/500_example.html
Normal file
11
html/error/500_example.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Error 500: Internal Server error</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>500: Internal Server error</h1>
|
||||
<p>The server encountered an error while trying to serve the page. We apologize for the inconvenience.</p>
|
||||
<hr><address>http://lunachan.net powered by Gochan v0.2</address>
|
||||
</body>
|
||||
</html>
|
BIN
html/error/derpy server.gif
Normal file
BIN
html/error/derpy server.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 144 KiB |
200
html/index.html
200
html/index.html
|
@ -1,34 +1,166 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>It worked!</title>
|
||||
<script type="text/javascript" src="javascript/jquery/jquery-1.7.2.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
$jq = jQuery.noConflict();
|
||||
$jq(document).ready(function() {
|
||||
var killserver_btn = $jq("button#killserver");
|
||||
|
||||
$jq("button#killserver").click(function() {
|
||||
$jq.ajax({
|
||||
method:'GET',
|
||||
url:"/manage",
|
||||
data: {
|
||||
action: 'killserver'
|
||||
},
|
||||
|
||||
success: function() {
|
||||
|
||||
},
|
||||
error:function() {
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
It works!<br />
|
||||
<button id="killserver">Kill server</button>
|
||||
</body>
|
||||
</html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Lunachan</title>
|
||||
<script type="text/javascript" src="/javascript/jquery/jquery-1.7.2.min.js"></script>
|
||||
<script type="text/javascript" src="/javascript/gochan.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="/css/global/front.css" />
|
||||
<link rel="stylesheet" href="/css/pipes/front.css" />
|
||||
<link rel="alternate stylesheet" href="/css/burichan/front.css" />
|
||||
<link rel="alternate stylesheet" href="/css/futaba/front.css" />
|
||||
<link rel="alternate stylesheet" href="/css/braeburn/front.css" />
|
||||
<link rel="alternate stylesheet" href="/css/leetchan/front.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
<div id="topmenu">
|
||||
<div class="topmenu-section">
|
||||
<div class="topmenu-item">
|
||||
<a href="/test1/">/test1/</a>
|
||||
</div>
|
||||
<div class="topmenu-item">
|
||||
<a href="/test2/">/test2/</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="top-pane">
|
||||
<span id="site-title">Lunachan</span><br />
|
||||
<span id="site-slogan">Do you like mmmmmmbananas?</span>
|
||||
</div>
|
||||
|
||||
<div id="side-pane">
|
||||
<h2>Boards</h2>
|
||||
<div class="section-block">
|
||||
<div class="section-title-block">
|
||||
<b>Section 1</b><span class="plus">-</span>
|
||||
</div>
|
||||
<div class="section-body">
|
||||
<ul class="boardmenu">
|
||||
<a href="/test/"><li id="test" class="boardmenu-item">Test</li></a>
|
||||
<a href="/test2/"><li id="test" class="boardmenu-item">Test2</li></a>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-block">
|
||||
<div class="section-title-block">
|
||||
<b>Section 2</b><span class="plus">-</span>
|
||||
</div>
|
||||
<div class="section-body">
|
||||
<ul class="boardmenu">
|
||||
<a href="/test/"><li id="test" class="boardmenu-item">Test</li></a>
|
||||
<a href="/test2/"><li id="test" class="boardmenu-item">Test2</li></a>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main">
|
||||
<div id="tab-bar">
|
||||
<div id="current-tab" class="tab">
|
||||
<a href="#">Home</a>
|
||||
</div>
|
||||
<div class="tab">
|
||||
<a href="#rules">Rules</a>
|
||||
</div>
|
||||
<div class="tab">
|
||||
<a href="#faq">FAQ</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="content">
|
||||
<div id="first-page" class="page">
|
||||
<div class="section-block">
|
||||
<div class="section-title-block" id="first-page0">
|
||||
<b>A news message thingy</b> by <a href="mailto:admin@lunachan.net" >Luna</a><a href="/#first-page0" class="permalink">#</a>
|
||||
</div>
|
||||
<div class="section-body">
|
||||
Some funky news stuff would go here
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-block">
|
||||
<div class="section-title-block">
|
||||
<b>A news message thingy</b> by <a href="mailto:admin@lunachan.net" class="section-poster">Luna</a>
|
||||
</div>
|
||||
<div class="section-body">
|
||||
Some funky news stuff would go here
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="rules-page" class="page">
|
||||
<div class="section-block">
|
||||
<div class="section-title-block">
|
||||
<b>Rules</b> by <a href="mailto:admin@lunachan.net" class="section-poster">Luna</a>
|
||||
</div>
|
||||
<div class="section-body">
|
||||
Don't talk about Gochan.<br />
|
||||
Do NOT talk about Gochan.<br />
|
||||
Purple pone is best pone, no exceptions.<br />
|
||||
No Comic Sans, breakers of this rule will be permabanned without warning<br />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="faq-page" class="page">
|
||||
<div class="section-block">
|
||||
<div class="section-title-block">
|
||||
<b>A FAQ message thingy</b> by <a href="mailto:admin@lunachan.net" class="section-poster">Luna</a>
|
||||
</div>
|
||||
<div class="section-body">
|
||||
Some funky FAQ stuff would go here
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-block">
|
||||
<div class="section-title-block">
|
||||
<b>A FAQ message thingy</b> by <a href="mailto:admin@lunachan.net" class="section-poster">Luna</a>
|
||||
</div>
|
||||
<div class="section-body">
|
||||
Some funky FAQ stuff would go here
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<a href="/">Home</a> | <a href="http://127.0.0.1:8080/#boards">Boards</a> | <a href="http://127.0.0.1:8080/#rules">Rules</a> | <a href="http://127.0.0.1:8080/#faq">FAQ</a><br />
|
||||
Powered by Gochan v0.2<br />
|
||||
Generated in over 9000 hours
|
||||
</div>
|
||||
</div>
|
||||
<div id="recent-posts">
|
||||
<h2>Recent Posts</h2>
|
||||
<div class="section-block">
|
||||
<div class="section-title-block">
|
||||
<span class="section-title"><a href="/test/">/test/</a></span> - <b>Poster Mc</b>!Tripcode
|
||||
</div>
|
||||
<div class="section-body">
|
||||
<img src="135693079632s.png" />
|
||||
TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT TOOT...<br /><i>(Comment truncated, click <a href="/test/">here</a> to continue reading)</i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-block">
|
||||
<div class="section-title-block">
|
||||
<span class="section-title"><a href="/test/">/test/</a></span> - <b>Anonymous</b>
|
||||
</div>
|
||||
<div class="section-body">
|
||||
OP is a pony.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-block">
|
||||
<div class="section-title-block">
|
||||
<span class="section-title"><a href="/test/">/test/</a></span> - <b>Poster Mc</b>!Tripcode
|
||||
</div>
|
||||
<div class="section-body">
|
||||
<img src="135683008384s.png" />
|
||||
<a href="#">>>22222</a><br />
|
||||
HERP DERP FROSTED BUTTS
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,118 @@
|
|||
var $jq = jQuery.noConflict();
|
||||
|
||||
|
||||
function changeFrontPage(page_name) {
|
||||
var tabs = $jq(".tab");
|
||||
var pages = $jq(".page");
|
||||
var current_page = getHashVal();
|
||||
pages.hide();
|
||||
if(current_page=="") {
|
||||
$jq(pages[0]).show();
|
||||
} else {
|
||||
for(var p = 0; p < pages.length; p++) {
|
||||
var page = $jq(pages[p]);
|
||||
if(page.attr("id").replace("-page","").replace("page","") == current_page) {
|
||||
page.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(var i = 0; i < tabs.length; i++) {
|
||||
var child = $jq(tabs[i]).children(0)
|
||||
var tabname = child.text();
|
||||
if(tabname.toLowerCase() == current_page) {
|
||||
$jq("#current-tab").attr({"id":""});
|
||||
child.parent().attr({"id":"current-tab"});
|
||||
}
|
||||
}
|
||||
|
||||
tabs.find("a").click(function(event) {
|
||||
current_page = getHashVal($jq(this).attr("href"));
|
||||
|
||||
if(current_page == "") {
|
||||
$jq("#current-tab").attr({"id":""});
|
||||
$jq(tabs[0]).attr({"id":"current-tab"});
|
||||
} else {
|
||||
for(var i = 0; i < tabs.length; i++) {
|
||||
var child = $jq(tabs[i]).children(0)
|
||||
var tabname = child.text();
|
||||
if(tabname.toLowerCase() == current_page) {
|
||||
$jq("#current-tab").attr({"id":""});
|
||||
$jq(tabs[i]).attr({"id":"current-tab"});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pages.hide()
|
||||
if(current_page=="") {
|
||||
$jq(pages[0]).show();
|
||||
} else {
|
||||
for(var p = 0; p < pages.length; p++) {
|
||||
var page = $jq(pages[p]);
|
||||
if(page.attr("id").replace("-page","").replace("page","") == current_page) {
|
||||
page.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getArg(name) {
|
||||
var href = window.location.href;
|
||||
var args = href.substr(href.indexOf("?")+1, href.length);
|
||||
args = args.split("&");
|
||||
|
||||
for(var i = 0; i < args.length; i++) {
|
||||
temp_args = args[i];
|
||||
temp_args = temp_args.split("=");
|
||||
temp_name = temp_args[0];
|
||||
temp_value = temp_args[1];
|
||||
args[temp_name] = temp_value;
|
||||
args[i] = temp_args;
|
||||
}
|
||||
return args[name];
|
||||
}
|
||||
|
||||
function getHashVal() {
|
||||
var href = window.location.href;
|
||||
if(arguments.length == 1) {
|
||||
href = arguments[0];
|
||||
}
|
||||
if(href.indexOf("#") == -1) {
|
||||
return "";
|
||||
} else {
|
||||
var hash = href.substring(href.indexOf("#"),href.length);
|
||||
if(hash == "#") return ""
|
||||
else return hash.substring(1,hash.length);
|
||||
}
|
||||
}
|
||||
|
||||
function isFrontPage() {
|
||||
var page = window.location.pathname;
|
||||
return page == "/" || page == "/index.html";
|
||||
}
|
||||
|
||||
function isBoardPage() {
|
||||
|
||||
}
|
||||
|
||||
function isThreadPage() {
|
||||
|
||||
}
|
||||
|
||||
$jq(document).ready(function() {
|
||||
if(isFrontPage()) {
|
||||
changeFrontPage(getHashVal());
|
||||
}
|
||||
|
||||
$jq(".plus").click(function() {
|
||||
var block = $jq(this).parent().next();
|
||||
if(block.css("display") == "none") {
|
||||
block.show();
|
||||
$jq(this).html("-");
|
||||
} else {
|
||||
block.hide();
|
||||
$jq(this).html("+");
|
||||
}
|
||||
});
|
||||
});
|
37
html/javascript/linkmenu.js
Normal file
37
html/javascript/linkmenu.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
// Drop down link menu
|
||||
|
||||
var down_arrow_symbol = "▼";
|
||||
var up_arrow_symbol = "▲";
|
||||
|
||||
var $jq = jQuery.noConflict();
|
||||
|
||||
var LinkMenu = function(title) {
|
||||
this.linkURLs = [];
|
||||
this.linkTitles = [];
|
||||
this.buttonTitle = title;
|
||||
$jq("div#verytopbar").append("<a href=\"#\" style=\"float:right;\" class=\"dropdown-button\" id=\""+title.toLowerCase()+"\">"+title+"</a>");
|
||||
this.button_jq = $jq("a#"+title.);
|
||||
this.button_jq.click(function(){
|
||||
$jq(document.body).append("<div id="+title.toLowerCase())
|
||||
})
|
||||
}
|
||||
|
||||
LinkMenu.prototype.open = function() {
|
||||
|
||||
}
|
||||
|
||||
LinkMenu.prototype.close = function() {
|
||||
|
||||
}
|
||||
|
||||
LinkMenu.prototype.isOpen = function() {
|
||||
|
||||
}
|
||||
|
||||
LinkMenu.prototype.addLink = function() {
|
||||
|
||||
}
|
||||
|
||||
LinkMenu.prototype.buildHTML = function() {
|
||||
|
||||
}
|
25
html/linkmenu.html
Normal file
25
html/linkmenu.html
Normal file
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Link menu test</title>
|
||||
<script type="text/javascript" src="javascript/jquery/jquery-1.7.2.min.js"></script>
|
||||
<script type="text/javascript" src="javascript/linkmenu.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="css/burichan/img.css"></link>
|
||||
<script type="text/javascript">
|
||||
var $jq = jQuery.noConflict();
|
||||
var mod_menu;
|
||||
|
||||
$jq(document).ready(function(){
|
||||
mod_menu = new LinkMenu("Manage")
|
||||
|
||||
})
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="verytopbar"><a href="#">/test/</a> | <a href="#">/test/</a></div>
|
||||
<br />
|
||||
<div id="main">
|
||||
bleh
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1 @@
|
|||
Board page
|
|
@ -6,8 +6,8 @@
|
|||
<body>
|
||||
<h1>Upload file</h1>
|
||||
|
||||
<form action="/upload" method="POST" id="uploadform" enctype="multipart/form-data">
|
||||
<input type="file" id="fileinput" multiple="true" name="file">
|
||||
<form action="/post" method="POST" id="uploadform" enctype="multipart/form-data">
|
||||
<input type="file" id="file" multiple="false" name="file">
|
||||
<input type="submit" id="filesubmit" value="Upload">
|
||||
</form>
|
||||
|
||||
|
|
|
@ -1,2 +1,266 @@
|
|||
-- Initial setup file for Gochan
|
||||
-- Deleted after setup is finished
|
||||
-- Deleted after setup is finished
|
||||
|
||||
CREATE DATABASE `DBNAME`;
|
||||
USE `DBNAME`;
|
||||
|
||||
CREATE TABLE `DBPREFIXannouncements` (
|
||||
`id` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`subject` VARCHAR(45) NOT NULL,
|
||||
`message` TEXT NOT NULL,
|
||||
`poster` VARCHAR(45) NOT NULL,
|
||||
`timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `DBPREFIXbanlist` (
|
||||
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`expired` TINYINT(1) DEFAULT '0',
|
||||
`allow_read` TINYINT(1) DEFAULT '1',
|
||||
`ip` CHAR(15) NOT NULL,
|
||||
`silent_ban` TINYINT(1) DEFAULT '0',
|
||||
`boards` VARCHAR(255) NOT NULL,
|
||||
`banned_by` VARCHAR(50) NOT NULL,
|
||||
`timestamp` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`expires` TIMESTAMP NOT NULL,
|
||||
`reason` VARCHAR(255) NOT NULL,
|
||||
`staff_note` VARCHAR(255) NOT NULL,
|
||||
`appeal` VARCHAR(255) NOT NULL,
|
||||
`appeal_at` TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `DBPREFIXbannedhashes` (
|
||||
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`checksum` VARCHAR(45) NOT NULL,
|
||||
`description` VARCHAR(45) NOT NULL,
|
||||
PRIMARY KEY(`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `DBPREFIXbannedtripcodes` (
|
||||
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`tripcode` CHAR(10) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `DBPREFIXboards` (
|
||||
`id` TINYINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`order` TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
`dir` VARCHAR(45) NOT NULL,
|
||||
`type` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`first_post` INT UNSIGNED NOT NULL DEFAULT 1,
|
||||
`upload_type` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`title` VARCHAR(45) NOT NULL,
|
||||
`subtitle` VARCHAR(64) NOT NULL,
|
||||
`section` VARCHAR(45) NOT NULL,
|
||||
`max_image_size` INT UNSIGNED NOT NULL DEFAULT 4718592,
|
||||
`max_pages` TINYINT UNSIGNED NOT NULL DEFAULT 11,
|
||||
`locale` VARCHAR(10) NOT NULL DEFAULT 'en-us',
|
||||
`default_style` VARCHAR(45) NOT NULL,
|
||||
`locked` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`created_on` TIMESTAMP NOT NULL,
|
||||
`anonymous` VARCHAR(15) NOT NULL DEFAULT 'Anonymous',
|
||||
`forced_anon` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`max_age` INT(20) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`mark_page` TINYINT UNSIGNED NOT NULL DEFAULT 9,
|
||||
`autosage_after` INT(5) UNSIGNED NOT NULL DEFAULT 200,
|
||||
`no_images_after` INT(5) UNSIGNED NOT NULL,
|
||||
`max_message_length` INT(10) UNSIGNED NOT NULL DEFAULT 8192,
|
||||
`embeds_allowed` VARCHAR(45) NOT NULL,
|
||||
`redirect_to_thread` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`show_id` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`compact_list` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`enable_nofile` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`enable_catalog` TINYINT(1) UNSIGNED NOT NULL DEFAULT 1,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `DBPREFIXsections` (
|
||||
`id` TINYINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`order` TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
`hidden` TINYINT(1) UNSIGNED NOT NULL,
|
||||
`name` VARCHAR(45) NOT NULL,
|
||||
`abbreviation` VARCHAR(10) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `DBPREFIXembeds` (
|
||||
`id` TINYINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`filetype` CHAR(3) NOT NULL,
|
||||
`name` VARCHAR(45) NOT NULL,
|
||||
`video_url` VARCHAR(255) NOT NULL,
|
||||
`width` SMALLINT UNSIGNED NOT NULL,
|
||||
`height` SMALLINT UNSIGNED NOT NULL,
|
||||
`embed_code` TEXT NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `DBPREFIXfiletypes` (
|
||||
`id` TINYINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`filetype` VARCHAR(10) NOT NULL,
|
||||
`mime` VARCHAR(45) NOT NULL,
|
||||
`thumb_image` VARCHAR(255) NOT NULL,
|
||||
`image_w` INT UNSIGNED NOT NULL DEFAULT 0,
|
||||
`image_h` INT UNSIGNED NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `DBPREFIXfrontpage` (
|
||||
`id` SMALLINT(5) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`page` TINYINT(3) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`order` TINYINT(3) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`subject` VARCHAR(140) NOT NULL,
|
||||
`message` TEXT NOT NULL,
|
||||
`timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`poster` VARCHAR(45) NOT NULL,
|
||||
`email` VARCHAR(45) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `DBPREFIXlinks` (
|
||||
`id` TINYINT NOT NULL AUTO_INCREMENT,
|
||||
`title` VARCHAR(45) NOT NULL,
|
||||
`url` VARCHAR(255) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `DBPREFIXloginattempts` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`ip` CHAR(10) NOT NULL,
|
||||
`timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `DBPREFIXmodlog` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`entry` TEXT NOT NULL,
|
||||
`user` VARCHAR(45) NOT NULL,
|
||||
`category` TINYINT(2) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `DBPREFIXpollresults` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`ip` CHAR(10) NOT NULL,
|
||||
`selection` VARCHAR(62) NOT NULL,
|
||||
`timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `DBPREFIXposts` (
|
||||
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`boardid` TINYINT(3) UNSIGNED NOT NULL,
|
||||
`parentid` INT(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`name` VARCHAR(45) NOT NULL,
|
||||
`tripcode` CHAR(10) NOT NULL,
|
||||
`email` VARCHAR(45) NOT NULL,
|
||||
`subject` VARCHAR(64) NOT NULL,
|
||||
`message` TEXT NOT NULL,
|
||||
`password` VARCHAR(45) NOT NULL,
|
||||
`filename` VARCHAR(45) NOT NULL,
|
||||
`filename_original` VARCHAR(45) NOT NULL,
|
||||
`file_checksum` VARCHAR(45) NOT NULL,
|
||||
`filesize` INT(20) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`image_w` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`image_h` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`thumb_w` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`thumb_h` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`ip` CHAR(10) NOT NULL,
|
||||
`tag` VARCHAR(5) NOT NULL,
|
||||
`timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`autosage` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`poster_authority` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`deleted_timestamp` TIMESTAMP NULL DEFAULT NULL,
|
||||
`bumped` TIMESTAMP NULL DEFAULT NULL,
|
||||
`stickied` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`locked` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`reviewed` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`sillytag` VARCHAR(45) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `parentid` (`parentid`),
|
||||
KEY `bumped` (`bumped`),
|
||||
KEY `file_checksum` (`file_checksum`),
|
||||
KEY `stickied` (`stickied`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
|
||||
|
||||
CREATE TABLE `DBPREFIXtempposts` (
|
||||
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`boardid` SMALLINT(5) UNSIGNED NOT NULL,
|
||||
`parentid` INT(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`name` VARCHAR(45) NOT NULL,
|
||||
`tripcode` CHAR(10) NOT NULL,
|
||||
`email` VARCHAR(45) NOT NULL,
|
||||
`subject` VARCHAR(64) NOT NULL,
|
||||
`message` TEXT NOT NULL,
|
||||
`password` VARCHAR(45) NOT NULL,
|
||||
`filename` VARCHAR(45) NOT NULL,
|
||||
`filename_original` VARCHAR(45) NOT NULL,
|
||||
`file_checksum` VARCHAR(45) NOT NULL,
|
||||
`filesize` INT(20) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`image_w` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`image_h` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`thumb_w` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`thumb_h` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`ip` CHAR(10) NOT NULL,
|
||||
`tag` VARCHAR(5) NOT NULL,
|
||||
`TIMESTAMP` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`autosage` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`poster_authority` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`deleted_timestamp` TIMESTAMP NULL DEFAULT NULL,
|
||||
`bumped` TIMESTAMP NULL DEFAULT NULL,
|
||||
`stickied` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`locked` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`reviewed` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`sillytag` VARCHAR(45) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `parentid` (`parentid`),
|
||||
KEY `bumped` (`bumped`),
|
||||
KEY `file_checksum` (`file_checksum`),
|
||||
KEY `stickied` (`stickied`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
|
||||
|
||||
CREATE TABLE `DBPREFIXreports` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`board` VARCHAR(45) NOT NULL,
|
||||
`postid` INT(10) UNSIGNED NOT NULL,
|
||||
`timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`ip` CHAR(15) NOT NULL,
|
||||
`reason` VARCHAR(255) NOT NULL,
|
||||
`cleared` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`istemp` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `DBPREFIXsessions` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`key` CHAR(10) NOT NULL,
|
||||
`data` VARCHAR(45) NOT NULL,
|
||||
`expires` TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MEMORY DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `DBPREFIXstaff` (
|
||||
`id` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`username` VARCHAR(45) NOT NULL,
|
||||
`password_checksum` VARCHAR(120) NOT NULL,
|
||||
`salt` CHAR(3) NOT NULL,
|
||||
`rank` TINYINT(1) UNSIGNED NOT NULL,
|
||||
`boards` VARCHAR(128) NOT NULL DEFAULT 'all',
|
||||
`added_on` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`last_active` TIMESTAMP NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `DBPREFIXwordfilters` (
|
||||
`id` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`from` VARCHAR(75) NOT NULL,
|
||||
`to` VARCHAR(75) NOT NULL,
|
||||
`boards` TEXT NOT NULL,
|
||||
`regex` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
-- Create admin account so we can log in
|
||||
-- INSERT INTO `DBPREFIXstaff` (`username`,`password_checksum`,`salt`,`rank`) VALUES ('admin','24326124313024434b7a4f6267504a6631716b464e2f41353457785465766c484f4f766a387843415778696c507a6358504d574a3357794574395975','abc',3);
|
14
src/TODO
14
src/TODO
|
@ -1,11 +1,13 @@
|
|||
X Make sure error codes and caching work correctly
|
||||
- Clean up library dependencies
|
||||
- Set up daemonization
|
||||
+ Clean up config file template
|
||||
+ Clean up server.go
|
||||
- Set up load balancing
|
||||
- Clean up config file template
|
||||
- Set up HTTPS for management
|
||||
- gzip-encoding for html, css, and javascript
|
||||
- Set up backend mode, compatibility with nginx and Apache
|
||||
- Set up templating
|
||||
- Set up timezone adjusting
|
||||
- Set up new mod menu style, integrated with board pages
|
||||
- Set up fallback mod menu (like Kusaba)
|
||||
- Give administrator server control options (restart/shutdown daemon, etc)
|
||||
- Give administrator server control options (restart/shutdown daemon, etc)
|
||||
- Set up basic posting/board interaction
|
||||
- Set up thumbnailing/image uploading
|
||||
- find out what changes were made in Kusaba 0.9.3 to fix XSS vulnerability
|
5
src/boards.go
Normal file
5
src/boards.go
Normal file
|
@ -0,0 +1,5 @@
|
|||
package main
|
||||
|
||||
func makeImageBoard(board BoardsTable) error {
|
||||
return nil
|
||||
}
|
16
src/geoip.go
Normal file
16
src/geoip.go
Normal file
|
@ -0,0 +1,16 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/nranchev/go-libGeoIP"
|
||||
)
|
||||
|
||||
func getCountryCode(ip string) (string,error) {
|
||||
if config.EnableGeoIP && config.GeoIPDBlocation != "" {
|
||||
gi, err := libgeo.Load(config.GeoIPDBlocation)
|
||||
if err != nil {
|
||||
return "",err
|
||||
}
|
||||
return gi.GetLocationByIP(ip).CountryCode,nil
|
||||
}
|
||||
return "",nil
|
||||
}
|
|
@ -7,23 +7,27 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
pid, piderr uintptr
|
||||
version = 0.1
|
||||
err error
|
||||
version float32 = 0.2
|
||||
)
|
||||
|
||||
|
||||
func main() {
|
||||
//modlogentries := []ModLogEntry
|
||||
//posts := []Post
|
||||
_,err = os.Stat("initialsetupdb.sql")
|
||||
initConfig()
|
||||
fmt.Println("Config file loaded. Connecting to database...")
|
||||
_,err := os.Stat("initialsetupdb.sql")
|
||||
//check if initialsetup file exists
|
||||
if err != nil {
|
||||
needs_initial_setup = false
|
||||
connectToSQLServer(true)
|
||||
} else {
|
||||
needs_initial_setup = true
|
||||
runInitialSetup()
|
||||
}
|
||||
fmt.Println("Connecting to database...(no, not really)")
|
||||
//connectToDB()
|
||||
//dbTests()
|
||||
|
||||
fmt.Println("Loading and parsing templates...")
|
||||
initTemplates()
|
||||
fmt.Println("Initializing server...")
|
||||
go initServer()
|
||||
select {}
|
||||
|
|
45
src/initialsetup.go
Normal file
45
src/initialsetup.go
Normal file
|
@ -0,0 +1,45 @@
|
|||
// functions for setting up SQL tables and the base administrator account
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func runInitialSetup() {
|
||||
if !db_connected {
|
||||
connectToSQLServer(false)
|
||||
}
|
||||
loadInitialSetupFile()
|
||||
}
|
||||
|
||||
func loadInitialSetupFile() {
|
||||
initial_sql_bytes,err := ioutil.ReadFile("initialsetupdb.sql")
|
||||
initial_sql_str := string(initial_sql_bytes)
|
||||
fmt.Println("Starting initial setup...")
|
||||
if err == nil {
|
||||
initial_sql_str = strings.Replace(initial_sql_str,"DBNAME",config.DBname, -1)
|
||||
initial_sql_str = strings.Replace(initial_sql_str,"DBPREFIX",config.DBprefix, -1)
|
||||
initial_sql_str += "\nINSERT INTO `"+config.DBname+"`.`"+config.DBprefix+"staff` (`username`, `password_checksum`, `salt`, `rank`) VALUES ('admin', '"+bcrypt_sum("password")+"', 'abc', 3);"
|
||||
_,err := db.Start(initial_sql_str)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("Initial setup failed.")
|
||||
error_log.Write(err.Error())
|
||||
} else {
|
||||
/*_,err := db.Start("INSERT INTO `"+config.DBname+"`.`"+config.DBprefix+"_staff` (`username`, `password_checksum`, `salt`, `rank`) VALUES ('admin', '"+bcrypt_sum("password")+"', 'abc', 3);")
|
||||
if err != nil {
|
||||
fmt.Println("Failed creating administrator account.")
|
||||
error_log.Write(err.Error())
|
||||
} else {*/
|
||||
fmt.Println("Initial setup complete.")
|
||||
|
||||
}
|
||||
} else {
|
||||
error_log.Write("Couldn't load initial sql file")
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
247
src/lib/resize/resize.go
Normal file
247
src/lib/resize/resize.go
Normal file
|
@ -0,0 +1,247 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package resize
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
)
|
||||
|
||||
// Resize returns a scaled copy of the image slice r of m.
|
||||
// The returned image has width w and height h.
|
||||
func Resize(m image.Image, r image.Rectangle, w, h int) image.Image {
|
||||
if w < 0 || h < 0 {
|
||||
return nil
|
||||
}
|
||||
if w == 0 || h == 0 || r.Dx() <= 0 || r.Dy() <= 0 {
|
||||
return image.NewRGBA64(image.Rect(0, 0, w, h))
|
||||
}
|
||||
switch m := m.(type) {
|
||||
case *image.RGBA:
|
||||
return resizeRGBA(m, r, w, h)
|
||||
case *image.YCbCr:
|
||||
if m, ok := resizeYCbCr(m, r, w, h); ok {
|
||||
return m
|
||||
}
|
||||
}
|
||||
ww, hh := uint64(w), uint64(h)
|
||||
dx, dy := uint64(r.Dx()), uint64(r.Dy())
|
||||
// The scaling algorithm is to nearest-neighbor magnify the dx * dy source
|
||||
// to a (ww*dx) * (hh*dy) intermediate image and then minify the intermediate
|
||||
// image back down to a ww * hh destination with a simple box filter.
|
||||
// The intermediate image is implied, we do not physically allocate a slice
|
||||
// of length ww*dx*hh*dy.
|
||||
// For example, consider a 4*3 source image. Label its pixels from a-l:
|
||||
// abcd
|
||||
// efgh
|
||||
// ijkl
|
||||
// To resize this to a 3*2 destination image, the intermediate is 12*6.
|
||||
// Whitespace has been added to delineate the destination pixels:
|
||||
// aaab bbcc cddd
|
||||
// aaab bbcc cddd
|
||||
// eeef ffgg ghhh
|
||||
//
|
||||
// eeef ffgg ghhh
|
||||
// iiij jjkk klll
|
||||
// iiij jjkk klll
|
||||
// Thus, the 'b' source pixel contributes one third of its value to the
|
||||
// (0, 0) destination pixel and two thirds to (1, 0).
|
||||
// The implementation is a two-step process. First, the source pixels are
|
||||
// iterated over and each source pixel's contribution to 1 or more
|
||||
// destination pixels are summed. Second, the sums are divided by a scaling
|
||||
// factor to yield the destination pixels.
|
||||
// TODO: By interleaving the two steps, instead of doing all of
|
||||
// step 1 first and all of step 2 second, we could allocate a smaller sum
|
||||
// slice of length 4*w*2 instead of 4*w*h, although the resultant code
|
||||
// would become more complicated.
|
||||
n, sum := dx*dy, make([]uint64, 4*w*h)
|
||||
for y := r.Min.Y; y < r.Max.Y; y++ {
|
||||
for x := r.Min.X; x < r.Max.X; x++ {
|
||||
// Get the source pixel.
|
||||
r32, g32, b32, a32 := m.At(x, y).RGBA()
|
||||
r64 := uint64(r32)
|
||||
g64 := uint64(g32)
|
||||
b64 := uint64(b32)
|
||||
a64 := uint64(a32)
|
||||
// Spread the source pixel over 1 or more destination rows.
|
||||
py := uint64(y) * hh
|
||||
for remy := hh; remy > 0; {
|
||||
qy := dy - (py % dy)
|
||||
if qy > remy {
|
||||
qy = remy
|
||||
}
|
||||
// Spread the source pixel over 1 or more destination columns.
|
||||
px := uint64(x) * ww
|
||||
index := 4 * ((py/dy)*ww + (px / dx))
|
||||
for remx := ww; remx > 0; {
|
||||
qx := dx - (px % dx)
|
||||
if qx > remx {
|
||||
qx = remx
|
||||
}
|
||||
sum[index+0] += r64 * qx * qy
|
||||
sum[index+1] += g64 * qx * qy
|
||||
sum[index+2] += b64 * qx * qy
|
||||
sum[index+3] += a64 * qx * qy
|
||||
index += 4
|
||||
px += qx
|
||||
remx -= qx
|
||||
}
|
||||
py += qy
|
||||
remy -= qy
|
||||
}
|
||||
}
|
||||
}
|
||||
return average(sum, w, h, n*0x0101)
|
||||
}
|
||||
|
||||
// average convert the sums to averages and returns the result.
|
||||
func average(sum []uint64, w, h int, n uint64) image.Image {
|
||||
ret := image.NewRGBA(image.Rect(0, 0, w, h))
|
||||
for y := 0; y < h; y++ {
|
||||
for x := 0; x < w; x++ {
|
||||
index := 4 * (y*w + x)
|
||||
ret.SetRGBA(x, y, color.RGBA{
|
||||
uint8(sum[index+0] / n),
|
||||
uint8(sum[index+1] / n),
|
||||
uint8(sum[index+2] / n),
|
||||
uint8(sum[index+3] / n),
|
||||
})
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// resizeYCbCr returns a scaled copy of the YCbCr image slice r of m.
|
||||
// The returned image has width w and height h.
|
||||
func resizeYCbCr(m *image.YCbCr, r image.Rectangle, w, h int) (image.Image, bool) {
|
||||
var verticalRes int
|
||||
switch m.SubsampleRatio {
|
||||
case image.YCbCrSubsampleRatio420:
|
||||
verticalRes = 2
|
||||
case image.YCbCrSubsampleRatio422:
|
||||
verticalRes = 1
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
ww, hh := uint64(w), uint64(h)
|
||||
dx, dy := uint64(r.Dx()), uint64(r.Dy())
|
||||
// See comment in Resize.
|
||||
n, sum := dx*dy, make([]uint64, 4*w*h)
|
||||
for y := r.Min.Y; y < r.Max.Y; y++ {
|
||||
Y := m.Y[y*m.YStride:]
|
||||
Cb := m.Cb[y/verticalRes*m.CStride:]
|
||||
Cr := m.Cr[y/verticalRes*m.CStride:]
|
||||
for x := r.Min.X; x < r.Max.X; x++ {
|
||||
// Get the source pixel.
|
||||
r8, g8, b8 := color.YCbCrToRGB(Y[x], Cb[x/2], Cr[x/2])
|
||||
r64 := uint64(r8)
|
||||
g64 := uint64(g8)
|
||||
b64 := uint64(b8)
|
||||
// Spread the source pixel over 1 or more destination rows.
|
||||
py := uint64(y) * hh
|
||||
for remy := hh; remy > 0; {
|
||||
qy := dy - (py % dy)
|
||||
if qy > remy {
|
||||
qy = remy
|
||||
}
|
||||
// Spread the source pixel over 1 or more destination columns.
|
||||
px := uint64(x) * ww
|
||||
index := 4 * ((py/dy)*ww + (px / dx))
|
||||
for remx := ww; remx > 0; {
|
||||
qx := dx - (px % dx)
|
||||
if qx > remx {
|
||||
qx = remx
|
||||
}
|
||||
qxy := qx * qy
|
||||
sum[index+0] += r64 * qxy
|
||||
sum[index+1] += g64 * qxy
|
||||
sum[index+2] += b64 * qxy
|
||||
sum[index+3] += 0xFFFF * qxy
|
||||
index += 4
|
||||
px += qx
|
||||
remx -= qx
|
||||
}
|
||||
py += qy
|
||||
remy -= qy
|
||||
}
|
||||
}
|
||||
}
|
||||
return average(sum, w, h, n), true
|
||||
}
|
||||
|
||||
// resizeRGBA returns a scaled copy of the RGBA image slice r of m.
|
||||
// The returned image has width w and height h.
|
||||
func resizeRGBA(m *image.RGBA, r image.Rectangle, w, h int) image.Image {
|
||||
ww, hh := uint64(w), uint64(h)
|
||||
dx, dy := uint64(r.Dx()), uint64(r.Dy())
|
||||
// See comment in Resize.
|
||||
n, sum := dx*dy, make([]uint64, 4*w*h)
|
||||
for y := r.Min.Y; y < r.Max.Y; y++ {
|
||||
pixOffset := m.PixOffset(r.Min.X, y)
|
||||
for x := r.Min.X; x < r.Max.X; x++ {
|
||||
// Get the source pixel.
|
||||
r64 := uint64(m.Pix[pixOffset+0])
|
||||
g64 := uint64(m.Pix[pixOffset+1])
|
||||
b64 := uint64(m.Pix[pixOffset+2])
|
||||
a64 := uint64(m.Pix[pixOffset+3])
|
||||
pixOffset += 4
|
||||
// Spread the source pixel over 1 or more destination rows.
|
||||
py := uint64(y) * hh
|
||||
for remy := hh; remy > 0; {
|
||||
qy := dy - (py % dy)
|
||||
if qy > remy {
|
||||
qy = remy
|
||||
}
|
||||
// Spread the source pixel over 1 or more destination columns.
|
||||
px := uint64(x) * ww
|
||||
index := 4 * ((py/dy)*ww + (px / dx))
|
||||
for remx := ww; remx > 0; {
|
||||
qx := dx - (px % dx)
|
||||
if qx > remx {
|
||||
qx = remx
|
||||
}
|
||||
qxy := qx * qy
|
||||
sum[index+0] += r64 * qxy
|
||||
sum[index+1] += g64 * qxy
|
||||
sum[index+2] += b64 * qxy
|
||||
sum[index+3] += a64 * qxy
|
||||
index += 4
|
||||
px += qx
|
||||
remx -= qx
|
||||
}
|
||||
py += qy
|
||||
remy -= qy
|
||||
}
|
||||
}
|
||||
}
|
||||
return average(sum, w, h, n)
|
||||
}
|
||||
|
||||
// Resample returns a resampled copy of the image slice r of m.
|
||||
// The returned image has width w and height h.
|
||||
func Resample(m image.Image, r image.Rectangle, w, h int) image.Image {
|
||||
if w < 0 || h < 0 {
|
||||
return nil
|
||||
}
|
||||
if w == 0 || h == 0 || r.Dx() <= 0 || r.Dy() <= 0 {
|
||||
return image.NewRGBA64(image.Rect(0, 0, w, h))
|
||||
}
|
||||
curw, curh := r.Dx(), r.Dy()
|
||||
img := image.NewRGBA(image.Rect(0, 0, w, h))
|
||||
for y := 0; y < h; y++ {
|
||||
for x := 0; x < w; x++ {
|
||||
// Get a source pixel.
|
||||
subx := x * curw / w
|
||||
suby := y * curh / h
|
||||
r32, g32, b32, a32 := m.At(subx, suby).RGBA()
|
||||
r := uint8(r32 >> 8)
|
||||
g := uint8(g32 >> 8)
|
||||
b := uint8(b32 >> 8)
|
||||
a := uint8(a32 >> 8)
|
||||
img.SetRGBA(x, y, color.RGBA{r, g, b, a})
|
||||
}
|
||||
}
|
||||
return img
|
||||
}
|
239
src/manage.go
239
src/manage.go
|
@ -3,82 +3,223 @@ package main
|
|||
import (
|
||||
"net/http"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"strconv"
|
||||
_ "code.google.com/p/go.crypto/bcrypt"
|
||||
)
|
||||
|
||||
type ManageFunction struct {
|
||||
Permissions int // 0 -> non-staff, 1 => janitor, 2 => moderator, 3 => administrator
|
||||
Callback func() string //return string of html output?
|
||||
Callback func() string //return string of html output
|
||||
}
|
||||
|
||||
func callManageFunction(w http.ResponseWriter, request *http.Request) int {
|
||||
func callManageFunction(w http.ResponseWriter, r *http.Request) {
|
||||
// check if we have sufficient permissions to run this function
|
||||
//return values: 0 if successful, 1 if insufficient privelages
|
||||
form := request.Form
|
||||
request = *r
|
||||
writer = w
|
||||
cookies = r.Cookies()
|
||||
request.ParseForm()
|
||||
form := r.Form
|
||||
action := form.Get("action")
|
||||
if action == "" {
|
||||
staff_rank := getStaffRank()
|
||||
//writer.Header().Set("CContent-Type", "text/html")
|
||||
|
||||
manage_page_html := ""
|
||||
//manage_page_html = strings.Replace(manage_page_html,"{link css}",getStyleLinks(w,"manage"),-1)
|
||||
//getStyleLinks(w,"manage")
|
||||
|
||||
if action == "" {
|
||||
action = "announcements"
|
||||
}
|
||||
if staff_rank == 0 {
|
||||
action = "login"
|
||||
}
|
||||
|
||||
global_header,err := getTemplateAsString(*global_header_tmpl)
|
||||
if err != nil {
|
||||
fmt.Fprintf(writer,err.Error())
|
||||
} else {
|
||||
fmt.Fprintf(writer,global_header)
|
||||
}
|
||||
|
||||
manage_header,err := getTemplateAsString(*manage_header_tmpl)
|
||||
if err != nil {
|
||||
fmt.Fprintf(writer,err.Error())
|
||||
} else {
|
||||
fmt.Fprintf(writer,manage_header)
|
||||
}
|
||||
|
||||
if _,ok := manage_functions[action]; ok {
|
||||
var manage_page_html = ""
|
||||
if getStaffRank() >= manage_functions[action].Permissions {
|
||||
global_header,_ := readFileToString("templates/global_header.html")
|
||||
manage_header,_ := readFileToString("templates/manage_header.html")
|
||||
global_footer,_ := readFileToString("templates/global_footer.html")
|
||||
manage_page_html = global_header +"\n"+ manage_header
|
||||
manage_page_html = strings.Replace(manage_page_html,"{link css}",getStyleLinks("manage"),-1)
|
||||
|
||||
manage_page_html = manage_page_html + manage_functions[action].Callback()+global_footer
|
||||
|
||||
fmt.Fprintf(w,manage_page_html)
|
||||
return 0
|
||||
if staff_rank >= manage_functions[action].Permissions {
|
||||
manage_page_html += manage_functions[action].Callback()
|
||||
fmt.Fprintf(writer,manage_page_html)
|
||||
|
||||
} else {
|
||||
manage_page_html = manage_page_html + action + " is undefined."
|
||||
fmt.Fprintf(writer,manage_page_html)
|
||||
}
|
||||
} else {
|
||||
var manage_page_html = ""
|
||||
global_header,_ := readFileToString("templates/global_header.html")
|
||||
manage_header,_ := readFileToString("templates/manage_header.html")
|
||||
global_footer,_ := readFileToString("templates/global_footer.html")
|
||||
manage_page_html = global_header +"\n"+ manage_header
|
||||
manage_page_html = strings.Replace(manage_page_html,"{link css}",getStyleLinks("manage"),-1)
|
||||
|
||||
manage_page_html = manage_page_html + action + " is undefined." + global_footer
|
||||
|
||||
fmt.Fprintf(w,manage_page_html)
|
||||
return 0
|
||||
manage_page_html = manage_page_html + action + " is undefined."
|
||||
fmt.Fprintf(writer,manage_page_html)
|
||||
}
|
||||
|
||||
global_footer,err := getTemplateAsString(*global_footer_tmpl)
|
||||
if err != nil {
|
||||
fmt.Fprintf(writer,err.Error())
|
||||
} else {
|
||||
fmt.Fprintf(writer,global_footer)
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
func getStaffRank() int {
|
||||
return 3
|
||||
var key string
|
||||
var staffname string
|
||||
|
||||
db.Start("USE `"+config.DBname+"`")
|
||||
session_cookie := getCookie("sessiondata")
|
||||
if session_cookie == nil {
|
||||
return 0
|
||||
} else {
|
||||
key = session_cookie.Value
|
||||
}
|
||||
|
||||
results,err := db.Start("SELECT * FROM `"+config.DBprefix+"sessions` WHERE `key` = '"+key+"';")
|
||||
if err != nil {
|
||||
error_log.Write(err.Error())
|
||||
return 0
|
||||
}
|
||||
|
||||
for {
|
||||
row, err := results.GetRow()
|
||||
if err != nil {
|
||||
error_log.Write(err.Error())
|
||||
}
|
||||
|
||||
if row == nil {
|
||||
break
|
||||
}
|
||||
|
||||
for col_num, col := range row {
|
||||
if col_num == 2 {
|
||||
staffname = string(col.([]byte))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
results,err = db.Start("SELECT * FROM `"+config.DBprefix+"staff` WHERE `username` = '"+staffname+"';")
|
||||
if err != nil {
|
||||
error_log.Write(err.Error())
|
||||
return 0
|
||||
}
|
||||
|
||||
for {
|
||||
row, err := results.GetRow()
|
||||
if err != nil {
|
||||
error_log.Write(err.Error())
|
||||
return 0
|
||||
}
|
||||
|
||||
if row == nil {
|
||||
break
|
||||
}
|
||||
|
||||
for col_num, col := range row {
|
||||
if col_num == 4 {
|
||||
rank,rerr := strconv.Atoi(string(col.([]byte)))
|
||||
if rerr == nil {
|
||||
return rank
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func createSession(key string,username string, password string) bool {
|
||||
//sum := bcrypt_sum(password)
|
||||
rows,_,err := db.Query("SELECT `password_checksum` FROM `"+config.DBprefix+"staff`")
|
||||
|
||||
if err != nil {
|
||||
error_log.Write(err.Error())
|
||||
fmt.Println("nope 1")
|
||||
return false
|
||||
} else {
|
||||
|
||||
|
||||
if len(rows) > 0 {
|
||||
_,err := db.Start(" INSERT INTO `"+config.DBprefix+"sessions` (`key`, `data`, `expires`) VALUES('"+key+"','"+username+"', '2023-17-04 16:21:01');")
|
||||
if err != nil {
|
||||
fmt.Println("Initial setup failed.")
|
||||
error_log.Write(err.Error())
|
||||
}
|
||||
} else {
|
||||
fmt.Println("nope 2")
|
||||
return false
|
||||
}
|
||||
}
|
||||
fmt.Println("wtf")
|
||||
return false
|
||||
}
|
||||
|
||||
var manage_functions = map[string]ManageFunction{
|
||||
"initialsetup": {
|
||||
Permissions: 0,
|
||||
Callback: func() string {
|
||||
html,_ := ioutil.ReadFile(config.DocumentRoot+"/index.html")
|
||||
return string(html)
|
||||
}},
|
||||
"error": {
|
||||
Permissions: 0,
|
||||
Callback: func() (html string) {
|
||||
html,err = readFileToString(document_root+"/index.html")
|
||||
exitWithErrorPage("lel, internet")
|
||||
return
|
||||
}},
|
||||
"login":{
|
||||
Permissions: 0,
|
||||
Callback: func() (html string) {
|
||||
html = "<div id=\"loginbox\">" +
|
||||
"\t<form method=\"GET\" action=\"/manage\">\n" +
|
||||
"\t\t<input type=\"hidden\" name=\"action\" value=\"login\" />\n" +
|
||||
"\t\t<input type=\"text\" name=\"username\" /><br />\n" +
|
||||
"\t\t<input type=\"password\" name=\"password\" /> <br />\n" +
|
||||
"\t\t<input type=\"submit\" value=\"Login\" />\n" +
|
||||
"\t</form>" +
|
||||
"</div>"
|
||||
username := request.FormValue("username")
|
||||
password := request.FormValue("password")
|
||||
|
||||
if username == "" || password == "" {
|
||||
//assume that they haven't logged in
|
||||
html = "\t<form method=\"POST\" action=\"/manage?action=login\" class=\"loginbox\">\n" +
|
||||
//"\t\t<input type=\"hidden\" name=\"action\" value=\"login\" />\n" +
|
||||
"\t\t<input type=\"text\" name=\"username\" class=\"logindata\" /><br />\n" +
|
||||
"\t\t<input type=\"password\" name=\"password\" class=\"logindata\" /> <br />\n" +
|
||||
"\t\t<input type=\"submit\" value=\"Login\" />\n" +
|
||||
"\t</form>"
|
||||
} else {
|
||||
key := md5_sum(request.RemoteAddr+username+password+config.RandomSeed+generateSalt())
|
||||
createSession(key,username,password)
|
||||
//check db for valid login
|
||||
/*
|
||||
password_bcrypt = bcrypt_encode(password)
|
||||
results,err := db.Query("SELECT `username`,`password`, FROM `"+config.DBprefix+"staff")
|
||||
if err != nil {
|
||||
error_log.Write(err.Error())
|
||||
}
|
||||
var entry StaffTable
|
||||
for results.Next() {
|
||||
err = results.Scan(&entry.username,&entry.password)
|
||||
if entry.username == username && entry.password == password_bcrypt {
|
||||
//authenticated
|
||||
|
||||
}
|
||||
if err != nil { error_log.write(err.Error()) }
|
||||
}
|
||||
*/
|
||||
}
|
||||
return
|
||||
}},
|
||||
"announcements": {
|
||||
Permissions: 1,
|
||||
Callback: func() (html string) {
|
||||
html = "Announcements will eventually go here."
|
||||
html = "<h2>Announcements</h2><br />" +
|
||||
"Announcements will eventually go here."
|
||||
|
||||
/*results,err := db.Query("SELECT * FROM `"+db_prefix+"announcements")
|
||||
if err != nil {
|
||||
|
@ -92,23 +233,30 @@ var manage_functions = map[string]ManageFunction{
|
|||
return
|
||||
}},
|
||||
"manageserver": {
|
||||
Permissions: 0,
|
||||
Permissions: 3,
|
||||
Callback: func() (html string) {
|
||||
html = "<script type=\"text/javascript\">\n$jq = jQuery.noConflict();\n$jq(document).ready(function() {\n\tvar killserver_btn = $jq(\"button#killserver\");\n\n\t$jq(\"button#killserver\").click(function() {\n\t\t$jq.ajax({\n\t\t\tmethod:'GET',\n\t\t\turl:\"/manage\",\n\t\t\tdata: {\n\t\t\t\taction: 'killserver'\n\t\t\t},\n\n\t\t\tsuccess: function() {\n\t\t\t\t\n\t\t\t},\n\t\t\terror:function() {\n\t\t\t\t\n\t\t\t}\n\t\t});\n\t});\n});\n</script>" +
|
||||
"<button id=\"killserver\">Kill server</button><br />\n"
|
||||
|
||||
return
|
||||
}},
|
||||
"rebuildall": {
|
||||
"cleanup": {
|
||||
Permissions:3,
|
||||
Callback: func() (html string) {
|
||||
|
||||
return
|
||||
}},
|
||||
"rebuildall": {
|
||||
Permissions:3,
|
||||
Callback: func() (html string) {
|
||||
initTemplates()
|
||||
return
|
||||
}},
|
||||
"recentposts": {
|
||||
Permissions:1,
|
||||
Callback: func() (html string) {
|
||||
html = "<h1>Recent posts</h1>\n<table>\n<tr></tr> "
|
||||
|
||||
html = "<h1>Recent posts</h1>\n<table style=\"border:2px solid;\">\n<tr><td>bleh</td><td>bleh bleh</td></tr>" +
|
||||
"</table>"
|
||||
return
|
||||
}},
|
||||
"killserver": {
|
||||
|
@ -116,4 +264,5 @@ var manage_functions = map[string]ManageFunction{
|
|||
Callback: func() (html string) {
|
||||
os.Exit(0)
|
||||
return
|
||||
}}}
|
||||
}},
|
||||
}
|
136
src/posting.go
Normal file
136
src/posting.go
Normal file
|
@ -0,0 +1,136 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"io/ioutil"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/jpeg"
|
||||
"image/gif"
|
||||
"image/png"
|
||||
"os"
|
||||
"./lib/resize"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func generateTripCode(input string) string {
|
||||
input += " " //padding
|
||||
return crypt(input,input[1:3])[3:]
|
||||
}
|
||||
|
||||
func createThumbnail(input string, output string) bool {
|
||||
var image_obj image.Image
|
||||
failed := false
|
||||
handle,err := os.Open(input)
|
||||
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer func() {
|
||||
if _, ok := recover().(error); ok {
|
||||
handle.Close()
|
||||
failed = true
|
||||
}
|
||||
}()
|
||||
if failed {
|
||||
error_log.Write("Failed to create thumbnail")
|
||||
return false
|
||||
}
|
||||
|
||||
filetype := input[len(input)-3:len(input)]
|
||||
if filetype == "gif" {
|
||||
image_obj,_ = gif.Decode(handle)
|
||||
} else if filetype == "jpeg" || filetype == "jpg" {
|
||||
image_obj,_ = jpeg.Decode(handle)
|
||||
} else if filetype == "png" {
|
||||
image_obj,_ = png.Decode(handle)
|
||||
} else {
|
||||
exitWithErrorPage("Upload file type not supported")
|
||||
}
|
||||
|
||||
old_rect := image_obj.Bounds()
|
||||
defer func() {
|
||||
if _, ok := recover().(error); ok {
|
||||
//serverError()
|
||||
exitWithErrorPage("lel, internet")
|
||||
}
|
||||
}()
|
||||
if config.ThumbWidth >= old_rect.Max.X && config.ThumbHeight >= old_rect.Max.Y {
|
||||
err := syscall.Symlink(input,output)
|
||||
if err != nil {
|
||||
error_log.Write(fmt.Sprintf("Error, couldn't create symlink to %s, %s", input, err.Error()))
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
thumb_w,thumb_h := getThumbnailSize(old_rect.Max.X,old_rect.Max.Y)
|
||||
image_obj = resize.Resize(image_obj, image.Rect(0,0,old_rect.Max.X,old_rect.Max.Y), thumb_w,thumb_h)
|
||||
|
||||
outwriter,_ := os.OpenFile(output, os.O_RDWR|os.O_CREATE,0777)
|
||||
if filetype == "gif" {
|
||||
//because Go doesn't come with a GIF writer :c
|
||||
jpeg.Encode(outwriter, image_obj, &jpeg.Options{Quality: 80})
|
||||
} else if filetype == "jpg" || filetype == "jpeg" {
|
||||
jpeg.Encode(outwriter,image_obj, &jpeg.Options{Quality: 80})
|
||||
} else if filetype == "png" {
|
||||
png.Encode(outwriter,image_obj)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
//find out what out thumbnail's width and height should be, partially ripped from Kusaba X
|
||||
|
||||
func getThumbnailSize(w int, h int) (new_w int, new_h int) {
|
||||
if w == h {
|
||||
new_w = config.ThumbWidth
|
||||
new_h = config.ThumbWidth
|
||||
} else {
|
||||
var percent float32
|
||||
|
||||
if (w > h) {
|
||||
percent = float32(config.ThumbWidth) / float32(w)
|
||||
} else {
|
||||
percent = float32(config.ThumbWidth) / float32(h)
|
||||
}
|
||||
new_w = int(float32(w) * percent)
|
||||
new_h = int(float32(h) * percent)
|
||||
//fmt.Printf("Old width: %d\nOld height: %d\nPercent: %f\nWidth: %d\nHeight: %d\n",w,h,percent*100,new_w,new_h)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func shortenPostForBoardPage(post *string) {
|
||||
|
||||
}
|
||||
|
||||
func makePost(w http.ResponseWriter, r *http.Request) {
|
||||
request = *r
|
||||
writer = w
|
||||
file,handler,err := request.FormFile("file")
|
||||
|
||||
//post has no referrer, or has a referrer from a different domain, probably a spambot
|
||||
if request.Referer() == "" || request.Referer()[7:len(config.Domain)+7] != config.Domain {
|
||||
access_log.Write("Rejected post from possible spambot @ : "+request.RemoteAddr)
|
||||
//TODO: insert post into temporary post table and add to report list
|
||||
}
|
||||
|
||||
//no file was uploaded
|
||||
if err != nil {
|
||||
access_log.Write("Receiving post from "+request.RemoteAddr+", referred from: "+request.Referer())
|
||||
} else {
|
||||
data,err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
fmt.Println("Couldn't read file")
|
||||
} else {
|
||||
access_log.Write("Receiving post with image: "+handler.Filename+" from "+request.RemoteAddr+", referrer: "+request.Referer())
|
||||
err = ioutil.WriteFile(handler.Filename, data, 0777)
|
||||
createThumbnail(handler.Filename,"output")
|
||||
if err != nil {
|
||||
fmt.Println("Couldn't write file")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
17
src/process.go
Normal file
17
src/process.go
Normal file
|
@ -0,0 +1,17 @@
|
|||
package main
|
||||
|
||||
// #define _GNU_SOURCE
|
||||
// #include <stdio.h>
|
||||
// #include <unistd.h>
|
||||
// #include <sys/types.h>
|
||||
import "C"
|
||||
|
||||
var pid uintptr
|
||||
/*
|
||||
func fork() int {
|
||||
return C.GoInt(C.fork())
|
||||
}
|
||||
|
||||
func setsid() {
|
||||
C.setsid()
|
||||
}*/
|
150
src/server.go
150
src/server.go
|
@ -1,86 +1,128 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"path"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/url"
|
||||
"net/http"
|
||||
//"html/template"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
form url.Values
|
||||
header http.Header
|
||||
cookies []*http.Cookie
|
||||
writer http.ResponseWriter
|
||||
request http.Request
|
||||
exit_error bool
|
||||
)
|
||||
|
||||
func initServer() {
|
||||
if port == 0 {
|
||||
port = 80
|
||||
if config.Port == 0 {
|
||||
config.Port = 80
|
||||
}
|
||||
getStyleLinks("manage")
|
||||
listener,err := net.Listen("tcp", domain+":"+strconv.Itoa(port))
|
||||
listener,err := net.Listen("tcp", config.Domain+":"+strconv.Itoa(config.Port))
|
||||
if(err != nil) {
|
||||
error_log.Write(err.Error())
|
||||
fmt.Println("Failed listening on "+domain+":"+strconv.Itoa(port)+", see log for details")
|
||||
fmt.Printf("Failed listening on "+config.Domain+":%d, see log for details",config.Port)
|
||||
os.Exit(2)
|
||||
}
|
||||
http.Handle("/", makeHandler(serveFile))
|
||||
http.Handle("/", makeHandler(fileHandle))
|
||||
http.Handle("/manage",makeHandler(callManageFunction))
|
||||
http.Handle("/post",makeHandler(makePost))
|
||||
//http.Handle("/util",makeHandler(utilHandler))
|
||||
http.Serve(listener, nil)
|
||||
}
|
||||
|
||||
func getFileHTTPCode(filename string) int {
|
||||
filename = document_root+"/"+filename
|
||||
|
||||
stat, err := os.Stat(filename);
|
||||
if err == nil {
|
||||
return 200
|
||||
} else {
|
||||
if stat.IsDir() {
|
||||
num_indexes := len(first_page)
|
||||
for i := 0; i < num_indexes; i++ {
|
||||
_,newerr := os.Stat(filename+"/"+first_page[i])
|
||||
if newerr == nil {
|
||||
return 200
|
||||
} else {
|
||||
return 404
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return 200
|
||||
}
|
||||
}
|
||||
return 500
|
||||
}
|
||||
|
||||
func serveFile(w http.ResponseWriter, request *http.Request, request_url string) {
|
||||
func fileHandle(w http.ResponseWriter, r *http.Request) {
|
||||
request = *r
|
||||
writer = w
|
||||
cookies = request.Cookies()
|
||||
request.ParseForm()
|
||||
form = request.Form
|
||||
request_url := request.URL.Path
|
||||
|
||||
filepath := path.Join(config.DocumentRoot, request_url)
|
||||
results,err := os.Stat(filepath)
|
||||
|
||||
if !strings.Contains(request.Header.Get("Accept-Encoding"), "gzip") {
|
||||
|
||||
if request.URL.Path == "/manage" {
|
||||
callManageFunction(w,request)
|
||||
} else {
|
||||
http.ServeFile(w, request, path.Join(document_root, request_url))
|
||||
}
|
||||
access_log.Write("Success: 200 from " + request.RemoteAddr + " @ " + request.RequestURI)
|
||||
|
||||
if err == nil {
|
||||
//the file exists, or there is a folder here
|
||||
if results.IsDir() {
|
||||
found_index := false
|
||||
newpath := ""
|
||||
|
||||
//check to see if one of the specified index pages exists
|
||||
for i := 0; i < len(config.FirstPage); i++ {
|
||||
newpath = path.Join(filepath,config.FirstPage[i])
|
||||
_,err := os.Stat(newpath)
|
||||
if err == nil {
|
||||
serveFile(w, newpath)
|
||||
found_index = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found_index {
|
||||
error404()
|
||||
}
|
||||
} else {
|
||||
//the file exists, and is not a folder
|
||||
//writer.Header().Add("Cache-Control", fmt.Sprintf("max-age=%d, public, must-revalidate, proxy-revalidate", 500))
|
||||
serveFile(w, filepath)
|
||||
}
|
||||
} else {
|
||||
//there is nothing at the requested address
|
||||
error404()
|
||||
}
|
||||
}
|
||||
|
||||
func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, request *http.Request) {
|
||||
defer func() {
|
||||
if _, ok := recover().(error); ok {
|
||||
//don't panic if the file doesn't exist
|
||||
//w.WriteHeader(404)
|
||||
http.ServeFile(w, request, path.Join(document_root, "404.html"))
|
||||
error_log.Write("Error: 404 Not Found from " + request.RemoteAddr + " @ " + request.RequestURI)
|
||||
return
|
||||
}
|
||||
}()
|
||||
title := request.URL.Path
|
||||
fn(w, request, title)
|
||||
func makeHandler(fn func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
//defer serverError()
|
||||
if !exit_error {
|
||||
fn(w, r)
|
||||
exit_error = false
|
||||
} else {
|
||||
exit_error = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func exitWithErrorPage(err string) {
|
||||
error_page_bytes,_ := ioutil.ReadFile("templates/error.html")
|
||||
error_page := string(error_page_bytes)
|
||||
error_page = strings.Replace(error_page,"{ERRORTEXT}", err,-1)
|
||||
fmt.Fprintf(writer,error_page)
|
||||
exit_error = true
|
||||
}
|
||||
|
||||
func redirect(location string) {
|
||||
//http.Redirect(writer,&request,location,http.StatusMovedTemporarily)
|
||||
}
|
||||
|
||||
func error404() {
|
||||
http.ServeFile(writer, &request, path.Join(config.DocumentRoot, "/error/404.html"))
|
||||
error_log.Write("Error: 404 Not Found from " + request.RemoteAddr + " @ " + request.RequestURI)
|
||||
}
|
||||
|
||||
func serverError() {
|
||||
if _, ok := recover().(error); ok {
|
||||
//something went wrong, now we need to throw a 500
|
||||
http.ServeFile(writer,&request, path.Join(config.DocumentRoot, "/error/500.html"))
|
||||
error_log.Write("Error: 500 Internal Server error from " + request.RemoteAddr + " @ " + request.RequestURI)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func serveFile(w http.ResponseWriter, filepath string) {
|
||||
http.ServeFile(w, &request, filepath)
|
||||
access_log.Write("Success: 200 from " + request.RemoteAddr + " @ " + request.RequestURI)
|
||||
}
|
107
src/server.go.bak
Normal file
107
src/server.go.bak
Normal file
|
@ -0,0 +1,107 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"path"
|
||||
"net"
|
||||
"net/url"
|
||||
"net/http"
|
||||
//"html/template"
|
||||
)
|
||||
|
||||
var (
|
||||
form url.Values
|
||||
header http.Header
|
||||
cookies []*http.Cookie
|
||||
)
|
||||
|
||||
func initServer() {
|
||||
if port == 0 {
|
||||
port = 80
|
||||
}
|
||||
getStyleLinks("manage")
|
||||
listener,err := net.Listen("tcp", domain+":"+strconv.Itoa(port))
|
||||
if(err != nil) {
|
||||
error_log.Write(err.Error())
|
||||
fmt.Printf("Failed listening on "+domain+":%d, see log for details",port)
|
||||
os.Exit(2)
|
||||
}
|
||||
http.Handle("/", makeHandler(fileHandle))
|
||||
http.Handle("/manage",makeHandler(callManageFunction))
|
||||
http.Handle("/post",makeHandler(makePost))
|
||||
http.Serve(listener, nil)
|
||||
}
|
||||
|
||||
func fileHandle(writer http.ResponseWriter, request *http.Request) {
|
||||
cookies = request.Cookies()
|
||||
request.ParseForm()
|
||||
form = request.Form
|
||||
request_url := request.URL.Path
|
||||
|
||||
filepath := path.Join(document_root, request_url)
|
||||
results,err := os.Stat(filepath)
|
||||
|
||||
if err == nil {
|
||||
//the file exists, or there is a folder here
|
||||
if results.IsDir() {
|
||||
found_index := false
|
||||
newpath := ""
|
||||
|
||||
//check to see if one of the specified index pages exists
|
||||
for i := 0; i < len(first_page); i++ {
|
||||
newpath = path.Join(filepath,first_page[i])
|
||||
_,err := os.Stat(newpath)
|
||||
if err == nil {
|
||||
serveFile(writer,request,newpath)
|
||||
found_index = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found_index {
|
||||
error404(&writer,request)
|
||||
}
|
||||
} else {
|
||||
//the file exists, and is not a folder
|
||||
writer.Header().Add("Cache-Control", fmt.Sprintf("max-age=%d, public, must-revalidate, proxy-revalidate", 500))
|
||||
serveFile(writer,request,filepath)
|
||||
}
|
||||
} else {
|
||||
//there is nothing at the requested address
|
||||
error404(&writer, request)
|
||||
}
|
||||
}
|
||||
|
||||
func makeHandler(fn func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
|
||||
return func(writer http.ResponseWriter, request *http.Request) {
|
||||
defer serverError(writer,request)
|
||||
fn(writer, request)
|
||||
}
|
||||
}
|
||||
|
||||
func exitWithErrorPage(error string) {
|
||||
|
||||
}
|
||||
|
||||
func error404(writer *http.ResponseWriter, request *http.Request) {
|
||||
//w := *writer
|
||||
//w.WriteHeader(404)
|
||||
http.ServeFile(*writer, request, path.Join(document_root, "404.html"))
|
||||
error_log.Write("Error: 404 Not Found from " + request.RemoteAddr + " @ " + request.RequestURI)
|
||||
}
|
||||
|
||||
func serverError(writer http.ResponseWriter, request *http.Request) {
|
||||
if _, ok := recover().(error); ok {
|
||||
//something went wrong, now we need to throw a 500
|
||||
http.ServeFile(writer,request, path.Join(document_root, "/error/500.html"))
|
||||
error_log.Write("Error: 500 Internal Server error from " + request.RemoteAddr + " @ " + request.RequestURI)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func serveFile(writer http.ResponseWriter, request *http.Request, filepath string) {
|
||||
http.ServeFile(writer, request, filepath)
|
||||
access_log.Write("Success: 200 from " + request.RemoteAddr + " @ " + request.RequestURI)
|
||||
}
|
62
src/sql.go
62
src/sql.go
|
@ -3,33 +3,75 @@ package main
|
|||
import (
|
||||
"os"
|
||||
"fmt"
|
||||
"database/sql"
|
||||
_ "go-mysql-driver/mysql"
|
||||
//"database/sql"
|
||||
//_ "github.com/go-sql-driver/mysql"
|
||||
|
||||
"github.com/ziutek/mymysql/mysql"
|
||||
_ "github.com/ziutek/mymysql/native" // Native engine
|
||||
//_ "github.com/ziutek/mymysql/thrsafe" // Thread safe engine
|
||||
)
|
||||
|
||||
var (
|
||||
db *sql.DB
|
||||
//db *sql.DB
|
||||
db mysql.Conn
|
||||
db_connected = false
|
||||
)
|
||||
|
||||
func connectToDB() {
|
||||
db, err = sql.Open("mysql",db_username+":"+db_password+"@"+db_host+"/"+db_name+"?charset=utf8&keepalive="+db_persistent_str)
|
||||
func connectToSQLServer(usedb bool) {
|
||||
//db, err = sql.Open("mysql",config.DBusername+":"+config.DBpassword+"@"+db_host+"/?charset=utf8")
|
||||
db = mysql.New("tcp", "", "127.0.0.1:3306", config.DBusername, config.DBpassword)
|
||||
err := db.Connect()
|
||||
if err != nil {
|
||||
error_log.Write(err.Error())
|
||||
fmt.Println("Failed to connect to the database, see log for details.")
|
||||
os.Exit(2)
|
||||
}
|
||||
if usedb {
|
||||
_,err = db.Start("USE `"+config.DBname+"`;")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
db_connected = true
|
||||
}
|
||||
|
||||
|
||||
func dbTests() {
|
||||
results,err := db.Query("SELECT * FROM `"+db_prefix+"modlog")
|
||||
results,err := db.Start("SELECT * FROM `"+config.DBprefix+"staff")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
/*var entry StaffTable
|
||||
if err != nil {
|
||||
error_log.Write(err.Error())
|
||||
fmt.Println("Failed to connect to the database, see log for details.")
|
||||
os.Exit(2)
|
||||
}
|
||||
var entry ModLogTable
|
||||
for results.Next() {
|
||||
err = results.Scan(&entry.entry,&entry.user,&entry.category,&entry.timestamp)
|
||||
err = results.Scan(&entry.username,&entry.password_checksum,&entry.rank)
|
||||
//if err != nil { panic(err) }
|
||||
}*/
|
||||
|
||||
for {
|
||||
row, err := results.GetRow()
|
||||
if err != nil {
|
||||
error_log.Write(err.Error())
|
||||
}
|
||||
|
||||
if row == nil {
|
||||
// No more rows
|
||||
break
|
||||
}
|
||||
|
||||
// Print all cols
|
||||
for _, col := range row {
|
||||
if col == nil {
|
||||
fmt.Print("<NULL>")
|
||||
} else {
|
||||
os.Stdout.Write(col.([]byte))
|
||||
}
|
||||
fmt.Print(" ")
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
139
src/template.go
139
src/template.go
|
@ -1,13 +1,134 @@
|
|||
package main
|
||||
|
||||
func getStyleLinks(stylesheet string) (links_str string) {
|
||||
num_styles := len(styles_arr)
|
||||
for l := 0; l < num_styles; l++ {
|
||||
links_str += "<link rel=\""
|
||||
if l > 0 {
|
||||
links_str += "alternate "
|
||||
}
|
||||
links_str += "stylesheet\" href=\"/css/"+styles_arr[l]+"/"+stylesheet+".css\" />\n"
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
|
||||
|
||||
type FooterData struct {
|
||||
Version float32
|
||||
GeneratedTime float32
|
||||
}
|
||||
|
||||
var funcMap = template.FuncMap{
|
||||
"isStyleDefault_img": func(style string) bool {
|
||||
return style == config.DefaultStyle_img
|
||||
},
|
||||
"isStyleNotDefault_img": func(style string) bool {
|
||||
return style != config.DefaultStyle_img
|
||||
},
|
||||
}
|
||||
|
||||
var (
|
||||
footer_data = FooterData{version, float32(0)}
|
||||
global_footer_tmpl_str string
|
||||
global_footer_tmpl *template.Template
|
||||
|
||||
global_header_tmpl_str string
|
||||
global_header_tmpl *template.Template
|
||||
|
||||
img_header_tmpl_str string
|
||||
img_header_tmpl *template.Template
|
||||
|
||||
manage_header_tmpl_str string
|
||||
manage_header_tmpl *template.Template
|
||||
|
||||
template_buffer bytes.Buffer
|
||||
)
|
||||
|
||||
func initTemplates() {
|
||||
global_footer_tmpl_bytes,tmpl_err := ioutil.ReadFile(config.TemplateDir+"/global_footer.html")
|
||||
if tmpl_err != nil {
|
||||
fmt.Println("Failed loading template \""+config.TemplateDir+"/global_footer.html\"")
|
||||
os.Exit(2)
|
||||
}
|
||||
return
|
||||
global_footer_tmpl_str = string(global_footer_tmpl_bytes)
|
||||
global_footer_tmpl,tmpl_err = template.New("global_footer_tmpl").Funcs(funcMap).Parse(string(global_footer_tmpl_str))
|
||||
if tmpl_err != nil {
|
||||
fmt.Println("Failed loading template \""+config.TemplateDir+"/global_footer.html\"")
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
global_header_tmpl_bytes,tmpl_err := ioutil.ReadFile(config.TemplateDir+"/global_header.html")
|
||||
if tmpl_err != nil {
|
||||
fmt.Println("Failed loading template \""+config.TemplateDir+"/global_header.html\"")
|
||||
os.Exit(2)
|
||||
}
|
||||
global_header_tmpl_str = string(global_header_tmpl_bytes)
|
||||
global_header_tmpl,tmpl_err = template.New("global_header_tmpl").Funcs(funcMap).Parse(string(global_header_tmpl_str))
|
||||
if tmpl_err != nil {
|
||||
fmt.Println("Failed loading template \""+config.TemplateDir+"/global_header.html\"")
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
img_header_tmpl_bytes,_ := ioutil.ReadFile(config.TemplateDir+"/img_header.html")
|
||||
if tmpl_err != nil {
|
||||
fmt.Println("Failed loading template \""+config.TemplateDir+"/img_header.html\"")
|
||||
os.Exit(2)
|
||||
}
|
||||
img_header_tmpl_str = string(img_header_tmpl_bytes)
|
||||
img_header_tmpl,_ = template.New("img_header_tmpl").Funcs(funcMap).Parse(string(img_header_tmpl_str))
|
||||
if tmpl_err != nil {
|
||||
fmt.Println("Failed loading template \""+config.TemplateDir+"/img_header.html\"")
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
manage_header_tmpl_bytes,_ := ioutil.ReadFile(config.TemplateDir+"/manage_header.html")
|
||||
manage_header_tmpl_str = string(manage_header_tmpl_bytes)
|
||||
manage_header_tmpl,_ = template.New("manage_header_tmpl").Funcs(funcMap).Parse(manage_header_tmpl_str)
|
||||
if tmpl_err != nil {
|
||||
fmt.Println("Failed loading template \""+config.TemplateDir+"/manage_header.html\"")
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
|
||||
func getTemplateAsString(templ template.Template) (string,error) {
|
||||
var buf bytes.Buffer
|
||||
err := templ.Execute(&buf,config)
|
||||
if err == nil {
|
||||
return buf.String(),nil
|
||||
}
|
||||
return "",err
|
||||
}
|
||||
|
||||
func getStyleLinks(w http.ResponseWriter, stylesheet string) {
|
||||
styles_map := make(map[int]string)
|
||||
for i := 0; i < len(config.Styles_img); i++ {
|
||||
styles_map[i] = config.Styles_img[i]
|
||||
}
|
||||
|
||||
err := manage_header_tmpl.Execute(w,config)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
|
||||
func buildAll() error {
|
||||
buildFrontPage()
|
||||
/*
|
||||
results,err := db.Query("SELECT `dir` FROM `"+config.DBprefix+"boards")
|
||||
var entry BoardTable
|
||||
for results.Next() {
|
||||
err = results.Scan(&entry.dir)
|
||||
buildBoard(entry.dir)
|
||||
}
|
||||
*/
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildFrontPage() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildBoard(dir string) error {
|
||||
//build board pages
|
||||
//build board thread pages
|
||||
return nil
|
||||
}
|
792
src/types.go
792
src/types.go
|
@ -1,329 +1,665 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"go-logfile/logfile"
|
||||
"goconf/conf"
|
||||
)
|
||||
|
||||
|
||||
var (
|
||||
c *conf.ConfigFile
|
||||
needs_initial_setup = true
|
||||
config GochanConfig
|
||||
access_log logfile.Log
|
||||
error_log logfile.Log
|
||||
)
|
||||
|
||||
// SQL Table structs
|
||||
|
||||
type AnnouncementsTable struct {
|
||||
id uint
|
||||
subject string
|
||||
message string
|
||||
poster string
|
||||
timestamp string
|
||||
}
|
||||
|
||||
type BanlistTable struct {
|
||||
id int
|
||||
Type bool
|
||||
id uint
|
||||
expired bool
|
||||
allowread bool
|
||||
allow_read bool
|
||||
ip string
|
||||
ipmd5 string
|
||||
globalban bool
|
||||
silentban bool
|
||||
silent_ban uint8
|
||||
boards string
|
||||
by string
|
||||
at int
|
||||
until int
|
||||
banned_by string
|
||||
timestamp string
|
||||
expires string
|
||||
reason string
|
||||
staffnote string
|
||||
staff_note string
|
||||
appeal string
|
||||
appealat int
|
||||
appeal_at string
|
||||
}
|
||||
|
||||
type BannedHashesTable struct {
|
||||
id int
|
||||
md5 string
|
||||
bantime int
|
||||
id uint
|
||||
checksum string
|
||||
description string
|
||||
}
|
||||
|
||||
type BannedTripcodesTable struct {
|
||||
id int
|
||||
id uint
|
||||
name string
|
||||
tripcode string
|
||||
}
|
||||
|
||||
type BlotterTable struct {
|
||||
id int
|
||||
important bool
|
||||
at int
|
||||
message string
|
||||
}
|
||||
|
||||
type BoardFiletypesTable struct {
|
||||
boardid int
|
||||
typeid int
|
||||
}
|
||||
|
||||
type BoardsTable struct {
|
||||
id int
|
||||
order int
|
||||
name string
|
||||
Type bool
|
||||
start int
|
||||
uploadtype bool
|
||||
desc string
|
||||
image string
|
||||
section int
|
||||
maximagesize int
|
||||
maxpages int
|
||||
maxage int
|
||||
markpage int
|
||||
maxreplies int
|
||||
messagelength int
|
||||
createdon int
|
||||
locked bool
|
||||
includeheader string
|
||||
redirecttothread bool
|
||||
anonymous string
|
||||
forcedanon bool
|
||||
embeds_allowed string
|
||||
trial bool
|
||||
popular bool
|
||||
defaultstyle string
|
||||
id uint8
|
||||
order uint8
|
||||
dir string
|
||||
Type uint8
|
||||
first_post uint
|
||||
upload_type uint8
|
||||
title string
|
||||
subtitle string
|
||||
section string
|
||||
max_image_size int
|
||||
max_pages uint8
|
||||
locale string
|
||||
showid bool
|
||||
compactlist bool
|
||||
enablereporting bool
|
||||
enablecaptcha bool
|
||||
enablenofile bool
|
||||
enablearchiving bool
|
||||
enablecatalog bool
|
||||
loadbalanceurl string
|
||||
loadbalancepassword string
|
||||
default_style string
|
||||
locked bool
|
||||
created_on string
|
||||
anonymous string
|
||||
forced_anon string
|
||||
max_age uint
|
||||
mark_page uint8
|
||||
autosage_after uint
|
||||
no_images_after uint
|
||||
max_message_length uint
|
||||
embeds_allowed string
|
||||
redirect_to_thread bool
|
||||
show_id bool
|
||||
compact_list bool
|
||||
enable_nofile bool
|
||||
enable_catalog bool
|
||||
}
|
||||
|
||||
type BoardSectionsTable struct {
|
||||
id int
|
||||
order int
|
||||
id uint8
|
||||
order uint8
|
||||
hidden bool
|
||||
name string
|
||||
abbreviation string
|
||||
}
|
||||
|
||||
type EmbedsTable struct {
|
||||
id int
|
||||
id uint8
|
||||
filetype string
|
||||
name string
|
||||
videourl string
|
||||
width int
|
||||
height int
|
||||
code string
|
||||
video_url string
|
||||
width uint16
|
||||
height uint16
|
||||
embed_code string
|
||||
}
|
||||
|
||||
type FiletypesTable struct {
|
||||
id int
|
||||
id uint8
|
||||
filetype string
|
||||
mime string
|
||||
image string
|
||||
image_w int
|
||||
image_h int
|
||||
force_thumb bool
|
||||
thumb_image string
|
||||
image_w uint
|
||||
image_h uint
|
||||
}
|
||||
|
||||
type FrontTable struct {
|
||||
id int
|
||||
page int
|
||||
order int
|
||||
id uint16
|
||||
page uint8
|
||||
order uint8
|
||||
subject string
|
||||
message string
|
||||
timestamp int
|
||||
timestamp string
|
||||
poster string
|
||||
email string
|
||||
}
|
||||
|
||||
type FrontLinksTable struct {
|
||||
id uint8
|
||||
title string
|
||||
url string
|
||||
}
|
||||
|
||||
type LoginAttemptsTable struct {
|
||||
username string
|
||||
id uint
|
||||
ip string
|
||||
timestamp int
|
||||
timestamp string
|
||||
}
|
||||
|
||||
type ModLogTable struct {
|
||||
id uint
|
||||
entry string
|
||||
user string
|
||||
category int
|
||||
timestamp int
|
||||
category uint8
|
||||
timestamp string
|
||||
}
|
||||
|
||||
type ModpageAnnouncementsTable struct {
|
||||
id int
|
||||
parentid int
|
||||
subject string
|
||||
postedat int
|
||||
postedby string
|
||||
message string
|
||||
}
|
||||
|
||||
type PollTable struct {
|
||||
type PollResultsTable struct {
|
||||
id uint
|
||||
ip string
|
||||
selection string
|
||||
time int
|
||||
timestamp string
|
||||
}
|
||||
|
||||
type PostTable struct {
|
||||
id int
|
||||
boardid int
|
||||
parentid int
|
||||
id uint
|
||||
boarid uint8
|
||||
parentid uint
|
||||
name string
|
||||
tripcode string
|
||||
email string
|
||||
subject string
|
||||
message string
|
||||
password string
|
||||
file string
|
||||
file_md5 string
|
||||
file_type string
|
||||
file_original string
|
||||
file_size int
|
||||
file_size_formatted string
|
||||
image_w int
|
||||
image_h int
|
||||
thumb_w int
|
||||
thumb_h int
|
||||
filename string
|
||||
filename_original string
|
||||
file_checksum string
|
||||
filesize string
|
||||
image_w uint16
|
||||
image_h uint16
|
||||
thumb_w uint16
|
||||
thumb_h uint16
|
||||
ip string
|
||||
ipmd5 string
|
||||
tag string
|
||||
timestamp int
|
||||
timestamp string
|
||||
autosage uint8
|
||||
poster_authority uint8
|
||||
deleted_timestamp string
|
||||
bumped string
|
||||
stickied bool
|
||||
locked bool
|
||||
autosage int
|
||||
posterauthority int
|
||||
reviewed bool
|
||||
deleted_timestamp int
|
||||
IS_DELETED bool
|
||||
bumped int
|
||||
sillytag string
|
||||
sillytag bool
|
||||
}
|
||||
|
||||
type TempPostTable struct {
|
||||
id uint
|
||||
boarid uint8
|
||||
parentid uint
|
||||
name string
|
||||
tripcode string
|
||||
email string
|
||||
subject string
|
||||
message string
|
||||
password string
|
||||
filename string
|
||||
filename_original string
|
||||
file_checksum string
|
||||
filesize string
|
||||
image_w uint16
|
||||
image_h uint16
|
||||
thumb_w uint16
|
||||
thumb_h uint16
|
||||
ip string
|
||||
tag string
|
||||
timestamp string
|
||||
autosage uint8
|
||||
poster_authority uint8
|
||||
deleted_timestamp string
|
||||
bumped string
|
||||
stickied bool
|
||||
locked bool
|
||||
reviewed bool
|
||||
sillytag bool
|
||||
}
|
||||
|
||||
type ReportsTable struct {
|
||||
id int
|
||||
cleared bool
|
||||
id uint
|
||||
board string
|
||||
postid int
|
||||
when int
|
||||
postid uint
|
||||
timestamp string
|
||||
ip string
|
||||
reason string
|
||||
cleared bool
|
||||
istemp bool
|
||||
}
|
||||
|
||||
type SessionsTable struct {
|
||||
id uint
|
||||
data string
|
||||
expires string
|
||||
}
|
||||
|
||||
type StaffTable struct {
|
||||
id int
|
||||
id uint16
|
||||
username string
|
||||
password string
|
||||
password_checksum string
|
||||
salt string
|
||||
Type int
|
||||
rank uint8
|
||||
boards string
|
||||
addedon int
|
||||
lastactive int
|
||||
em_contact string
|
||||
}
|
||||
|
||||
type TrackerTable struct {
|
||||
index int
|
||||
search_query string
|
||||
found_names string
|
||||
found_ips string
|
||||
}
|
||||
|
||||
type WatchedThreadsTable struct {
|
||||
id int
|
||||
threadid int
|
||||
board string
|
||||
ip string
|
||||
lastsawreplyid int
|
||||
addedon string
|
||||
last_active string
|
||||
}
|
||||
|
||||
type WordFiltersTable struct {
|
||||
id int
|
||||
word string
|
||||
replacedby string
|
||||
id uint16
|
||||
from string
|
||||
to string
|
||||
boards string
|
||||
time int
|
||||
regex bool
|
||||
}
|
||||
|
||||
var (
|
||||
needs_initial_setup = true
|
||||
config,_ = conf.ReadConfigFile("config.cfg")
|
||||
log_dir,_ = config.GetString("server","log_dir")
|
||||
access_log,_ = logfile.OpenLogFile(log_dir+"/access.log",false)
|
||||
error_log,_ = logfile.OpenLogFile(log_dir+"/error.log",false)
|
||||
document_root,_ = config.GetString("server","document_root")
|
||||
first_page_str,_ = config.GetString("server","first_page")
|
||||
first_page = strings.Split(first_page_str,",")
|
||||
domain,_ = config.GetString("server","domain")
|
||||
port,_ = config.GetInt("server","port")
|
||||
db_type,_ = config.GetString("database","type")
|
||||
db_name,_ = config.GetString("database", "name")
|
||||
db_host,_ = config.GetString("database","host")
|
||||
db_username,_ = config.GetString("database","username")
|
||||
db_password,_ = config.GetString("database","password")
|
||||
db_prefix,_ = config.GetString("database","prefix")
|
||||
db_persistent,_ = config.GetBool("database","keepalive")
|
||||
db_persistent_str = strconv.Itoa(Btoi(db_persistent))
|
||||
lockdown bool
|
||||
lockdown_message string
|
||||
sillytags string
|
||||
use_sillytags bool
|
||||
site_name string
|
||||
site_slogan string
|
||||
site_headerurl bool
|
||||
site_irc string
|
||||
site_banreason string
|
||||
site_allowdupes bool
|
||||
webfolder string
|
||||
webpath string
|
||||
root_dir string
|
||||
template_dir string
|
||||
cached_template_dir string
|
||||
styles,_ = config.GetString("styles","styles")
|
||||
styles_arr = strings.Split(styles,",")
|
||||
default_style string
|
||||
style_switcher bool
|
||||
dropdown_style_switcher bool
|
||||
styles_txt []string
|
||||
default_txt_style string
|
||||
txt_style_switcher bool
|
||||
menu_type string
|
||||
menu_styles []string
|
||||
default_menu_style string
|
||||
menu_style_switcher bool
|
||||
new_thread_delay int
|
||||
reply_delay int
|
||||
line_length int
|
||||
thumb_width int
|
||||
thumb_height int
|
||||
reply_thumb_width int
|
||||
reply_thumb_height int
|
||||
catalog_thumb_width int
|
||||
catalog_thumb_height int
|
||||
thumb_method string
|
||||
animated_thumbs bool
|
||||
new_window bool
|
||||
make_links bool
|
||||
no_message_thread bool
|
||||
no_message_reply bool
|
||||
img_threads_per_page int
|
||||
txt_threads_per_page int
|
||||
replies_on_boardpage int
|
||||
sticky_replies_on_boardpage int
|
||||
thumb_msg bool
|
||||
ban_colors []string
|
||||
ban_msg string
|
||||
traditional_read bool
|
||||
youtube_width int
|
||||
youtube_height int
|
||||
use_dir_title bool
|
||||
make_rss bool
|
||||
expand bool
|
||||
quick_reply bool
|
||||
watched_threads bool
|
||||
gen_firstlast_pages bool
|
||||
use_blotter bool
|
||||
make_sitemap bool
|
||||
enable_appeals bool
|
||||
max_modlog_days int
|
||||
random_seed string
|
||||
use_static_menu bool
|
||||
generate_boardlist bool
|
||||
)
|
||||
// Global variables, most initialized by config.cfg
|
||||
|
||||
type GochanConfig struct {
|
||||
Domain string
|
||||
Port int
|
||||
FirstPage []string
|
||||
Error404Path string
|
||||
Error500Path string
|
||||
Username string
|
||||
|
||||
DocumentRoot string
|
||||
TemplateDir string
|
||||
LogDir string
|
||||
|
||||
DBtype string
|
||||
DBhost string
|
||||
DBname string
|
||||
DBusername string
|
||||
DBpassword string
|
||||
DBprefix string
|
||||
DBkeepalive bool
|
||||
|
||||
Lockdown bool
|
||||
LockdownMessage string
|
||||
Sillytags string
|
||||
UseSillytags bool
|
||||
Modboard string
|
||||
|
||||
SiteName string
|
||||
SiteSlogan string
|
||||
SiteHeaderURL string
|
||||
SiteWebfolder string
|
||||
SiteDomain string
|
||||
|
||||
Styles_img []string
|
||||
DefaultStyle_img string
|
||||
Styles_txt []string
|
||||
DefaultStyle_txt string
|
||||
|
||||
AllowDuplicateImages bool
|
||||
NewThreadDelay int
|
||||
ReplyDelay int
|
||||
MaxLineLength int
|
||||
ReservedTrips string //eventually this will be map[string]string
|
||||
|
||||
ThumbWidth int
|
||||
ThumbHeight int
|
||||
ThumbWidth_reply int
|
||||
ThumbHeight_reply int
|
||||
ThumbWidth_catalog int
|
||||
ThumbHeight_catalog int
|
||||
|
||||
ThreadsPerPage_img int
|
||||
ThreadsPerPage_txt int
|
||||
RepliesOnBoardpage int
|
||||
GenLast50 bool
|
||||
GenFirst100 bool
|
||||
StickyRepliesOnBoardPage int
|
||||
BanColors string //eventually this will be map[string] string
|
||||
BanMsg string
|
||||
YoutubeWidth int
|
||||
YoutubeHeight int
|
||||
ExpandButton bool
|
||||
ImagesOpenNewTab bool
|
||||
MakeURLsHyperlinked bool
|
||||
NewTabOnOutlinks bool
|
||||
EnableQuickReply bool
|
||||
|
||||
DefaultBanReason string
|
||||
EnableGeoIP bool
|
||||
GeoIPDBlocation string // set to "cf" or the path to the db
|
||||
MaxRecentPosts int
|
||||
MakeRSS bool
|
||||
MakeSitemap bool
|
||||
EnableAppeals bool
|
||||
MaxModlogDays int
|
||||
RandomSeed string
|
||||
Version float32
|
||||
}
|
||||
|
||||
func initConfig() {
|
||||
var err error
|
||||
c,err = conf.ReadConfigFile("config.cfg")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(2)
|
||||
}
|
||||
config.Domain,err = c.GetString("server", "domain")
|
||||
config.Port,err = c.GetInt("server", "port")
|
||||
if err != nil {
|
||||
config.Port = 80
|
||||
fmt.Println("server.port not set in config.cfg, defaulting to 80")
|
||||
}
|
||||
|
||||
first_page_str,err_ := c.GetString("server", "first_page")
|
||||
if err_ != nil {
|
||||
first_page_str = "board.html,index.html"
|
||||
fmt.Println("server.first_page not set in config.cfg, defaulting to "+first_page_str)
|
||||
}
|
||||
|
||||
config.FirstPage = strings.Split(first_page_str, ",")
|
||||
|
||||
config.Error404Path,err = c.GetString("server", "error_404_path")
|
||||
if err != nil {
|
||||
config.Error404Path = "/error/404.html"
|
||||
fmt.Println("server.error_404_path not set in config.cfg, defaulting to "+config.Error404Path)
|
||||
}
|
||||
config.Error500Path,err = c.GetString("server", "error_500_path")
|
||||
if err != nil {
|
||||
config.Error500Path = "/error/500.html"
|
||||
fmt.Println("server.error_500_path not set in config.cfg, defaulting to "+config.Error500Path)
|
||||
}
|
||||
|
||||
config.Username,err = c.GetString("server", "username")
|
||||
if err != nil {
|
||||
config.Username = "gochan"
|
||||
fmt.Println("server.username not set in config.cfg, defaulting to "+config.Username)
|
||||
}
|
||||
|
||||
config.DocumentRoot,err = c.GetString("directories", "document_root")
|
||||
if err != nil {
|
||||
fmt.Println("directories.document_root not set in config.cfg, halting.")
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
config.TemplateDir,err = c.GetString("directories", "template_dir")
|
||||
if err != nil {
|
||||
config.TemplateDir = "templates"
|
||||
fmt.Println("directories.template_dir not set in config.cfg, defaulting to "+config.TemplateDir)
|
||||
}
|
||||
|
||||
config.LogDir,err = c.GetString("directories", "log_dir")
|
||||
if err != nil {
|
||||
config.LogDir = "log"
|
||||
fmt.Println("directories.log_dir not set in config.cfg, defaulting to "+config.LogDir)
|
||||
}
|
||||
|
||||
access_log,err = logfile.OpenLogFile(config.LogDir+"/access.log",false)
|
||||
if err != nil {
|
||||
fmt.Println("Couldn't open access log. Returned error: "+err.Error())
|
||||
}
|
||||
|
||||
error_log,err = logfile.OpenLogFile(config.LogDir+"/error.log",false)
|
||||
if err != nil {
|
||||
fmt.Println("Couldn't open error log. Returned error: "+err.Error())
|
||||
}
|
||||
|
||||
config.DBtype,err = c.GetString("database", "type")
|
||||
if err != nil {
|
||||
config.DBtype = "mysql"
|
||||
fmt.Println("database.db_type not set in config.cfg, defaulting to "+config.DBtype)
|
||||
}
|
||||
|
||||
config.DBhost,err = c.GetString("database", "host")
|
||||
if err != nil {
|
||||
config.DBhost = "unix(/var/run/mysqld/mysqld.sock)"
|
||||
fmt.Println("database.db_host not set in config.cfg, defaulting to "+config.DBhost)
|
||||
}
|
||||
|
||||
config.DBname,err = c.GetString("database", "name")
|
||||
if err != nil {
|
||||
fmt.Println("database.db_name not set in config.cfg, halting.")
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
config.DBusername,err = c.GetString("database", "username")
|
||||
if err != nil {
|
||||
fmt.Println("database.db_username not set in config.cfg, halting.")
|
||||
os.Exit(2)
|
||||
}
|
||||
config.DBpassword,err = c.GetString("database", "password")
|
||||
if err != nil {
|
||||
config.DBpassword = ""
|
||||
}
|
||||
|
||||
config.DBprefix,err = c.GetString("database", "prefix")
|
||||
if err == nil {
|
||||
config.DBprefix += "_"
|
||||
} else {
|
||||
config.DBprefix = ""
|
||||
}
|
||||
|
||||
config.DBkeepalive,err = c.GetBool("database", "keepalive")
|
||||
if err != nil {
|
||||
config.DBkeepalive = false
|
||||
}
|
||||
|
||||
config.Lockdown,err = c.GetBool("gochan", "lockdown")
|
||||
if err != nil {
|
||||
config.Lockdown = false
|
||||
}
|
||||
config.LockdownMessage,err = c.GetString("gochan", "lockdown_message")
|
||||
if err != nil {
|
||||
config.LockdownMessage = ""
|
||||
}
|
||||
|
||||
config.Sillytags,err = c.GetString("gochan", "sillytags")
|
||||
if err != nil {
|
||||
config.Sillytags = ""
|
||||
}
|
||||
|
||||
config.UseSillytags,err = c.GetBool("gochan", "use_sillytags")
|
||||
if err != nil {
|
||||
config.UseSillytags = false
|
||||
}
|
||||
config.Modboard,err = c.GetString("gochan", "mod_board")
|
||||
if err != nil {
|
||||
config.Modboard = "staff"
|
||||
}
|
||||
|
||||
config.SiteName,err = c.GetString("site", "name")
|
||||
if err != nil {
|
||||
config.SiteName = "An unnamed imageboard"
|
||||
}
|
||||
|
||||
config.SiteSlogan,err = c.GetString("site", "slogan")
|
||||
if err != nil {
|
||||
config.SiteSlogan = ""
|
||||
}
|
||||
|
||||
config.SiteWebfolder,err = c.GetString("site", "webfolder")
|
||||
if err != nil {
|
||||
fmt.Println("site.webfolder not set in config.cfg, halting.")
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
styles_str,err_ := c.GetString("styles", "styles")
|
||||
if err == nil {
|
||||
config.Styles_img = strings.Split(styles_str, ",")
|
||||
}
|
||||
|
||||
config.DefaultStyle_img,err = c.GetString("styles", "default_style")
|
||||
if err != nil {
|
||||
config.DefaultStyle_img = "pipes"
|
||||
}
|
||||
|
||||
styles_txt_str,err_ := c.GetString("styles", "styles_txt")
|
||||
if err == nil {
|
||||
config.Styles_txt = strings.Split(styles_txt_str, ",")
|
||||
}
|
||||
|
||||
config.DefaultStyle_txt,err = c.GetString("styles", "default_txt_style")
|
||||
if err != nil {
|
||||
config.DefaultStyle_txt = "pipes"
|
||||
}
|
||||
|
||||
|
||||
config.AllowDuplicateImages,err = c.GetBool("posting", "allow_duplicate_images")
|
||||
if err != nil {
|
||||
config.AllowDuplicateImages = true
|
||||
}
|
||||
|
||||
config.NewThreadDelay,err = c.GetInt("posting", "new_thread_delay")
|
||||
if err != nil {
|
||||
config.NewThreadDelay = 30
|
||||
}
|
||||
|
||||
config.ReplyDelay,err = c.GetInt("posting", "reply_delay")
|
||||
if err != nil {
|
||||
config.ReplyDelay = 7
|
||||
}
|
||||
|
||||
config.MaxLineLength,err = c.GetInt("posting", "max_line_length")
|
||||
if err != nil {
|
||||
config.MaxLineLength = 150
|
||||
}
|
||||
//ReservedTrips string //eventually this will be map[string]string
|
||||
|
||||
config.ThumbWidth,err = c.GetInt("thumbnails", "thumb_width")
|
||||
if err != nil {
|
||||
config.ThumbWidth = 200
|
||||
}
|
||||
|
||||
config.ThumbWidth,err = c.GetInt("thumbnails", "thumb_height")
|
||||
if err != nil {
|
||||
config.ThumbHeight = 200
|
||||
}
|
||||
|
||||
config.ThumbWidth_reply,err = c.GetInt("thumbnails", "reply_thumb_width")
|
||||
if err != nil {
|
||||
config.ThumbWidth_reply = 125
|
||||
}
|
||||
|
||||
config.ThumbWidth,err = c.GetInt("thumbnails", "reply_thumb_width")
|
||||
if err != nil {
|
||||
config.ThumbHeight_reply = 125
|
||||
}
|
||||
|
||||
config.ThumbWidth,err = c.GetInt("thumbnails", "catalog_thumb_width")
|
||||
if err != nil {
|
||||
config.ThumbWidth_catalog = 50
|
||||
}
|
||||
|
||||
config.ThumbWidth,err = c.GetInt("thumbnails", "catalog_thumb_width")
|
||||
if err != nil {
|
||||
config.ThumbHeight_catalog = 50
|
||||
}
|
||||
|
||||
|
||||
config.ThreadsPerPage_img,err = c.GetInt("threads", "img_threads_per_page")
|
||||
if err != nil {
|
||||
config.ThreadsPerPage_img = 10
|
||||
}
|
||||
|
||||
config.ThreadsPerPage_txt,err = c.GetInt("threads", "txt_threads_per_page")
|
||||
if err != nil {
|
||||
config.ThreadsPerPage_txt = 15
|
||||
}
|
||||
|
||||
config.RepliesOnBoardpage,err = c.GetInt("threads", "replies_on_boardpage")
|
||||
if err != nil {
|
||||
config.RepliesOnBoardpage = 3
|
||||
}
|
||||
|
||||
config.StickyRepliesOnBoardPage,err = c.GetInt("threads", "sticky_replies_on_boardpage")
|
||||
if err != nil {
|
||||
config.StickyRepliesOnBoardPage = 1
|
||||
}
|
||||
|
||||
config.GenLast50,err = c.GetBool("threads", "gen_last50_page")
|
||||
if err != nil {
|
||||
config.GenLast50 = true
|
||||
}
|
||||
|
||||
config.GenFirst100,err = c.GetBool("threads", "gen_first100_page")
|
||||
if err != nil {
|
||||
config.GenFirst100 = false
|
||||
}
|
||||
|
||||
config.BanColors,err = c.GetString("threads", "ban_colors") //eventually this will be map[string] string
|
||||
if err != nil {
|
||||
config.BanColors = "admin:#CC0000"
|
||||
}
|
||||
|
||||
config.BanMsg,err = c.GetString("threads", "ban_msg")
|
||||
if err != nil {
|
||||
config.BanMsg = "(USER WAS BANNED FOR THIS POST)"
|
||||
}
|
||||
|
||||
config.ExpandButton,err = c.GetBool("threads", "expand_button")
|
||||
if err != nil {
|
||||
config.ExpandButton = true
|
||||
}
|
||||
|
||||
config.ImagesOpenNewTab,err = c.GetBool("threads", "images_open_new_tab")
|
||||
if err != nil {
|
||||
config.ImagesOpenNewTab = true
|
||||
}
|
||||
|
||||
config.MakeURLsHyperlinked,err = c.GetBool("threads", "make_urls_hyperlinked")
|
||||
if err != nil {
|
||||
config.MakeURLsHyperlinked = true
|
||||
}
|
||||
|
||||
config.NewTabOnOutlinks,err = c.GetBool("threads", "new_tab_on_outlinks")
|
||||
if err != nil {
|
||||
config.NewTabOnOutlinks = true
|
||||
}
|
||||
|
||||
config.EnableQuickReply,err = c.GetBool("threads", "quick_reply")
|
||||
if err != nil {
|
||||
config.EnableQuickReply = true
|
||||
}
|
||||
|
||||
config.DefaultBanReason,err = c.GetString("misc","default_ban_reason")
|
||||
if err != nil {
|
||||
config.DefaultBanReason = ""
|
||||
}
|
||||
|
||||
config.EnableGeoIP,err = c.GetBool("misc", "enable_geoip")
|
||||
if err != nil {
|
||||
config.EnableGeoIP = false
|
||||
}
|
||||
|
||||
config.GeoIPDBlocation,err = c.GetString("misc","geoip_location") // cf for cloudflare or a local path
|
||||
if err != nil {
|
||||
if config.EnableGeoIP {
|
||||
fmt.Println("Error: GeoIP enabled but no database provided. Set misc.geoip_location in config.cfg to \"cf\" to use CloudFlare's GeoIP headers, or to a local filepath")
|
||||
} else {
|
||||
config.GeoIPDBlocation = ""
|
||||
}
|
||||
}
|
||||
|
||||
config.MaxRecentPosts,err = c.GetInt("misc", "max_recent_posts")
|
||||
if err != nil {
|
||||
config.MaxRecentPosts = 10
|
||||
}
|
||||
|
||||
config.MakeRSS,err = c.GetBool("misc", "make_rss")
|
||||
if err != nil {
|
||||
config.MakeRSS = false
|
||||
}
|
||||
|
||||
config.MakeSitemap,err = c.GetBool("misc", "make_sitemap")
|
||||
if err != nil {
|
||||
config.MakeSitemap = false
|
||||
}
|
||||
|
||||
config.EnableAppeals,err = c.GetBool("misc", "enable_appeals")
|
||||
if err != nil {
|
||||
config.EnableAppeals = true
|
||||
}
|
||||
|
||||
config.MaxModlogDays,err = c.GetInt("misc", "max_modlog_days")
|
||||
if err != nil {
|
||||
config.MaxModlogDays = 15
|
||||
}
|
||||
|
||||
config.RandomSeed,err = c.GetString("misc", "random_seed")
|
||||
if err != nil {
|
||||
}
|
||||
|
||||
config.Version = version
|
||||
}
|
95
src/util.go
95
src/util.go
|
@ -1,13 +1,34 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"crypto/sha1"
|
||||
"code.google.com/p/go.crypto/bcrypt"
|
||||
"io"
|
||||
"os"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
// #cgo LDFLAGS: -lcrypt
|
||||
// #define _GNU_SOURCE
|
||||
// #include <crypt.h>
|
||||
// #include <stdlib.h>
|
||||
import "C"
|
||||
|
||||
var crypt_data = C.struct_crypt_data{}
|
||||
|
||||
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 abcdefghijklmnopqrstuvwxyz~!@#$%^&*()_+{}[]-=:\"\\/?.>,<;:'"
|
||||
|
||||
|
||||
func crypt(key, salt string) string {
|
||||
ckey := C.CString(key)
|
||||
csalt := C.CString(salt)
|
||||
out := C.GoString(C.crypt_r(ckey,csalt,&crypt_data))
|
||||
C.free(unsafe.Pointer(ckey))
|
||||
C.free(unsafe.Pointer(csalt))
|
||||
return out
|
||||
}
|
||||
|
||||
func md5_sum(str string) string {
|
||||
hash := md5.New()
|
||||
|
@ -16,34 +37,51 @@ func md5_sum(str string) string {
|
|||
return digest
|
||||
}
|
||||
|
||||
func readFileToString(path string) (str string, err error) {
|
||||
var (
|
||||
file *os.File
|
||||
part []byte
|
||||
prefix bool
|
||||
)
|
||||
func sha1_sum(str string) string {
|
||||
hash := sha1.New()
|
||||
io.WriteString(hash,str)
|
||||
digest := fmt.Sprintf("%x",hash.Sum(nil))
|
||||
return digest
|
||||
}
|
||||
|
||||
if file,err = os.Open(path); err != nil {
|
||||
return
|
||||
func bcrypt_sum(str string) string {
|
||||
hash := ""
|
||||
digest,err := bcrypt.GenerateFromPassword([]byte(str), 10)
|
||||
if err == nil {
|
||||
hash = fmt.Sprintf("%x",digest)
|
||||
}
|
||||
defer file.Close()
|
||||
return hash
|
||||
}
|
||||
|
||||
reader := bufio.NewReader(file)
|
||||
buffer := bytes.NewBuffer(make([]byte,0))
|
||||
for {
|
||||
if part,prefix,err = reader.ReadLine(); err != nil {
|
||||
break
|
||||
}
|
||||
buffer.Write(part)
|
||||
if !prefix {
|
||||
str = str + buffer.String() + "\n"
|
||||
buffer.Reset()
|
||||
func getCookie(name string) *http.Cookie {
|
||||
num_cookies := len(cookies)
|
||||
for c := 0; c < num_cookies; c += 1 {
|
||||
if cookies[c].Name == name {
|
||||
return cookies[c]
|
||||
}
|
||||
}
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateSalt() string {
|
||||
salt := make([]byte, 3)
|
||||
salt[0] = chars[rand.Intn(86)]
|
||||
salt[1] = chars[rand.Intn(86)]
|
||||
salt[2] = chars[rand.Intn(86)]
|
||||
return string(salt)
|
||||
}
|
||||
|
||||
func getFormattedFilesize(size float32) string {
|
||||
if(size < 1000) {
|
||||
return fmt.Sprintf("%fB", size)
|
||||
} else if(size <= 100000) {
|
||||
//size = size * 0.2
|
||||
return fmt.Sprintf("%fKB", size/1024)
|
||||
} else if(size <= 100000000) {
|
||||
//size = size * 0.2
|
||||
return fmt.Sprintf("%fMB", size/1024/1024)
|
||||
}
|
||||
return
|
||||
return fmt.Sprintf("%0.2fGB", size/1024/1024/1024)
|
||||
}
|
||||
|
||||
func searchStrings(item string,arr []string,permissive bool) int {
|
||||
|
@ -57,6 +95,7 @@ func searchStrings(item string,arr []string,permissive bool) int {
|
|||
}
|
||||
|
||||
func Btoi(b bool) int {
|
||||
if b { return 1 }
|
||||
if b == true { return 1 }
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
|
|
12
templates/error.html
Normal file
12
templates/error.html
Normal file
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Error :c</title>
|
||||
</head>
|
||||
<body>
|
||||
<center>
|
||||
<h1>Error!</h1>
|
||||
<h2>{ERRORTEXT}</h2>
|
||||
</center>
|
||||
</body>
|
||||
</html>
|
|
@ -1 +1,14 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{SITE_NAME}</title>
|
||||
<script type="text/javascript" src="/javascript/jquery/jquery-1.7.2.min.js"></script>
|
||||
<script type="text/javascript" src="/javascript/gochan.js"></script>
|
||||
{link css}
|
||||
</head>
|
||||
<body>
|
||||
<center>
|
||||
<h1>{SITE_NAME}</h1>
|
||||
<h2>{SITE_SLOGAN}</h2>
|
||||
</body>
|
||||
</html>
|
|
@ -1,4 +1,8 @@
|
|||
|
||||
</div>
|
||||
<div id="footer">
|
||||
<a href="{{.SiteWebfolder}}">Home</a> | <a href="{{.SiteWebfolder}}#boards">Boards</a> | <a href="{{.SiteWebfolder}}#rules">Rules</a> | <a href="{{.SiteWebfolder}}#faq">FAQ</a><br />
|
||||
Powered by Kusaba v{{.Version}}<br />
|
||||
Generated in over 9000 hours
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,8 +1,8 @@
|
|||
|
||||
<script type="text/javascript">
|
||||
var board_type = "img";
|
||||
</script>
|
||||
|
||||
<link rel="stylesheet" href="/css/global/front.css" />
|
||||
{{range $i, $style := .Styles_img}}
|
||||
<link rel="{{if isStyleNotDefault_img $style}}alternate {{end}}stylesheet" href="/css/{{$style}}/img.css" />{{end}}
|
||||
<script type="text/javascript">
|
||||
var board_type = "img";
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<link rel="stylesheet" href="/css/global/manage.css" />
|
||||
{{range $i, $style := .Styles_img}}
|
||||
<link rel="{{if isStyleNotDefault_img $style}}alternate {{end}}stylesheet" href="/css/{{$style}}/manage.css" />{{end}}
|
||||
|
||||
<title>Gochan Manage page</title>
|
||||
<script type="text/javascript" src="/javascript/jquery/jquery-1.7.2.min.js"></script>
|
||||
<script type="text/javascript" src="/javascript/gochan.js"></script>
|
||||
|
||||
{link css}
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="content">
|
||||
<body>
|
Loading…
Add table
Add a link
Reference in a new issue