initial AText

This commit is contained in:
Azareal 2020-06-08 17:04:47 +10:00
parent 308182cdb3
commit a8702b617f
14 changed files with 92 additions and 67 deletions

View File

@ -82,6 +82,9 @@ var AllowedFileExts = StringList{
var ImageFileExts = StringList{
"png", "jpg", "jpe", "jpeg", "jif", "jfi", "jfif", "svg", "bmp", "gif", "tiff", "tif", "webp", /* "apng", "bpg", */
}
var TextFileExts = StringList{
"txt", "xml", "json", "yaml", "toml", "ini", "md", "html", "rtf", "js", "py", "rb", "css", "scss", "less", "eqcss", "pcss", "java", "ts", "cs", "c", "cc", "cpp", "cxx", "C", "c++", "h", "hh", "hpp", "hxx", "h++", "rs", "rlib", "htaccess", "gitignore", /*"go","php",*/
}
var VideoFileExts = StringList{
"mp4", "avi", "ogg", "ogv", "ogx", "wmv", "webm",
}

View File

@ -44,6 +44,9 @@ var attachOpen = []byte("<a class='attach'href=\"")
var attachClose = []byte("\"download>Attachment</a>")
var sidParam = []byte("?sid=")
var stypeParam = []byte("&amp;stype=")
var textOpen = []byte("<a class='attach'href=\"")
var textOpen2 = []byte("\">View</a> / <a class='attach'href=\"")
var textClose = []byte("\"download>Download</a>")
var urlPattern = `(?s)([ {1}])((http|https|ftp|mailto)*)(:{??)\/\/([\.a-zA-Z\/]+)([ {1}])`
var urlReg *regexp.Regexp
@ -713,6 +716,24 @@ func ParseMessage(msg string, sectionID int, sectionType string, settings *Parse
case EImage:
addImage(media.URL)
continue
case AText:
sb.Write(textOpen)
sb.WriteString(media.URL)
sb.Write(sidParam)
sid := strconv.Itoa(sectionID)
sb.WriteString(sid)
sb.Write(stypeParam)
sb.WriteString(sectionType)
sb.Write(textOpen2)
sb.WriteString(media.URL)
sb.Write(sidParam)
sb.WriteString(sid)
sb.Write(stypeParam)
sb.WriteString(sectionType)
sb.Write(textClose)
i += urlLen
lastItem = i
continue
case AOther:
sb.Write(attachOpen)
sb.WriteString(media.URL)
@ -951,6 +972,7 @@ const (
AImage
AVideo
AAudio
AText
AOther
)
@ -1011,6 +1033,8 @@ func parseMediaString(data string, settings *ParseSettings) (media MediaEmbed, o
media.Type = AVideo
case WebAudioFileExts.Contains(ext):
media.Type = AAudio
case TextFileExts.Contains(ext):
media.Type = AText
default:
media.Type = AOther
}

View File

@ -7,11 +7,11 @@ import (
"github.com/Azareal/Gosora/common/phrases"
)
func IPSearch(w http.ResponseWriter, r *http.Request, user *c.User, h *c.Header) c.RouteError {
func IPSearch(w http.ResponseWriter, r *http.Request, u *c.User, h *c.Header) c.RouteError {
h.Title = phrases.GetTitlePhrase("ip_search")
// TODO: How should we handle the permissions if we extend this into an alt detector of sorts?
if !user.Perms.ViewIPs {
return c.NoPermissions(w, r, user)
if !u.Perms.ViewIPs {
return c.NoPermissions(w, r, u)
}
// TODO: Reject IP Addresses with illegal characters

View File

@ -10,13 +10,13 @@ import (
c "github.com/Azareal/Gosora/common"
)
func WordFilters(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError {
basePage, ferr := buildBasePage(w, r, user, "word_filters", "word-filters")
func WordFilters(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
basePage, ferr := buildBasePage(w, r, u, "word_filters", "word-filters")
if ferr != nil {
return ferr
}
if !user.Perms.EditSettings {
return c.NoPermissions(w, r, user)
if !u.Perms.EditSettings {
return c.NoPermissions(w, r, u)
}
// TODO: What if this list gets too long?
@ -29,20 +29,20 @@ func WordFilters(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteEr
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_word_filters", &pi})
}
func WordFiltersCreateSubmit(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError {
_, ferr := c.SimplePanelUserCheck(w, r, user)
func WordFiltersCreateSubmit(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
_, ferr := c.SimplePanelUserCheck(w, r, u)
if ferr != nil {
return ferr
}
if !user.Perms.EditSettings {
return c.NoPermissions(w, r, user)
if !u.Perms.EditSettings {
return c.NoPermissions(w, r, u)
}
js := r.PostFormValue("js") == "1"
// ? - We're not doing a full sanitise here, as it would be useful if admins were able to put down rules for replacing things with HTML, etc.
find := strings.TrimSpace(r.PostFormValue("find"))
if find == "" {
return c.LocalErrorJSQ("You need to specify what word you want to match", w, r, user, js)
return c.LocalErrorJSQ("You need to specify what word you want to match", w, r, u, js)
}
// Unlike with find, it's okay if we leave this blank, as this means that the admin wants to remove the word entirely with no replacement
@ -52,7 +52,7 @@ func WordFiltersCreateSubmit(w http.ResponseWriter, r *http.Request, user *c.Use
if err != nil {
return c.InternalErrorJSQ(err, w, r, js)
}
err = c.AdminLogs.Create("create", wfid, "word_filter", user.GetIP(), user.ID)
err = c.AdminLogs.Create("create", wfid, "word_filter", u.GetIP(), u.ID)
if err != nil {
return c.InternalError(err, w, r)
}
@ -61,13 +61,13 @@ func WordFiltersCreateSubmit(w http.ResponseWriter, r *http.Request, user *c.Use
}
// TODO: Implement this as a non-JS fallback
func WordFiltersEdit(w http.ResponseWriter, r *http.Request, user *c.User, wfid string) c.RouteError {
basePage, ferr := buildBasePage(w, r, user, "edit_word_filter", "word-filters")
func WordFiltersEdit(w http.ResponseWriter, r *http.Request, u *c.User, wfid string) c.RouteError {
basePage, ferr := buildBasePage(w, r, u, "edit_word_filter", "word-filters")
if ferr != nil {
return ferr
}
if !user.Perms.EditSettings {
return c.NoPermissions(w, r, user)
if !u.Perms.EditSettings {
return c.NoPermissions(w, r, u)
}
_ = wfid
@ -75,30 +75,30 @@ func WordFiltersEdit(w http.ResponseWriter, r *http.Request, user *c.User, wfid
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_word_filters_edit", &pi})
}
func WordFiltersEditSubmit(w http.ResponseWriter, r *http.Request, user *c.User, swfid string) c.RouteError {
_, ferr := c.SimplePanelUserCheck(w, r, user)
func WordFiltersEditSubmit(w http.ResponseWriter, r *http.Request, u *c.User, swfid string) c.RouteError {
_, ferr := c.SimplePanelUserCheck(w, r, u)
if ferr != nil {
return ferr
}
js := r.PostFormValue("js") == "1"
if !user.Perms.EditSettings {
return c.NoPermissionsJSQ(w, r, user, js)
if !u.Perms.EditSettings {
return c.NoPermissionsJSQ(w, r, u, js)
}
wfid, err := strconv.Atoi(swfid)
if err != nil {
return c.LocalErrorJSQ("The word filter ID must be an integer.", w, r, user, js)
return c.LocalErrorJSQ("The word filter ID must be an integer.", w, r, u, js)
}
find := strings.TrimSpace(r.PostFormValue("find"))
if find == "" {
return c.LocalErrorJSQ("You need to specify what word you want to match", w, r, user, js)
return c.LocalErrorJSQ("You need to specify what word you want to match", w, r, u, js)
}
// Unlike with find, it's okay if we leave this blank, as this means that the admin wants to remove the word entirely with no replacement
replace := strings.TrimSpace(r.PostFormValue("replace"))
wf, err := c.WordFilters.Get(wfid)
if err == sql.ErrNoRows {
return c.LocalErrorJSQ("This word filter doesn't exist.", w, r, user, js)
return c.LocalErrorJSQ("This word filter doesn't exist.", w, r, u, js)
} else if err != nil {
return c.InternalErrorJSQ(err, w, r, js)
}
@ -111,7 +111,7 @@ func WordFiltersEditSubmit(w http.ResponseWriter, r *http.Request, user *c.User,
if err != nil {
return c.InternalErrorJSQ(err, w, r, js)
}
err = c.AdminLogs.CreateExtra("edit", wfid, "word_filter", user.GetIP(), user.ID, string(lBytes))
err = c.AdminLogs.CreateExtra("edit", wfid, "word_filter", u.GetIP(), u.ID, string(lBytes))
if err != nil {
return c.InternalErrorJSQ(err, w, r, js)
}
@ -120,25 +120,25 @@ func WordFiltersEditSubmit(w http.ResponseWriter, r *http.Request, user *c.User,
return nil
}
func WordFiltersDeleteSubmit(w http.ResponseWriter, r *http.Request, user *c.User, swfid string) c.RouteError {
_, ferr := c.SimplePanelUserCheck(w, r, user)
func WordFiltersDeleteSubmit(w http.ResponseWriter, r *http.Request, u *c.User, swfid string) c.RouteError {
_, ferr := c.SimplePanelUserCheck(w, r, u)
if ferr != nil {
return ferr
}
js := r.PostFormValue("js") == "1"
if !user.Perms.EditSettings {
return c.NoPermissionsJSQ(w, r, user, js)
if !u.Perms.EditSettings {
return c.NoPermissionsJSQ(w, r, u, js)
}
wfid, err := strconv.Atoi(swfid)
if err != nil {
return c.LocalErrorJSQ("The word filter ID must be an integer.", w, r, user, js)
return c.LocalErrorJSQ("The word filter ID must be an integer.", w, r, u, js)
}
err = c.WordFilters.Delete(wfid)
if err == sql.ErrNoRows {
return c.LocalErrorJSQ("This word filter doesn't exist", w, r, user, js)
return c.LocalErrorJSQ("This word filter doesn't exist", w, r, u, js)
}
err = c.AdminLogs.Create("delete", wfid, "word_filter", user.GetIP(), user.ID)
err = c.AdminLogs.Create("delete", wfid, "word_filter", u.GetIP(), u.ID)
if err != nil {
return c.InternalError(err, w, r)
}

View File

@ -5,11 +5,11 @@
<h1>{{lang "ip_search_head"}}</h1>
</div>
</div>
<form action="/users/ips/" method="get" id="ip-search-form"></form>
<form action="/users/ips/"method="get"id="ip-search-form"></form>
<div class="rowblock ip_search_block">
<div class="rowitem passive">
<input form="ip-search-form" name="ip" class="ip_search_input" type="search" placeholder="🔍︎"{{if .IP}} value="{{.IP}}"{{end}}>
<input form="ip-search-form" class="ip_search_search" type="submit" value="{{lang "ip_search_search_button"}}">
<input form="ip-search-form"name="ip"class="ip_search_input"type="search"placeholder="🔍︎"{{if .IP}}value="{{.IP}}"{{end}}>
<input form="ip-search-form"class="ip_search_search"type="submit"value="{{lang "ip_search_search_button"}}">
</div>
</div>
{{if .IP}}<div class="rowblock rowlist bgavatars micro_grid{{if .ItemList}} has_items{{end}}">

View File

@ -7,7 +7,7 @@
<div class="rowblock">
<div class="rowitem passive rowmsg level_{{.Status}}">
<div class="levelBit">{{level .Level}}</div>
<div class="progressWrap"{{if eq .Status "inprogress"}} style="width:{{.Percentage}}%;"{{end}}>
<div class="progressWrap"{{if eq .Status "inprogress"}}style="width:{{.Percentage}}%;"{{end}}>
<div>Score: {{.Score}}</div>
</div>
</div>

View File

@ -4,16 +4,16 @@
<div class="rowitem"><h1>{{lang "login_mfa_verify_head"}}</h1></div>
</div>
<div class="rowblock the_form">
<form action="/accounts/mfa_verify/submit/" method="post">
<form action="/accounts/mfa_verify/submit/"method="post">
<div class="formrow real_first_child">
<div class="formitem formlabel"><a>{{lang "login_mfa_verify_explanation"}}</a></div>
</div>
<div class="formrow login_mfa_token_row">
<div class="formitem formlabel"><a id="login_mfa_verify_label">{{lang "login_mfa_token"}}</a></div>
<div class="formitem"><input name="mfa_token" type="text" autocomplete="off" placeholder="*****" aria-labelledby="login_mfa_verify_label" required></div>
<div class="formitem"><input name="mfa_token"type="text"autocomplete="off"placeholder="*****"aria-labelledby="login_mfa_verify_label"required></div>
</div>
<div class="formrow login_button_row form_button_row">
<div class="formitem"><button name="login-button" class="formbutton">{{lang "login_mfa_verify_button"}}</button></div>
<div class="formitem"><button name="login-button"class="formbutton">{{lang "login_mfa_verify_button"}}</button></div>
</div>
</form>
</div>

View File

@ -1,5 +1,3 @@
{{template "header.html" . }}
<main>
</main>
<main></main>
{{template "footer.html" . }}

View File

@ -3,14 +3,14 @@
</div>{{flush}}
<div class="colstack_grid panel_dashboard grid1">
{{range .Grid1}}
<div id="{{.ID}}" class="grid_item {{.Class}}" title="{{.Note}}" style="{{if .TextColour}}color:{{.TextColour}};{{end}}{{if .Background}}background-color:{{.Background}};{{end}}">
<div id="{{.ID}}"class="grid_item {{.Class}}"title="{{.Note}}"style="{{if .TextColour}}color:{{.TextColour}};{{end}}{{if .Background}}background-color:{{.Background}};{{end}}">
{{if .Href}}<a href="{{.Href}}">{{.Body}}</a>{{else}}<span>{{.Body}}</span>{{end}}
</div>
{{end}}
</div>{{flush}}
<div class="colstack_grid panel_dashboard grid2">
{{range .Grid2}}
<div id="{{.ID}}" class="grid_item {{.Class}}" title="{{.Note}}" style="{{if .TextColour}}color:{{.TextColour}};{{end}}{{if .Background}}background-color:{{.Background}};{{end}}">
<div id="{{.ID}}"class="grid_item {{.Class}}"title="{{.Note}}"style="{{if .TextColour}}color:{{.TextColour}};{{end}}{{if .Background}}background-color:{{.Background}};{{end}}">
{{if .Href}}<a href="{{.Href}}">{{.Body}}</a>{{else}}<span>{{.Body}}</span>{{end}}
</div>
{{end}}

View File

@ -1,7 +1,7 @@
<div class="colstack_item colstack_head">
<div class="rowitem"><h1>{{lang "panel_debug_head"}}</h1></div>
</div>{{flush}}
<div id="panel_debug" class="colstack_grid">
<div id="panel_debug"class="colstack_grid">
{{template "panel_debug_stat_head.html" "panel_debug_uptime_label"}}
{{template "panel_debug_stat_head.html" "panel_debug_go_version_label"}}
{{template "panel_debug_stat_head.html" "panel_debug_database_version_label"}}
@ -25,7 +25,7 @@
{{template "panel_debug_stat_q.html"}}
</div>
{{template "panel_debug_subhead.html" "panel_debug_tasks"}}
<div id="panel_debug" class="colstack_grid">
<div id="panel_debug"class="colstack_grid">
{{template "panel_debug_stat_head.html" "panel_debug_tasks_half_second"}}
{{template "panel_debug_stat_head.html" "panel_debug_tasks_second"}}
{{template "panel_debug_stat_head.html" "panel_debug_tasks_fifteen_minute"}}
@ -41,7 +41,7 @@
{{template "panel_debug_stat_q.html"}}
</div>
{{template "panel_debug_subhead.html" "panel_debug_memory_stats"}}
<div id="panel_debug" class="colstack_grid">
<div id="panel_debug"class="colstack_grid">
{{template "panel_debug_stat_head.html" "panel_debug_memory_stats_sys"}}
{{template "panel_debug_stat_head.html" "panel_debug_memory_stats_heapsys"}}
{{template "panel_debug_stat_head.html" "panel_debug_memory_stats_heapalloc"}}
@ -71,7 +71,7 @@
<div class="grid_item grid_stat"><span>{{.MemStats.OtherSys}} ({{bunit .MemStats.OtherSys}})</span></div>
</div>
{{template "panel_debug_subhead.html" "panel_debug_caches"}}
<div id="panel_debug" class="colstack_grid">
<div id="panel_debug"class="colstack_grid">
{{template "panel_debug_stat_head.html" "panel_debug_caches_topic"}}
{{template "panel_debug_stat_head.html" "panel_debug_caches_user"}}
{{template "panel_debug_stat_head.html" "panel_debug_caches_reply"}}
@ -87,7 +87,7 @@
{{template "panel_debug_stat_q.html"}}
</div>
{{template "panel_debug_subhead.html" "panel_debug_database"}}
<div id="panel_debug" class="colstack_grid">
<div id="panel_debug"class="colstack_grid">
{{template "panel_debug_stat_head.html" "panel_debug_database_topics"}}
{{template "panel_debug_stat_head.html" "panel_debug_database_users"}}
{{template "panel_debug_stat_head.html" "panel_debug_database_replies"}}
@ -145,7 +145,7 @@
{{template "panel_debug_stat_q.html"}}
</div>
{{template "panel_debug_subhead.html" "panel_debug_disk"}}
<div id="panel_debug" class="colstack_grid">
<div id="panel_debug"class="colstack_grid">
{{template "panel_debug_stat_head.html" "panel_debug_disk_static_files"}}
{{template "panel_debug_stat_head.html" "panel_debug_disk_attachments"}}
{{template "panel_debug_stat_head.html" "panel_debug_disk_avatars"}}

View File

@ -1,8 +1,8 @@
<div class="colstack_item colstack_head">
<div class="rowitem"><h1>{{.Setting.FriendlyName}}</h1></div>
</div>
<div id="panel_setting" class="colstack_item the_form">
<form action="/panel/settings/edit/submit/{{.Setting.Name}}?s={{.CurrentUser.Session}}" method="post">
<div id="panel_setting"class="colstack_item the_form">
<form action="/panel/settings/edit/submit/{{.Setting.Name}}?s={{.CurrentUser.Session}}"method="post">
{{if eq .Setting.Type "list"}}
<div class="formrow">
<div class="formitem formlabel"><a>{{lang "panel_setting_value"}}</a></div>
@ -31,7 +31,7 @@
<div class="formitem"><input name="value"type="text"value="{{.Setting.Content}}"></div>
</div>{{end}}
<div class="formrow form_button_row">
<div class="formitem"><button name="panel-button" class="formbutton">{{lang "panel_setting_update_button"}}</button></div>
<div class="formitem"><button name="panel-button"class="formbutton">{{lang "panel_setting_update_button"}}</button></div>
</div>
</form>
</div>

View File

@ -1,10 +1,10 @@
<div class="colstack_item colstack_head">
<div class="rowitem"><h1>{{lang "panel_settings_head"}}</h1></div>
</div>
<div id="panel_settings" class="colstack_item rowlist bgavatars micro_grid">
<div id="panel_settings"class="colstack_item rowlist bgavatars micro_grid">
{{range .Something}}
<div class="rowitem panel_compactrow editable_parent">
<a href="/panel/settings/edit/{{.Name}}" class="editable_block panel_upshift" title="{{.FriendlyName}}">{{.FriendlyName}}</a>
<a href="/panel/settings/edit/{{.Name}}"class="editable_block panel_upshift"title="{{.FriendlyName}}">{{.FriendlyName}}</a>
<a class="panel_compacttext to_right">{{.Content}}</a>
</div>
{{end}}

View File

@ -1,10 +1,10 @@
<div class="colstack_item colstack_head">
<div class="rowitem"><h1>{{lang "panel_themes_menus_head"}}</h1></div>
</div>
<div id="panel_menus" class="colstack_item rowlist">
<div id="panel_menus"class="colstack_item rowlist">
{{range .ItemList}}
<div class="rowitem panel_compactrow editable_parent">
<a href="/panel/themes/menus/edit/{{.ID}}" class="editable_block panel_upshift">{{if .Name}}{{.Name}} - {{end}}#{{.ID}}</a>
<a href="/panel/themes/menus/edit/{{.ID}}"class="editable_block panel_upshift">{{if .Name}}{{.Name}} - {{end}}#{{.ID}}</a>
<a class="panel_compacttext to_right">{{.ItemCount}}{{lang "panel_themes_menus_items_suffix"}}</a>
</div>
{{end}}

View File

@ -1,25 +1,25 @@
<input form="quick_post_form" id="has_poll_input" name="has_poll" value=0 type="hidden">
<input form="quick_post_form"id="has_poll_input"name="has_poll"value=0 type="hidden">
<div class="formrow topic_content_row">
<div class="formitem">
<textarea form="quick_post_form" id="input_content" name="content" placeholder="{{lang "quick_topic.content_placeholder"}}" required></textarea>
<textarea form="quick_post_form"id="input_content"name="content"placeholder="{{lang "quick_topic.content_placeholder"}}"required></textarea>
</div>
</div>
<div class="formrow poll_content_row auto_hide">
<div class="formitem">
<div class="pollinput" data-pollinput=0>
<input type="checkbox" disabled>
<div class="pollinput"data-pollinput=0>
<input type="checkbox"disabled>
<label class="pollinputlabel"></label>
<input form="quick_post_form" name="pollinputitem[0]" class="pollinputinput" type="text" placeholder="{{lang "quick_topic.add_poll_option_first"}}">
<input form="quick_post_form"name="pollinputitem[0]"class="pollinputinput"type="text"placeholder="{{lang "quick_topic.add_poll_option_first"}}">
</div>
</div>
</div>
<div class="formrow quick_button_row">
<div class="formitem">
<button form="quick_post_form" class="formbutton">{{lang "quick_topic.create_button"}}</button>
<button form="quick_post_form" class="formbutton" id="add_poll_button">{{lang "quick_topic.add_poll_button"}}</button>
<button form="quick_post_form"class="formbutton">{{lang "quick_topic.create_button"}}</button>
<button form="quick_post_form"class="formbutton"id="add_poll_button">{{lang "quick_topic.add_poll_button"}}</button>
{{if .CurrentUser.Perms.UploadFiles}}
<input name="upload_files"form="quick_post_form" id="upload_files" multiple type="file" class="auto_hide">
<label for="upload_files" class="formbutton add_file_button">{{lang "quick_topic.add_file_button"}}</label>
<input name="upload_files"form="quick_post_form"id="upload_files"multiple type="file"class="auto_hide">
<label for="upload_files"class="formbutton add_file_button">{{lang "quick_topic.add_file_button"}}</label>
<div id="upload_file_dock"></div>{{end}}
<button class="formbutton close_form">{{lang "quick_topic.cancel_button"}}</button>
</div>