mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-08-01 22:26:24 -07:00
Use router package instead of GET parameter for manage pages
This commit is contained in:
parent
d94a0d8fcf
commit
aba84ceed2
33 changed files with 105 additions and 121 deletions
|
@ -13,7 +13,7 @@ Demo installation: https://gochan.org
|
|||
3. If you're using nginx, copy gochan-http.nginx, or gochan-fastcgi.nginx if `UseFastCGI` is set to true to /etc/nginx/sites-enabled/, or the appropriate folder in Windows.
|
||||
4. If you're using a Linux distribution with systemd, you can optionally copy gochan.service to /lib/systemd/system/gochan.service and run `systemctl enable gochan.service` to have it run on startup. Then run `systemctl start gochan.service` to start it as a background service.
|
||||
1. If you aren't using a distro with systemd, you can start a screen session and run `/path/to/gochan`
|
||||
5. Go to http://[gochan url]/manage?action=staff, log in (default username/password is admin/password), and create a new admin user (and any other staff users as necessary). Then delete the admin user for security.
|
||||
5. Go to http://[gochan url]/manage/staff, log in (default username/password is admin/password), and create a new admin user (and any other staff users as necessary). Then delete the admin user for security.
|
||||
|
||||
## Installation using Docker
|
||||
See [`docker/README.md`](docker/README.md)
|
||||
|
|
2
build.py
2
build.py
|
@ -366,7 +366,7 @@ def install(prefix="/usr", document_root="/srv/gochan", symlinks=False, js_only=
|
|||
print(
|
||||
"gochan was successfully installed. If you haven't already, you should copy\n",
|
||||
"sample-configs/gochan.example.json to /etc/gochan/gochan.json (modify as needed)\n",
|
||||
"You may also need to go to https://yourgochansite/manage?action=rebuildall to rebuild the javascript config")
|
||||
"You may also need to go to https://yourgochansite/manage/rebuildall to rebuild the javascript config")
|
||||
if gcos == "linux":
|
||||
print(
|
||||
"If your Linux distribution has systemd, you will also need to run the following commands:\n",
|
||||
|
|
|
@ -21,7 +21,7 @@ the README and/or the -h command line flag before you use it.
|
|||
migrateCompleteTxt = `Database migration successful!
|
||||
To migrate the uploads for each board, move or copy the uploads to /path/to/gochan/document/root/<boardname>/src/
|
||||
Then copy the thumbnails to /path/to/gochan/documentroot/<boardname>/thumb/
|
||||
Then start the gochan server and go to http://yoursite/manage?action=rebuildall to generate the html files
|
||||
Then start the gochan server and go to http://yoursite/manage/rebuildall to generate the html files
|
||||
for the threads and board pages`
|
||||
|
||||
allowedDirActions = "Valid values are noaction, copy, and move (defaults to noaction if unset)"
|
||||
|
|
|
@ -10,6 +10,8 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/uptrace/bunrouter"
|
||||
|
||||
"github.com/gochan-org/gochan/pkg/config"
|
||||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
"github.com/gochan-org/gochan/pkg/manage"
|
||||
|
@ -18,14 +20,10 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
server *gochanServer
|
||||
router *bunrouter.Router
|
||||
)
|
||||
|
||||
type gochanServer struct {
|
||||
namespaces map[string]func(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
|
||||
func (s gochanServer) serveFile(writer http.ResponseWriter, request *http.Request) {
|
||||
func serveFile(writer http.ResponseWriter, request *http.Request) {
|
||||
systemCritical := config.GetSystemCriticalConfig()
|
||||
siteConfig := config.GetSiteConfig()
|
||||
|
||||
|
@ -56,7 +54,7 @@ func (s gochanServer) serveFile(writer http.ResponseWriter, request *http.Reques
|
|||
return
|
||||
}
|
||||
}
|
||||
s.setFileHeaders(filePath, writer)
|
||||
setFileHeaders(filePath, writer)
|
||||
|
||||
// serve the requested file
|
||||
fileBytes, _ = os.ReadFile(filePath)
|
||||
|
@ -65,7 +63,7 @@ func (s gochanServer) serveFile(writer http.ResponseWriter, request *http.Reques
|
|||
}
|
||||
|
||||
// set mime type/cache headers according to the file's extension
|
||||
func (*gochanServer) setFileHeaders(filename string, writer http.ResponseWriter) {
|
||||
func setFileHeaders(filename string, writer http.ResponseWriter) {
|
||||
extension := strings.ToLower(path.Ext(filename))
|
||||
switch extension {
|
||||
case ".png":
|
||||
|
@ -102,16 +100,6 @@ func (*gochanServer) setFileHeaders(filename string, writer http.ResponseWriter)
|
|||
}
|
||||
}
|
||||
|
||||
func (s gochanServer) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
||||
for name, namespaceFunction := range s.namespaces {
|
||||
if request.URL.Path == config.WebPath(name) {
|
||||
namespaceFunction(writer, request)
|
||||
return
|
||||
}
|
||||
}
|
||||
s.serveFile(writer, request)
|
||||
}
|
||||
|
||||
func initServer() {
|
||||
systemCritical := config.GetSystemCriticalConfig()
|
||||
siteConfig := config.GetSiteConfig()
|
||||
|
@ -124,8 +112,9 @@ func initServer() {
|
|||
Int("Port", systemCritical.Port).Send()
|
||||
fmt.Printf("Failed listening on %s:%d: %s", systemCritical.ListenIP, systemCritical.Port, err.Error())
|
||||
}
|
||||
server = new(gochanServer)
|
||||
server.namespaces = make(map[string]func(http.ResponseWriter, *http.Request))
|
||||
router = bunrouter.New(
|
||||
bunrouter.WithNotFoundHandler(bunrouter.HTTPHandlerFunc(serveFile)),
|
||||
)
|
||||
|
||||
// Check if Akismet API key is usable at startup.
|
||||
err = serverutil.CheckAkismetAPIKey(siteConfig.AkismetAPIKey)
|
||||
|
@ -135,22 +124,21 @@ func initServer() {
|
|||
fmt.Println("Got error when initializing Akismet spam protection, it will be disabled:", err)
|
||||
}
|
||||
|
||||
server.namespaces["captcha"] = posting.ServeCaptcha
|
||||
server.namespaces["manage"] = manage.CallManageFunction
|
||||
server.namespaces["post"] = posting.MakePost
|
||||
server.namespaces["util"] = utilHandler
|
||||
server.namespaces["example"] = func(writer http.ResponseWriter, request *http.Request) {
|
||||
if writer != nil {
|
||||
http.Redirect(writer, request, "https://www.youtube.com/watch?v=dQw4w9WgXcQ", http.StatusFound)
|
||||
}
|
||||
}
|
||||
router.GET(config.WebPath("/captcha"), bunrouter.HTTPHandlerFunc(posting.ServeCaptcha))
|
||||
router.POST(config.WebPath("/captcha"), bunrouter.HTTPHandlerFunc(posting.ServeCaptcha))
|
||||
router.GET(config.WebPath("/manage"), bunrouter.HTTPHandlerFunc(manage.CallManageFunction))
|
||||
router.GET(config.WebPath("/manage/:action"), bunrouter.HTTPHandlerFunc(manage.CallManageFunction))
|
||||
router.POST(config.WebPath("/manage/:action"), bunrouter.HTTPHandlerFunc(manage.CallManageFunction))
|
||||
router.POST(config.WebPath("/post"), bunrouter.HTTPHandlerFunc(posting.MakePost))
|
||||
router.GET(config.WebPath("/util"), bunrouter.HTTPHandlerFunc(utilHandler))
|
||||
router.POST(config.WebPath("/util"), bunrouter.HTTPHandlerFunc(utilHandler))
|
||||
// Eventually plugins might be able to register new namespaces or they might be restricted to something
|
||||
// like /plugin
|
||||
|
||||
if systemCritical.UseFastCGI {
|
||||
err = fcgi.Serve(listener, server)
|
||||
err = fcgi.Serve(listener, router)
|
||||
} else {
|
||||
err = http.Serve(listener, server)
|
||||
err = http.Serve(listener, router)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
|
@ -57,7 +57,7 @@ def gotoPage(driver: WebDriver, page: str):
|
|||
|
||||
|
||||
def isLoggedIn(driver: WebDriver):
|
||||
gotoPage(driver, "manage?action=login")
|
||||
gotoPage(driver, "manage/login")
|
||||
return driver.find_element(by=By.CSS_SELECTOR, value="h1#board-title").text == "Dashboard"
|
||||
|
||||
|
||||
|
@ -177,7 +177,7 @@ class TestRunner(unittest.TestCase):
|
|||
if boardExists("seleniumtesting"):
|
||||
raise Exception("Board /seleniumtests/ already exists")
|
||||
loginToStaff(self.driver)
|
||||
gotoPage(self.driver, "manage?action=boards")
|
||||
gotoPage(self.driver, "manage/boards")
|
||||
|
||||
# fill out the board creation form
|
||||
self.driver.find_element(by=By.NAME, value="dir").\
|
||||
|
@ -197,7 +197,7 @@ class TestRunner(unittest.TestCase):
|
|||
|
||||
makePostOnPage("seleniumtesting", self)
|
||||
|
||||
gotoPage(self.driver, "manage?action=boards")
|
||||
gotoPage(self.driver, "manage/boards")
|
||||
sel = Select(self.driver.find_element(by=By.ID, value="modifyboard"))
|
||||
sel.select_by_visible_text("/seleniumtesting/ - Selenium testing")
|
||||
self.driver.find_element(by=By.NAME, value="dodelete").click()
|
||||
|
@ -221,7 +221,7 @@ class TestRunner(unittest.TestCase):
|
|||
def test_moveThread(self):
|
||||
if not boardExists("test2"):
|
||||
loginToStaff(self.driver)
|
||||
gotoPage(self.driver, "manage?action=boards")
|
||||
gotoPage(self.driver, "manage/boards")
|
||||
|
||||
# fill out the board creation form
|
||||
self.driver.find_element(by=By.NAME, value="dir").\
|
||||
|
|
|
@ -31,7 +31,7 @@ If you want, you can install [Sass](https://sass-lang.com/install) to streamline
|
|||
|
||||
To use sass, run `./build.py sass`. If you want to minify the created css files, use the `--minify` flag. If you want sass to watch the input directory for changes as you edit and save the files, use the `--watch` flag.
|
||||
|
||||
If you are upgading from gochan 2.2, delete your html/css directory unless you have made themes that you want to keep. Then rebuild the pages. (/manage?action=rebuildall)
|
||||
If you are upgading from gochan 2.2, delete your html/css directory unless you have made themes that you want to keep. Then rebuild the pages. (/manage/rebuildall)
|
||||
|
||||
## Attribution
|
||||
The BunkerChan, Clear, and Dark themes come from the imageboard BunkerChan. Burichan is based on the theme with the same name from Kusaba X. Photon comes from nol.ch (I think?) that as far as I know no longer exists. Pipes was created by a user (Mbyte?) on Lunachan (defunct). Yotsuba and Yotsuba B are based on the themes with the same names from 4chan.
|
|
@ -157,7 +157,7 @@ function handleActions(action, postIDStr) {
|
|||
// manage stuff
|
||||
case "Posts from this IP":
|
||||
getPostInfo(postID).then(info => {
|
||||
window.open(`${webroot}manage?action=ipsearch&limit=100&ip=${info.ip}`);
|
||||
window.open(`${webroot}manage/ipsearch?limit=100&ip=${info.ip}`);
|
||||
}).catch(reason => {
|
||||
alertLightbox(`Failed getting post IP: ${reason.statusText}`, "Error");
|
||||
});
|
||||
|
|
|
@ -4,7 +4,7 @@ import "jquery-ui/ui/unique-id";
|
|||
import "jquery-ui/ui/keycode";
|
||||
import "jquery-ui/ui/widgets/tabs";
|
||||
$(() => {
|
||||
if(window.location.search.indexOf("?action=filebans") != 0)
|
||||
if(window.location.pathname != webroot + "manage/filebans")
|
||||
return;
|
||||
$("div#fileban-tabs").tabs();
|
||||
});
|
|
@ -92,7 +92,7 @@ export function banFile(banType, filename, checksum, staffNote = "") {
|
|||
}
|
||||
return $.ajax({
|
||||
method: "POST",
|
||||
url: `${webroot}manage?action=filebans`,
|
||||
url: `${webroot}manage/filebans`,
|
||||
data: xhrFields
|
||||
});
|
||||
}
|
||||
|
@ -100,10 +100,7 @@ export function banFile(banType, filename, checksum, staffNote = "") {
|
|||
export async function initStaff() {
|
||||
return $.ajax({
|
||||
method: "GET",
|
||||
url: `${webroot}manage`,
|
||||
data: {
|
||||
action: "actions"
|
||||
},
|
||||
url: `${webroot}manage/actions`,
|
||||
async: true,
|
||||
cache: false,
|
||||
success: result => {
|
||||
|
@ -138,10 +135,7 @@ export async function getStaffInfo() {
|
|||
loginChecked = true;
|
||||
return $.ajax({
|
||||
method: "GET",
|
||||
url: `${webroot}manage`,
|
||||
data: {
|
||||
action: "staffinfo",
|
||||
},
|
||||
url: `${webroot}manage/staffinfo`,
|
||||
async: true,
|
||||
cache: true,
|
||||
dataType: "json"
|
||||
|
@ -158,9 +152,8 @@ export async function getStaffInfo() {
|
|||
export async function getPostInfo(id) {
|
||||
return $.ajax({
|
||||
method: "GET",
|
||||
url: `${webroot}manage`,
|
||||
url: `${webroot}manage/postinfo`,
|
||||
data: {
|
||||
action: "postinfo",
|
||||
postid: id
|
||||
},
|
||||
async: true,
|
||||
|
@ -191,7 +184,7 @@ export function banSelectedPost() {
|
|||
break;
|
||||
}
|
||||
}
|
||||
window.location = `${webroot}manage?action=bans&dir=${boardDir}&postid=${postID}`;
|
||||
window.location = `${webroot}manage/bans?dir=${boardDir}&postid=${postID}`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -201,7 +194,7 @@ export function banSelectedPost() {
|
|||
function menuItem(action, isCategory = false) {
|
||||
return isCategory ? $("<div/>").append($("<b/>").text(action)) : $("<div/>").append(
|
||||
$("<a/>").prop({
|
||||
href: `${webroot}manage?action=${action.id}`
|
||||
href: `${webroot}manage/${action.id}`
|
||||
}).text(action.title)
|
||||
);
|
||||
}
|
||||
|
@ -294,9 +287,8 @@ function updateReports(reports) {
|
|||
function getReports() {
|
||||
return $.ajax({
|
||||
method: "GET",
|
||||
url: `${webroot}manage`,
|
||||
url: `${webroot}manage/reports`,
|
||||
data: {
|
||||
action: "reports",
|
||||
json: "1"
|
||||
},
|
||||
async: true,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Make the sections table on /manage?action=boardsections sortable to make changing the list order easier
|
||||
// Make the sections table on /manage/boardsections sortable to make changing the list order easier
|
||||
|
||||
/* global webroot */
|
||||
|
||||
|
@ -28,7 +28,7 @@ function applyOrderChanges() {
|
|||
let sectionhidden = $el.find(":nth-child(4)").html().toLowerCase() == "yes"?"on":"off";
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: webroot + "manage?action=boardsections",
|
||||
url: webroot + "manage/boardsections",
|
||||
data: {
|
||||
updatesection: updatesection,
|
||||
sectionname: sectionname,
|
||||
|
@ -81,7 +81,7 @@ function addButtons() {
|
|||
}
|
||||
|
||||
$(() => {
|
||||
if(window.location.search.indexOf("?action=boardsections") != 0)
|
||||
if(window.location.pathname != webroot + "manage/boardsections")
|
||||
return;
|
||||
|
||||
$sectionsTable = $("table#sections");
|
||||
|
|
6
frontend/js/types/gochan.d.ts
vendored
6
frontend/js/types/gochan.d.ts
vendored
|
@ -91,7 +91,7 @@ declare interface ThreadPost {
|
|||
}
|
||||
|
||||
/**
|
||||
* An object representing a staff member retreived by requesting /manage?action=staffinfo
|
||||
* An object representing a staff member retreived by requesting /manage/staffinfo
|
||||
*/
|
||||
interface StaffInfo {
|
||||
/**
|
||||
|
@ -117,7 +117,7 @@ declare interface ThreadPost {
|
|||
*/
|
||||
interface StaffAction {
|
||||
/**
|
||||
* The GET key used when requesting /manage?action=<id>
|
||||
* The GET key used when requesting /manage/<id>
|
||||
*/
|
||||
id?:string;
|
||||
/**
|
||||
|
@ -142,7 +142,7 @@ interface StaffAction {
|
|||
}
|
||||
|
||||
/**
|
||||
* The result of requesting /manage?action=actions
|
||||
* The result of requesting /manage/actions
|
||||
*/
|
||||
declare var staffActions: StaffAction[];
|
||||
|
||||
|
|
12
frontend/package-lock.json
generated
12
frontend/package-lock.json
generated
|
@ -8440,9 +8440,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/json5": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
|
||||
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
||||
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"json5": "lib/cli.js"
|
||||
|
@ -16345,9 +16345,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"json5": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
|
||||
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
||||
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
|
||||
"dev": true
|
||||
},
|
||||
"kleur": {
|
||||
|
|
1
go.mod
1
go.mod
|
@ -13,6 +13,7 @@ require (
|
|||
github.com/tdewolff/minify v2.3.6+incompatible
|
||||
github.com/tdewolff/parse v2.3.4+incompatible // indirect
|
||||
github.com/tdewolff/test v1.0.7 // indirect
|
||||
github.com/uptrace/bunrouter v1.0.19 // indirect
|
||||
github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64
|
||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
|
||||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b
|
||||
|
|
8
go.sum
8
go.sum
|
@ -4,6 +4,7 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
|
|||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/frustra/bbcode v0.0.0-20201127003707-6ef347fbe1c8 h1:sdIsYe6Vv7KIWZWp8KqSeTl+XlF17d+wHCC4lbxFcYs=
|
||||
|
@ -20,15 +21,20 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
|
|||
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
||||
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY=
|
||||
github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/tdewolff/minify v2.3.6+incompatible h1:2hw5/9ZvxhWLvBUnHE06gElGYz+Jv9R4Eys0XUzItYo=
|
||||
github.com/tdewolff/minify v2.3.6+incompatible/go.mod h1:9Ov578KJUmAWpS6NeZwRZyT56Uf6o3Mcz9CEsg8USYs=
|
||||
github.com/tdewolff/parse v2.3.4+incompatible h1:x05/cnGwIMf4ceLuDMBOdQ1qGniMoxpP46ghf0Qzh38=
|
||||
github.com/tdewolff/parse v2.3.4+incompatible/go.mod h1:8oBwCsVmUkgHO8M5iCzSIDtpzXOT0WXX9cWhz+bIzJQ=
|
||||
github.com/tdewolff/test v1.0.7 h1:8Vs0142DmPFW/bQeHRP3MV19m1gvndjUb1sn8yy74LM=
|
||||
github.com/tdewolff/test v1.0.7/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
||||
github.com/uptrace/bunrouter v1.0.19 h1:kdN1Nl/9RDq9eBPnjS6GvNKcgiAeMxdb9DbpslLndFg=
|
||||
github.com/uptrace/bunrouter v1.0.19/go.mod h1:TwT7Bc0ztF2Z2q/ZzMuSVkcb/Ig/d3MQeP2cxn3e1hI=
|
||||
github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
|
||||
github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 h1:5mLPGnFdSsevFRFc9q3yYbBkB6tsm4aCwwQV/j1JQAQ=
|
||||
github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
|
||||
|
@ -56,5 +62,7 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
layeh.com/gopher-luar v1.0.10 h1:55b0mpBhN9XSshEd2Nz6WsbYXctyBT35azk4POQNSXo=
|
||||
layeh.com/gopher-luar v1.0.10/go.mod h1:TPnIVCZ2RJBndm7ohXyaqfhzjlZ+OA2SZR/YwL8tECk=
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
<title>gochan</title>
|
||||
</head>
|
||||
<body>
|
||||
Welcome to gochan! The front page hasn't been created yet, so you will need to log in and build it. You can do so <a href="/manage?action=rebuildall">here</a>. The default username is "admin", and the default password is "password". For security reasons, you should probably change that befor you go public.<br />
|
||||
Next, you should create a board, which you can do <a href="/manage?action=boards">here</a>.<br />
|
||||
Welcome to gochan! The front page hasn't been created yet, so you will need to log in and build it. You can do so <a href="/manage/rebuildall">here</a>. The default username is "admin", and the default password is "password". For security reasons, you should probably change that befor you go public.<br />
|
||||
Next, you should create a board, which you can do <a href="/manage/boards">here</a>.<br />
|
||||
Thank you for using gochan.
|
||||
</body>
|
||||
</html>
|
|
@ -161,7 +161,7 @@ type Post struct {
|
|||
Subject string // sql: `subject`
|
||||
Message template.HTML // sql: `message`
|
||||
MessageRaw string // sql: `message_raw`
|
||||
Password string // sql: `password`
|
||||
Password string `json:"-"` // sql: `password`
|
||||
DeletedAt time.Time // sql: `deleted_at`
|
||||
IsDeleted bool // sql: `is_deleted`
|
||||
BannedMessage string // sql: `banned_message`
|
||||
|
@ -208,11 +208,11 @@ type LoginSession struct {
|
|||
type Staff struct {
|
||||
ID int // sql: `id`
|
||||
Username string // sql: `username`
|
||||
PasswordChecksum string // sql: `password_checksum`
|
||||
PasswordChecksum string `json:"-"` // sql: `password_checksum`
|
||||
Rank int // sql: `global_rank`
|
||||
AddedOn time.Time // sql: `added_on`
|
||||
LastLogin time.Time // sql: `last_login`
|
||||
IsActive bool // sql: `is_active`
|
||||
AddedOn time.Time `json:"-"` // sql: `added_on`
|
||||
LastLogin time.Time `json:"-"` // sql: `last_login`
|
||||
IsActive bool `json:"-"` // sql: `is_active`
|
||||
}
|
||||
|
||||
// table: DBPREFIXthreads
|
||||
|
|
|
@ -46,9 +46,9 @@ var (
|
|||
chopPortNumRegex = regexp.MustCompile(`(.+|\w+):(\d+)$`)
|
||||
)
|
||||
|
||||
// Action represents the functions accessed by staff members at /manage?action=<functionname>.
|
||||
// Action represents the functions accessed by staff members at /manage/<functionname>.
|
||||
type Action struct {
|
||||
// the string used when the user requests /manage?action=<id>
|
||||
// the string used when the user requests /manage/<ID>
|
||||
ID string `json:"id"`
|
||||
|
||||
// The text shown in the staff menu and the window title
|
||||
|
@ -159,7 +159,7 @@ var actions = []Action{
|
|||
}
|
||||
outputStr += "Cleanup finished"
|
||||
} else {
|
||||
outputStr += `<form action="/manage?action=cleanup" method="post">` +
|
||||
outputStr += `<form action="/manage/cleanup" method="post">` +
|
||||
`<input name="run" id="run" type="submit" value="Run Cleanup" />` +
|
||||
`</form>`
|
||||
}
|
||||
|
@ -781,7 +781,7 @@ var actions = []Action{
|
|||
} else {
|
||||
key := gcutil.Md5Sum(request.RemoteAddr + username + password + systemCritical.RandomSeed + gcutil.RandomString(3))[0:10]
|
||||
createSession(key, username, password, request, writer)
|
||||
http.Redirect(writer, request, path.Join(systemCritical.WebRoot, "manage?action="+request.FormValue("redirect")), http.StatusFound)
|
||||
http.Redirect(writer, request, path.Join(systemCritical.WebRoot, "manage/"+request.FormValue("redirect")), http.StatusFound)
|
||||
}
|
||||
return
|
||||
}},
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/gochan-org/gochan/pkg/gcsql"
|
||||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
"github.com/gochan-org/gochan/pkg/serverutil"
|
||||
"github.com/uptrace/bunrouter"
|
||||
)
|
||||
|
||||
type ErrStaffAction struct {
|
||||
|
@ -43,13 +44,12 @@ func CallManageFunction(writer http.ResponseWriter, request *http.Request) {
|
|||
|
||||
errEv.Str("IP", gcutil.GetRealIP(request))
|
||||
if err = request.ParseForm(); err != nil {
|
||||
errEv.
|
||||
Str("IP", gcutil.GetRealIP(request)).
|
||||
Caller().Msg("Error parsing form data")
|
||||
errEv.Err(err).Caller().Msg("Error parsing form data")
|
||||
serverutil.ServeError(writer, "Error parsing form data: "+err.Error(), wantsJSON, nil)
|
||||
return
|
||||
}
|
||||
actionID := request.FormValue("action")
|
||||
params := bunrouter.ParamsFromContext(request.Context())
|
||||
actionID := params.ByName("action")
|
||||
gcutil.LogStr("action", actionID, infoEv, accessEv, errEv)
|
||||
|
||||
var staff *gcsql.Staff
|
||||
|
|
|
@ -50,7 +50,7 @@ func ServeErrorPage(writer http.ResponseWriter, err string) {
|
|||
// ServeNotFound shows an error page if a requested file is not found
|
||||
func ServeNotFound(writer http.ResponseWriter, request *http.Request) {
|
||||
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
writer.WriteHeader(404)
|
||||
writer.WriteHeader(http.StatusNotFound)
|
||||
systemCritical := config.GetSystemCriticalConfig()
|
||||
errorPage, err := os.ReadFile(systemCritical.DocumentRoot + "/error/404.html")
|
||||
if err != nil {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<table border="1">
|
||||
<tr><th>Action</th><th>Appeal Text</th><th>Banned IP</th></tr>
|
||||
{{range $_,$appeal := $.appeals}}
|
||||
<tr><td><a href="{{webPath "manage"}}?action=appeals&approve={{$appeal.ID}}">Approve</a> | <a href="{{webPath "manage"}}?action=appeals&deny={{$appeal.ID}}">Deny</a></td><td>{{$appeal.AppealText}}</td><td>{{getAppealBanIP $appeal.IPBanID}}</td></tr>
|
||||
<tr><td><a href="{{webPath "manage/appeals"}}?approve={{$appeal.ID}}">Approve</a> | <a href="{{webPath "manage/appeals"}}?deny={{$appeal.ID}}">Deny</a></td><td>{{$appeal.AppealText}}</td><td>{{getAppealBanIP $appeal.IPBanID}}</td></tr>
|
||||
<tr></tr>
|
||||
{{end}}
|
||||
</table>
|
|
@ -1,4 +1,4 @@
|
|||
<form method="POST" action="{{webPath "manage?action=bans"}}">
|
||||
<form method="POST" action="{{webPath "manage/bans"}}">
|
||||
<input type="hidden" name="do" value="add" />
|
||||
<h2>Add IP ban</h2>
|
||||
<table>
|
||||
|
@ -20,13 +20,12 @@
|
|||
<tr><th>Reason</th><td><textarea name="reason" style="width: 100%;" rows="6" placeholder="Message to be displayed to the banned user"></textarea></td></tr>
|
||||
<tr><th>Staff note</th><td><textarea name="staffnote" style="width: 100%;" rows="6" placeholder="Private note that only staff can see"></textarea></td></tr>
|
||||
</table>
|
||||
<input type="submit" value="Ban user" /> <input type="button" name="docancel" value="Cancel" onclick="window.location = './manage?action=bans'; return false"/>
|
||||
<input type="submit" value="Ban user" /> <input type="button" name="docancel" value="Cancel" onclick="window.location = './manage/bans'; return false"/>
|
||||
</form>
|
||||
|
||||
<h2 id="banlist">Banlist</h2>
|
||||
<form action="{{webPath "manage?action=bans"}}" method="get">
|
||||
<input type="hidden" name="action" value="bans">
|
||||
Filter board: <select name="filterboardid" id="filterboardid" onchange="window.location = '{{webPath "manage?action=bans&filterboardid="}}' + this.value + '#banlist'">
|
||||
<form action="{{webPath "manage/bans"}}" method="get">
|
||||
Filter board: <select name="filterboardid" id="filterboardid" onchange="window.location = '{{webPath "manage/bans?filterboardid="}}' + this.value + '#banlist'">
|
||||
<option value="0">All boards</option>
|
||||
{{- range $b, $board := $.allBoards -}}
|
||||
<option value="{{$board.ID}}" {{if eq $.filterboardid $board.ID}}selected{{end}}>/{{$board.Dir}}/ - {{$board.Title}}</option>
|
||||
|
@ -37,7 +36,7 @@ Filter board: <select name="filterboardid" id="filterboardid" onchange="window.l
|
|||
<tr><th>Action</th><th>IP</th><th>Board</th><th>Reason</th><th>Staff</th><th>Staff note</th><th>Banned post text</th><th>Set</th><th>Expires</th><th>Appeal at</th></tr>
|
||||
{{range $_, $ban := $.banlist -}}
|
||||
<tr>
|
||||
<td> <a href="{{webPath "manage?action=bans&edit="}}{{$ban.ID}}">Edit</a> | <a href="{{webPath "manage?action=bans&delete="}}{{$ban.ID}}">Delete</a> </td>
|
||||
<td> <a href="{{webPath "manage/bans?edit="}}{{$ban.ID}}">Edit</a> | <a href="{{webPath "manage/bans?delete="}}{{$ban.ID}}">Delete</a> </td>
|
||||
<td>{{$ban.IP}}</td>
|
||||
<td>{{if not $ban.BoardID}}<i>all</i>{{else}}/{{getBoardDirFromID $ban.BoardID}}/{{end}}</td>
|
||||
<td>{{$ban.Message}}</td>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<form action="{{$.webroot}}manage?action=boards" method="GET">
|
||||
<input type="hidden" name="action" value="boards">
|
||||
<form action="{{$.webroot}}manage/boards" method="GET">
|
||||
{{with $.boards}}{{else}}
|
||||
<input type="hidden" name="noboards" value="1">
|
||||
{{end}}
|
||||
|
@ -20,8 +19,7 @@
|
|||
{{else}}
|
||||
<h2>Create new board</h2>
|
||||
{{end}}
|
||||
<form action="{{$.webroot}}manage?action=boards" method="POST">
|
||||
<input type="hidden" name="action" value="boards">
|
||||
<form action="{{$.webroot}}manage/boards" method="POST">
|
||||
<input type="hidden" name="board" value="{{$.board.ID}}"/>
|
||||
<table>
|
||||
<tr>
|
||||
|
@ -127,7 +125,7 @@
|
|||
</table>
|
||||
{{- if $.editing -}}
|
||||
<input type="submit" name="domodify" value="Save changes" onclick="return confirm('Click ok to confirm')"/>
|
||||
<input type="submit" name="docancel" value="Cancel" onclick="window.location = './manage?action=boards'; return false"/>
|
||||
<input type="submit" name="docancel" value="Cancel" onclick="window.location = './manage/boards'; return false"/>
|
||||
{{- else -}}
|
||||
<input type="submit" name="docreate" value="Create new board" onclick="return confirm('Click ok to confirm')"/>
|
||||
{{- end -}}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Some fields omitted because they can not be (safely) edited from the web interface while Gochan is running.
|
||||
Edit these directly in gochan.json, then restart Gochan.<br />
|
||||
<span class="warning">This config editor isn't fully stable so MAKE BACKUPS!</span>
|
||||
<form action="/manage?action=config" method="POST">
|
||||
<form action="/manage/config" method="POST">
|
||||
<input name="do" value="save" type="hidden" />
|
||||
{{generateConfigTable}}<br />
|
||||
<input type="submit" />
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
<fieldset><legend>Staff actions (role: {{$.rankString}})</legend>
|
||||
<ul>
|
||||
{{range $a, $action := $.actions}}
|
||||
{{if ne $action.Title "Dashboard"}}<li><a href="{{$.webroot}}manage?action={{$action.ID}}">{{$action.Title}}</a> </li>{{end}}
|
||||
{{if ne $action.Title "Dashboard"}}<li><a href="{{$.webroot}}manage/{{$action.ID}}">{{$action.Title}}</a> </li>{{end}}
|
||||
{{end}}
|
||||
</ul>
|
||||
</fieldset>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
</ul>
|
||||
<div id="filename-bans">
|
||||
<h2>Create new filename ban</h2>
|
||||
<form id="filenamebanform" action="{{.webroot}}manage?action=filebans" method="POST">
|
||||
<form id="filenamebanform" action="{{.webroot}}manage/filebans" method="POST">
|
||||
<input type="hidden" name="bantype" value="filename">
|
||||
<table>
|
||||
<tr><td>Filename:</td><td><input type="text" name="filename" id="filename"></td></tr>
|
||||
|
@ -34,7 +34,7 @@
|
|||
<td>{{$staff := (getStaffNameFromID $ban.StaffID)}}{{if eq $staff ""}}<i>?</i>{{else}}{{$staff}}{{end}}</td>
|
||||
|
||||
<td>{{$ban.StaffNote}}</td>
|
||||
<td><a href="{{$.webroot}}manage?action=filebans&delfnb={{$ban.ID}}">Delete</a></td>
|
||||
<td><a href="{{$.webroot}}manage/filebans?delfnb={{$ban.ID}}">Delete</a></td>
|
||||
</tr>
|
||||
{{end -}}
|
||||
</table>
|
||||
|
@ -42,7 +42,7 @@
|
|||
</div>
|
||||
<div id="checksum-bans">
|
||||
<h2>Create new file checksum ban</h2>
|
||||
<form id="checksumbanform" action="{{.webroot}}manage?action=filebans#checksum-bans" method="POST">
|
||||
<form id="checksumbanform" action="{{.webroot}}manage/filebans#checksum-bans" method="POST">
|
||||
<input type="hidden" name="bantype" value="checksum">
|
||||
<table>
|
||||
<tr><td>Checksum</td><td><input type="text" name="checksum"></td></tr>
|
||||
|
@ -68,7 +68,7 @@
|
|||
<td>{{$uri := (intPtrToBoardDir $ban.BoardID "" "?")}}{{if eq $uri ""}}<i>All boards</i>{{else}}/{{$uri}}/{{end}}</td>
|
||||
<td>{{$staff := (getStaffNameFromID $ban.StaffID)}}{{if eq $staff ""}}<i>?</i>{{else}}{{$staff}}{{end}}</td>
|
||||
<td>{{$ban.StaffNote}}</td>
|
||||
<td><a href="{{$.webroot}}manage?action=filebans&delcsb={{$ban.ID}}#checksum-bans">Delete</a></td>
|
||||
<td><a href="{{$.webroot}}manage/filebans?delcsb={{$ban.ID}}#checksum-bans">Delete</a></td>
|
||||
</tr>
|
||||
{{- end -}}
|
||||
</table>
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
{{- end -}}
|
||||
<fieldset>
|
||||
<legend>Search</legend>
|
||||
<form method="GET" action="{{.webroot}}manage" class="staff-form">
|
||||
<input type="hidden" name="action" value="ipsearch"/>
|
||||
<form method="GET" action="{{.webroot}}manage/ipsearch" class="staff-form">
|
||||
<label for="ip">IP Address</label>
|
||||
<input type="text" name="ip" id="ipquery" value="{{.ipQuery}}"><br />
|
||||
<label for="number">Max results</label>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<form method="POST" action="{{.webroot}}manage?action=login" id="login-box" class="staff-form">
|
||||
<form method="POST" action="{{.webroot}}manage/login" id="login-box" class="staff-form">
|
||||
<input type="hidden" name="redirect" value="{{.redirect}}" />
|
||||
<table>
|
||||
<tr><td>Login</td><td><input type="text" name="username" class="logindata" /><br /></td></tr>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<h2>Create a new name/tripcode ban</h2>
|
||||
<form id="namebanform" action="{{.webroot}}manage?action=namebans" method="post">
|
||||
<form id="namebanform" action="{{.webroot}}manage/namebans" method="post">
|
||||
<table>
|
||||
<tr><td>Name/Tripcode:</td><td><input type="text" name="name" id="name"> (ex: "Name", "Name!Tripcode", "!Tripcode, etc)</td></tr>
|
||||
<tr><td>Regular expression:</td><td><input type="checkbox" name="isregex" id="isregex"/></td></tr>
|
||||
|
@ -25,7 +25,7 @@
|
|||
<td>{{$uri := (intPtrToBoardDir $ban.BoardID "" "?")}}{{if eq $uri ""}}<i>All boards</i>{{else}}/{{$uri}}/{{end}}</td>
|
||||
<td>{{$staff := (getStaffNameFromID $ban.StaffID)}}{{if eq $staff ""}}<i>?</i>{{else}}{{$staff}}{{end}}</td>
|
||||
<td>{{$ban.StaffNote}}</td>
|
||||
<td><a href="{{$.webroot}}manage?action=namebans&del={{$ban.ID}}">Delete</a></td>
|
||||
<td><a href="{{$.webroot}}manage/namebans?del={{$ban.ID}}">Delete</a></td>
|
||||
{{end -}}
|
||||
</table>
|
||||
{{end}}
|
|
@ -1,5 +1,4 @@
|
|||
<form action="{{$.webroot}}manage" method="GET">
|
||||
<input type="hidden" name="action" value="recentposts">
|
||||
<form action="{{$.webroot}}manage/recentposts" method="GET">
|
||||
<label for="boardid">Board:</label>
|
||||
<select name="boardid" id="boardid">
|
||||
<option value="0">All boards</option>
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
{{$report.staff_user}}
|
||||
{{- end -}}
|
||||
</td><td>
|
||||
<a href="{{webPath "manage?action=reports&dismiss="}}{{$report.id}}">Dismiss</a>
|
||||
<a href="{{webPath "manage/reports?dismiss="}}{{$report.id}}">Dismiss</a>
|
||||
{{if eq $.staff.Rank 3 -}}
|
||||
|
|
||||
<a href="{{webPath "manage?action=reports&dismiss="}}{{$report.id}}&block=1" title="Prevent future reports of this post, regardless of report reason">Make post unreportable</a>
|
||||
<a href="{{webPath "manage/reports?dismiss="}}{{$report.id}}&block=1" title="Prevent future reports of this post, regardless of report reason">Make post unreportable</a>
|
||||
{{- end}}
|
||||
</td></tr>
|
||||
{{end}}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<form action="{{.webroot}}manage?action=boardsections" method="POST" id="sectionform">
|
||||
<form action="{{.webroot}}manage/boardsections" method="POST" id="sectionform">
|
||||
{{with .edit_section}}<input type="hidden" name="updatesection" value="{{.ID}}" />{{end}}
|
||||
<h2>{{with .edit_section}}Edit{{else}}New{{end}} section</h2>
|
||||
<table>
|
||||
|
@ -9,7 +9,7 @@
|
|||
</table>
|
||||
<input type="submit" name="save_section" value="{{with .edit_section}}Save{{else}}Create{{end}} section">
|
||||
{{with .edit_section}}
|
||||
<input type="button" onclick="window.location='{{$.webroot}}manage?action=boardsections'" value="Cancel">
|
||||
<input type="button" onclick="window.location='{{$.webroot}}manage/boardsections'" value="Cancel">
|
||||
{{else}}
|
||||
<input type="button" onclick="document.getElementById('sectionform').reset()" value="Reset"/>
|
||||
{{end}}
|
||||
|
@ -24,8 +24,8 @@
|
|||
<td>{{$section.Abbreviation}}</td>
|
||||
<td>{{$section.Position}}</td>
|
||||
<td>{{if eq $section.Hidden true}}Yes{{else}}No{{end}}</td>
|
||||
<td><a href="{{$.webroot}}manage?action=boardsections&edit={{$section.ID}}">Edit</a> |
|
||||
<a href="{{$.webroot}}manage?action=boardsections&delete={{$section.ID}}" onclick="return confirm('Are you sure you want to delete this section?')">Delete</a></td>
|
||||
<td><a href="{{$.webroot}}manage/boardsections?edit={{$section.ID}}">Edit</a> |
|
||||
<a href="{{$.webroot}}manage/boardsections?delete={{$section.ID}}" onclick="return confirm('Are you sure you want to delete this section?')">Delete</a></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</table>
|
||||
|
|
|
@ -12,16 +12,16 @@
|
|||
<td>{{formatTimestamp $staff.AddedOn}}</td>
|
||||
<td>
|
||||
<a {{if eq $staff.Username $.currentUsername -}}
|
||||
href="{{$.webroot}}manage?action=staff" title="Cannot self terminate" style="color: black;"
|
||||
href="{{$.webroot}}manage/staff" title="Cannot self terminate" style="color: black;"
|
||||
{{- else -}}
|
||||
href="{{$.webroot}}manage?action=staff&do=del&username={{$staff.Username}}" title="Delete {{$staff.Username}}" style="color:red;"
|
||||
href="{{$.webroot}}manage/staff?do=del&username={{$staff.Username}}" title="Delete {{$staff.Username}}" style="color:red;"
|
||||
{{end}}>Delete</a>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</table><hr />
|
||||
<h2>Add new staff</h2>
|
||||
<form action="{{.webroot}}manage?action=staff" onsubmit="return makeNewStaff();" method="POST">
|
||||
<form action="{{.webroot}}manage/staff" onsubmit="return makeNewStaff();" method="POST">
|
||||
<input type="hidden" name="do" value="add" />
|
||||
<table>
|
||||
<tr><td>Username:</td><td><input id="username" name="username" type="text"/></td></tr>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<h2>{{with $.edit}}Edit filter{{else}}Create new{{end}}</h2>
|
||||
<form id="wordfilterform" action="{{.webroot}}manage?action=wordfilters{{with $.edit}}&edit={{$.edit.ID}}{{end}}" method="POST">
|
||||
<form id="wordfilterform" action="{{.webroot}}manage/wordfilters{{with $.edit}}?edit={{$.edit.ID}}{{end}}" method="POST">
|
||||
<table>
|
||||
<tr><td>Search for:</td><td><input type="text" name="find" id="findfilter" value="{{with $.edit}}{{$.edit.Search}}{{end}}"/></td></tr>
|
||||
<tr><td>Replace with:</td><td><input type="text" name="replace" id="replacefilter" value="{{with $.edit}}{{$.edit.ChangeTo}}{{end}}"/></td></tr>
|
||||
|
@ -9,7 +9,7 @@
|
|||
<tr><td>
|
||||
<input type="submit" name="dowordfilter" value="{{with $.edit}}Edit{{else}}Create new{{end}} wordfilter"/>
|
||||
<input type="button" onclick="document.getElementById('wordfilterform').reset()" value="Reset"/>
|
||||
{{with $.edit}}<input type="button" onclick="window.location='{{$.webroot}}manage?action=wordfilters'" value="Cancel"/>{{end}}
|
||||
{{with $.edit}}<input type="button" onclick="window.location='{{$.webroot}}manage/wordfilters'" value="Cancel"/>{{end}}
|
||||
</td></tr>
|
||||
</table>
|
||||
</form>
|
||||
|
@ -21,7 +21,7 @@
|
|||
<tr><th>Actions</th><th>Search</th><th>Replace with</th><th>Is regex</th><th>Dirs</th><th>Created by</th><th>Staff note</th></tr>
|
||||
{{- range $f,$filter := .wordfilters}}
|
||||
<tr>
|
||||
<td><a href="{{$.webroot}}manage?action=wordfilters&edit={{$filter.ID}}">Edit</a> | <a href="{{$.webroot}}manage?action=wordfilters&delete={{$filter.ID}}" onclick="return confirm('Are you sure you want to delete this wordfilter?')">Delete</a> </td>
|
||||
<td><a href="{{$.webroot}}manage/wordfilters?edit={{$filter.ID}}">Edit</a> | <a href="{{$.webroot}}manage/wordfilters?delete={{$filter.ID}}" onclick="return confirm('Are you sure you want to delete this wordfilter?')">Delete</a> </td>
|
||||
<td>{{$filter.Search}}</td>
|
||||
<td>{{$filter.ChangeTo}}</td>
|
||||
<td>{{if $filter.IsRegex}}yes{{else}}no{{end}}</td>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue