Lindenii Project Forge
Commit info | |
---|---|
ID | b2f5ebdc623c5cf278215ef2da0ecefaba2f5d65 |
Author | Runxi Yu<me@runxiyu.org> |
Author date | Thu, 13 Feb 2025 01:52:16 +0800 |
Committer | Runxi Yu<me@runxiyu.org> |
Committer date | Thu, 13 Feb 2025 01:52:16 +0800 |
Actions | Get patch |
login: Stub login page
package main import ( "net/http" ) func handle_login(w http.ResponseWriter, r *http.Request, params map[string]any) { if r.Method != "POST" { err := templates.ExecuteTemplate(w, "login", params) if err != nil { _, _ = w.Write([]byte("Error rendering template: " + err.Error())) return } } _ = r.PostFormValue("username") _ = r.PostFormValue("password") }
package main import ( "errors" "fmt" "net/http" "strings" ) type http_router_t struct{} func (router *http_router_t) ServeHTTP(w http.ResponseWriter, r *http.Request) { segments, _, err := parse_request_uri(r.RequestURI) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } non_empty_last_segments_len := len(segments) dir_mode := false if segments[len(segments)-1] == "" { non_empty_last_segments_len-- dir_mode = true } if segments[0] == ":" { if len(segments) < 2 { http.Error(w, "Blank system endpoint", http.StatusNotFound) return } else if len(segments) == 2 && !dir_mode { http.Redirect(w, r, r.URL.Path+"/", http.StatusSeeOther) return } switch segments[1] { case "static": static_handler.ServeHTTP(w, r)
return
case "source": source_handler.ServeHTTP(w, r)
default: http.Error(w, fmt.Sprintf("Unknown system module type: %s", segments[1]), http.StatusNotFound)
return
}
return
} params := make(map[string]any) params["global"] = global_data var _user_id int _user_id, params["username"], err = get_user_info_from_request(r) if _user_id == 0 { params["user_id"] = "" } else { params["user_id"] = string(_user_id)
} if segments[0] == ":" { switch segments[1] { case "login": handle_login(w, r, params) return default: http.Error(w, fmt.Sprintf("Unknown system module type: %s", segments[1]), http.StatusNotFound) return }
} fmt.Printf("%#v\n", params) separator_index := -1 for i, part := range segments { if part == ":" { separator_index = i break } } switch { case non_empty_last_segments_len == 0: handle_index(w, r, params) case separator_index == -1: http.Error(w, "Group indexing hasn't been implemented yet", http.StatusNotImplemented) case non_empty_last_segments_len == separator_index+1: http.Error(w, "Group root hasn't been implemented yet", http.StatusNotImplemented) case non_empty_last_segments_len == separator_index+2: if !dir_mode { http.Redirect(w, r, r.URL.Path+"/", http.StatusSeeOther) return } module_type := segments[separator_index+1] params["group_name"] = segments[0] switch module_type { case "repos": handle_group_repos(w, r, params) default: http.Error(w, fmt.Sprintf("Unknown module type: %s", module_type), http.StatusNotFound) } default: module_type := segments[separator_index+1] module_name := segments[separator_index+2] params["group_name"] = segments[0] switch module_type { case "repos": params["repo_name"] = module_name // TODO: subgroups if non_empty_last_segments_len == separator_index+3 { if !dir_mode { http.Redirect(w, r, r.URL.Path+"/", http.StatusSeeOther) return } handle_repo_index(w, r, params) return } repo_feature := segments[separator_index+3] switch repo_feature { case "info": handle_repo_info(w, r, params) case "tree": params["rest"] = strings.Join(segments[separator_index+4:], "/") handle_repo_tree(w, r, params) case "raw": params["rest"] = strings.Join(segments[separator_index+4:], "/") handle_repo_raw(w, r, params) case "log": if non_empty_last_segments_len != separator_index+5 { http.Error(w, "Too many parameters", http.StatusBadRequest) return } if dir_mode { http.Redirect(w, r, strings.TrimSuffix(r.URL.Path, "/"), http.StatusSeeOther) return } params["ref"] = segments[separator_index+4] handle_repo_log(w, r, params) case "commit": if dir_mode { http.Redirect(w, r, strings.TrimSuffix(r.URL.Path, "/"), http.StatusSeeOther) return } params["commit_id"] = segments[separator_index+4] handle_repo_commit(w, r, params) default: http.Error(w, fmt.Sprintf("Unknown repo feature: %s", repo_feature), http.StatusNotFound) } default: http.Error(w, fmt.Sprintf("Unknown module type: %s", module_type), http.StatusNotFound) } } } var err_bad_request = errors.New("Bad Request")
html { font-family: sans-serif; background-color: var(--background-color); color: var(--text-color); --background-color: hsl(0, 0%, 100%); --text-color: hsl(0, 0%, 0%); --link-color: hsl(320, 50%, 36%); --light-text-color: hsl(0, 0%, 45%); --darker-border-color: hsl(0, 0%, 72%); --lighter-border-color: hsl(0, 0%, 85%); --text-decoration-color: hsl(0, 0%, 72%); --darker-box-background-color: hsl(0, 0%, 92%); --lighter-box-background-color: hsl(0, 0%, 95%);
--primary-color: hsl(320, 50%, 36%); --primary-color-contrast: hsl(320, 0%, 100%); --danger-color: hsl(0, 50%, 36%); --danger-color-contrast: hsl(0, 0%, 100%);
} @media (prefers-color-scheme: dark) { html { --background-color: hsl(0, 0%, 0%); --text-color: hsl(0, 0%, 100%); --link-color: hsl(320, 50%, 76%); --light-text-color: hsl(0, 0%, 78%); --darker-border-color: hsl(0, 0%, 35%); --lighter-border-color: hsl(0, 0%, 25%); --text-decoration-color: hsl(0, 0%, 30%); --darker-box-background-color: hsl(0, 0%, 20%); --lighter-box-background-color: hsl(0, 0%, 15%); } } html, code, pre { font-size: 1rem; /* TODO: Not always correct */ } footer { margin-top: 1rem; margin-left: auto; margin-right: auto; display: block; padding: 0 5px; width: fit-content; text-align: center; color: var(--light-text-color); } footer a:link, footer a:visited { color: inherit; } .padding-wrapper { margin: 1rem auto; max-width: 60rem; padding: 0 5px; } a:link, a:visited { text-decoration-color: var(--text-decoration-color); color: var(--link-color); } #readme code:not(pre > code) { background-color: var(--lighter-box-background-color); border-radius: 2px; padding: 2px; } table { border: var(--lighter-border-color) solid 1px; border-spacing: 0px; border-collapse: collapse; } table.wide { width: 100%; } td, th { padding: 3px 5px; border: var(--lighter-border-color) solid 1px; }
th {
th, thead, tfoot {
background-color: var(--lighter-box-background-color); } th[scope=row] { text-align: left; } tr.title-row > th { background-color: var(--darker-box-background-color); } td > pre { margin: 0; } td#readme > *:last-child { margin-bottom: 0; } td#readme > *:first-child { margin-top: 0; } .commit-id { font-family: monospace; } .scroll { overflow-x: auto; } .toggle-table-off, .toggle-table-on { display: none; } .toggle-table-off + table > thead > tr > th, .toggle-table-on + table > thead > tr > th { padding: 0; } .toggle-table-off + table > thead > tr > th > label, .toggle-table-on + table > thead > tr > th > label { width: 100%; display: inline-block; padding: 3px 0; cursor: pointer; } .toggle-table-off:checked + table > tbody { display: none; } .toggle-table-on + table > tbody { display: none; } .toggle-table-on:checked + table > tbody { display: table-row-group; } .chunk-unchanged { color: grey; } .chunk-addition { color: green; } @media (prefers-color-scheme: dark) { .chunk-addition { color: lime; } } .chunk-deletion { color: red; } .chunk-unknown { color: yellow; } pre.chunk { margin-top: 0; margin-bottom: 0; } .toggle-on-wrapper { border: var(--lighter-border-color) solid 1px; } .toggle-on-toggle { display: none; } .toggle-on-header { cursor: pointer; display: block; width: 100%; background-color: var(--lighter-box-background-color); } .toggle-on-header > span { padding: 3px 5px; display: inline-block; } .toggle-on-content { display: none; } .toggle-on-toggle:checked + .toggle-on-header + .toggle-on-content { display: block; } .file-patch + .file-patch { margin-top: 0.5rem; } .file-content { padding: 3px 5px; } .file-header { font-family: monospace; }
textarea { box-sizing: border-box; background-color: var(--lighter-box-background-color); resize: vertical; } textarea, input[type=text], input[type=password] { font-family: sans-serif; font-size: smaller; background-color: var(--lighter-box-background-color); color: var(--text-color); border: none; padding: 0.3rem; width: 100%; box-sizing: border-box; } td.tdinput, th.tdinput { padding: 0; } td.tdinput textarea, td.tdinput input[type=text], td.tdinput input[type=password], th.tdinput textarea, th.tdinput input[type=text], th.tdinput input[type=password] { background-color: transparent; } .btn-primary { background: var(--primary-color); color: var(--primary-color-contrast); border: var(--lighter-border-color) 1px solid; font-weight: bold; } .btn-danger { background: var(--danger-color); color: var(--danger-color-contrast); border: var(--lighter-border-color) 1px solid; font-weight: bold; } .btn-white { background: var(--primary-color-contrast); color: var(--primary-color); border: var(--lighter-border-color) 1px solid; } .btn-normal, input[type=file]::file-selector-button { background: var(--lighter-box-background-color); border: var(--lighter-border-color) 1px solid !important; color: var(--light-text-color); } .btn, .btn-white, .btn-danger, .btn-normal, .btn-primary, input[type=submit], input[type=file]::file-selector-button { display: inline-block; width: auto; min-width: fit-content; border-radius: 0; padding: .1rem .75rem; font-size: 0.9rem; transition: background .1s linear; cursor: pointer; } a.btn, a.btn-white, a.btn-danger, a.btn-normal, a.btn-primary { text-decoration: none; }
{{- define "login" -}} <!DOCTYPE html> <html lang="en"> <head> {{ template "head_common" . }} <title>Login – Lindenii Forge</title> </head> <body class="index"> <div class="padding-wrapper"> <form method="POST" enctype="application/x-www-form-urlencoded"> <table> <thead> <tr> <th class="title-row" colspan="2"> Password Authentication </th> </tr> </thead> <tbody> <tr> <th scope="row">Username</th> <td class="tdinput"> <input id="usernameinput" name="username" type="text" /> </td> </tr> <tr> <th scope="row">Password</th> <td class="tdinput"> <input id="passwordinput" name="password" type="password" /> </td> </tr> </tbody> <tfoot> <tr> <td class="th-like" colspan="2"> <div class="flex-justify"> <div class="left"> </div> <div class="right"> <input class="btn-primary" type="submit" value="Submit" /> </div> </div> </td> </tr> </tfoot> </table> </form> </div> <footer> {{ template "footer" . }} </footer> </body> </html> {{- end -}}