dkforest

A forum and chat platform (onion)
git clone https://git.dasho.dev/n0tr1v/dkforest.git
Log | Files | Refs | LICENSE

commit 273d9e84f2c1722994fc843caca44f0bf215af43
parent 0b74330697d0cf8256da5ff4a50a4e2753a0b218
Author: n0tr1v <n0tr1v@protonmail.com>
Date:   Sun, 21 May 2023 22:16:42 -0700

chat stream experiment

Diffstat:
Mpkg/database/tableChatMessages.go | 4++++
Mpkg/web/handlers/api/v1/data.go | 6++----
Mpkg/web/handlers/api/v1/handlers.go | 4+---
Mpkg/web/handlers/api/v1/messages.qtpl | 471+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Mpkg/web/handlers/api/v1/messages.qtpl.go | 1706++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Mpkg/web/handlers/handlers.go | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpkg/web/middlewares/middlewares.go | 1+
Mpkg/web/web.go | 1+
8 files changed, 1277 insertions(+), 1035 deletions(-)

diff --git a/pkg/database/tableChatMessages.go b/pkg/database/tableChatMessages.go @@ -4,6 +4,7 @@ import ( "crypto/cipher" "crypto/rand" "dkforest/pkg/config" + "dkforest/pkg/pubsub" "dkforest/pkg/utils" "encoding/json" "errors" @@ -528,9 +529,12 @@ func (d *DkfDB) CreateOrEditMessage( } } editMsg.DoSave(d) + MsgPubSub.Pub("room_"+utils.FormatInt64(int64(roomID)), editMsg) return editMsg.ID, nil } +var MsgPubSub = pubsub.NewPubSub[*ChatMessage]() + func encryptMessages(html, origMessage, roomKey string) (string, string, error) { var err error // Encrypt html message (for displaying) diff --git a/pkg/web/handlers/api/v1/data.go b/pkg/web/handlers/api/v1/data.go @@ -18,8 +18,7 @@ type chatTopBarData struct { CommandsList []string } -type chatMessagesData struct { - IsModerator bool +type ChatMessagesData struct { NbButtons int64 Messages []database.ChatMessage Members []managers.UserInfo @@ -27,7 +26,6 @@ type chatMessagesData struct { VisibleMemberInChat bool // either or not at least 1 user is "visibile" (not hellbanned) PreventRefresh bool TopBarQueryParams string - DateFormat string RoomName string InboxCount int64 ManualRefreshTimeout int64 @@ -42,7 +40,7 @@ type chatMessagesData struct { ErrorTs int64 } -func (c chatMessagesData) MarshalJSON() ([]byte, error) { +func (c ChatMessagesData) MarshalJSON() ([]byte, error) { return json.Marshal(&struct { Members []managers.UserInfo Messages []database.ChatMessage diff --git a/pkg/web/handlers/api/v1/handlers.go b/pkg/web/handlers/api/v1/handlers.go @@ -86,7 +86,7 @@ var memeRenameRgx = regexp.MustCompile(`^/meme ([a-zA-Z0-9_-]{3,50}) ([a-zA-Z0-9 var memeRemoveRgx = regexp.MustCompile(`^/memerm ([a-zA-Z0-9_-]{3,50})$`) var memesRgx = regexp.MustCompile(`^/memes$`) -func chatMessages(c echo.Context) (status int, data chatMessagesData) { +func chatMessages(c echo.Context) (status int, data ChatMessagesData) { authCookie, _ := c.Cookie(hutils.AuthCookieName) authUser := c.Get("authUser").(*database.User) db := c.Get("database").(*database.DkfDB) @@ -149,8 +149,6 @@ func chatMessages(c echo.Context) (status int, data chatMessagesData) { } data.ManualRefreshTimeout = authUser.RefreshRate + 25 - data.DateFormat = authUser.GetDateFormat() - data.IsModerator = authUser.IsModerator() data.Messages = msgs data.Members = membersInRoom data.MembersInChat = membersInChat diff --git a/pkg/web/handlers/api/v1/messages.qtpl b/pkg/web/handlers/api/v1/messages.qtpl @@ -2,7 +2,123 @@ {% import "dkforest/pkg/managers" %} {% import humanize "github.com/dustin/go-humanize" %} -{% func Messages(VERSION, CSRF, NullUsername string, AuthUser *database.User, Data chatMessagesData) -%} +{%- func GenerateStyle(AuthUser *database.User, Data ChatMessagesData) -%} +<style> + i { font-style: italic; } + + /* Remove button padding in FF */ + button::-moz-focus-inner { + border:0; + padding:0; + } + + body { font-family: Lato,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"; } + a { color: #00bc8c; text-decoration: none; } + a:hover { color: #007053; text-decoration: underline; } + .unread_room { color: #2392da; text-decoration: none; } + .unread_room:hover { color: #004970; text-decoration: underline; } + .emoji { + font-family: "Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji", Times, Symbola, Aegyptus, Code2000, Code2001, Code2002, Musica, serif, LastResort; + font-size: 17px; + } + .mod-btn { + width: 16px; height: 16px; + margin: 0; padding: 0; + border: 1px solid gray; + display: inline; + text-align: center; + vertical-align: middle; + user-select: none; + background-color: #444; + color: #ea2a2a; + -webkit-box-shadow: 1px 1px 1px rgba(0,0,0,0.25); + -moz-box-shadow: 1px 1px 1px rgba(0,0,0,0.25); + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + } + .mod-btn:hover { + background-color: #222; + } + .delete_msg_btn { + font-size: 15px; + line-height: 1; + } + .delete_msg_btn::after { content: "×"; } + .hb_btn { + font-size: 10px; + line-height: 1.4; + } + .hb_btn::after { content: "hb"; } + .k_btn { + font-size: 10px; + line-height: 1.4; + } + .k_btn::after { content: "k"; } + #manualrefresh { + {% if !Data.ForceManualRefresh %} + top: -200%; + animation: timeout_messages {%dl Data.ManualRefreshTimeout %}s forwards; + {% endif %} + color: #bf2718; + display: block; + position: fixed; + text-align: center; + left: calc(50% - 200px); + width: 400px; + z-index: 2; + background-color: #500000; + border: 2px solid #ff0000; + } + @keyframes timeout_messages { + 0% { top: -200%; } + 99% { top: -200%; } + 100% { top: 0; } + } + .date { color: #999; font-family: 'Courier New', Courier, monospace; font-size: 14px; } + .date-link:hover { color: #999; text-decoration: underline; } + .sysmsg { color: #fff; font-family: 'Courier New', Courier, monospace; font-size: 14px; } + small { font-size: 80%; font-weight: 400; } + .msg { padding: 3px 0 3px 8px; border-bottom: 1px solid #444; color: #888; position: relative; } + .msg p:first-of-type { display: inline; } + strong { font-weight: bold; } + em { font-style: italic; } + pre { border: 1px solid #2b442b; padding: 2px; margin: 2px 0; max-height: 300px; overflow: auto; background-color: rgba(39,40,34,0.6) !important; + font-family: SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace; } + code { border: 1px solid #2b442b; color: #f92672; padding: 0 2px; margin: 0px 0; background-color: rgba(39,40,34,0.6) !important; } + .censored { background-color: black; color: black; padding: 0 3px; } + .censored:hover { background-color: black; color: white; } + ul { list-style-type: disc; margin: 0 0 0 15px; } + * { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } + .afk-indicator { color: #ff9a27; } + .spacer16 { display: inline-block; width: 16px; } + .spacer36 { display: inline-block; width: 36px; } + .spacer56 { display: inline-block; width: 56px; } + .d-inline { display: inline; } + .o-wrap { overflow-wrap: break-word; } + .f-def-clr { color: #888; } + .f-orange-clr { color: orange; } + .f-white-clr, .f-white-clr:hover { color: white; } + .line-through { text-decoration: line-through; } + .hb-row { background-color: rgba(0, 0, 0, 0.7); opacity: {%f AuthUser.GetHellbanOpacityF64() %}; } + .own-highlight { background-color: rgba(255,241,176,0.05); } + .read-marker { border-top: {%dl AuthUser.ChatReadMarkerSize %}px solid {%s AuthUser.ChatReadMarkerColor %}; } + #msgs { {% if !AuthUser.HideRightColumn %}width: calc(100% - 170px); float: left; {% endif %}line-height: 1.2; } + #no-msg { padding-left: 10px; color: #ddd; } + #rgt-pane { width: 150px; height: 100%; float: left; margin-left: 20px; position: fixed; right: 0; overflow-y: auto; line-height: 1.15; } + .rgt-title { font-weight: bolder; color: #ced4da; } + .mb-20px { margin-bottom: 20px; } + .mb-30px { margin-bottom: 30px; } + .mt-5px { margin-top: 5px; } + .mt-10px { margin-top: 10px; } + .notif, .notif:hover { color: #e74c3c; } + #msg-err { background-color: #8f2d2d; color: #ffffff; padding: 1px 5px 2px 5px; display: block; text-decoration: none; } +</style> +{%- endfunc -%} + +{% func Messages(VERSION, CSRF, NullUsername string, AuthUser *database.User, Data ChatMessagesData) -%} <html lang="en"> <head> <title></title> @@ -58,120 +174,8 @@ border-spacing: 0; } /* --- end --- */ - - - i { font-style: italic; } - - /* Remove button padding in FF */ - button::-moz-focus-inner { - border:0; - padding:0; - } - - body { font-family: Lato,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"; } - a { color: #00bc8c; text-decoration: none; } - a:hover { color: #007053; text-decoration: underline; } - .unread_room { color: #2392da; text-decoration: none; } - .unread_room:hover { color: #004970; text-decoration: underline; } - .emoji { - font-family: "Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji", Times, Symbola, Aegyptus, Code2000, Code2001, Code2002, Musica, serif, LastResort; - font-size: 17px; - } - .mod-btn { - width: 16px; height: 16px; - margin: 0; padding: 0; - border: 1px solid gray; - display: inline; - text-align: center; - vertical-align: middle; - user-select: none; - background-color: #444; - color: #ea2a2a; - -webkit-box-shadow: 1px 1px 1px rgba(0,0,0,0.25); - -moz-box-shadow: 1px 1px 1px rgba(0,0,0,0.25); - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - } - .mod-btn:hover { - background-color: #222; - } - .delete_msg_btn { - font-size: 15px; - line-height: 1; - } - .delete_msg_btn::after { content: "×"; } - .hb_btn { - font-size: 10px; - line-height: 1.4; - } - .hb_btn::after { content: "hb"; } - .k_btn { - font-size: 10px; - line-height: 1.4; - } - .k_btn::after { content: "k"; } - #manualrefresh { - {% if !Data.ForceManualRefresh %} - top: -200%; - animation: timeout_messages {%dl Data.ManualRefreshTimeout %}s forwards; - {% endif %} - color: #bf2718; - display: block; - position: fixed; - text-align: center; - left: calc(50% - 200px); - width: 400px; - z-index: 2; - background-color: #500000; - border: 2px solid #ff0000; - } - @keyframes timeout_messages { - 0% { top: -200%; } - 99% { top: -200%; } - 100% { top: 0; } - } - .date { color: #999; font-family: 'Courier New', Courier, monospace; font-size: 14px; } - .date-link:hover { color: #999; text-decoration: underline; } - .sysmsg { color: #fff; font-family: 'Courier New', Courier, monospace; font-size: 14px; } - small { font-size: 80%; font-weight: 400; } - .msg { padding: 3px 0 3px 8px; border-bottom: 1px solid #444; color: #888; position: relative; } - .msg p:first-of-type { display: inline; } - strong { font-weight: bold; } - em { font-style: italic; } - pre { border: 1px solid #2b442b; padding: 2px; margin: 2px 0; max-height: 300px; overflow: auto; background-color: rgba(39,40,34,0.6) !important; - font-family: SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace; } - code { border: 1px solid #2b442b; color: #f92672; padding: 0 2px; margin: 0px 0; background-color: rgba(39,40,34,0.6) !important; } - .censored { background-color: black; color: black; padding: 0 3px; } - .censored:hover { background-color: black; color: white; } - ul { list-style-type: disc; margin: 0 0 0 15px; } - * { - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - } - .afk-indicator { color: #ff9a27; } - .spacer16 { display: inline-block; width: 16px; } - .spacer36 { display: inline-block; width: 36px; } - .spacer56 { display: inline-block; width: 56px; } - .d-inline { display: inline; } - .o-wrap { overflow-wrap: break-word; } - .f-def-clr { color: #888; } - .f-orange-clr { color: orange; } - .f-white-clr, .f-white-clr:hover { color: white; } - .line-through { text-decoration: line-through; } - .hb-row { background-color: rgba(0, 0, 0, 0.7); opacity: {%f AuthUser.GetHellbanOpacityF64() %}; } - .own-highlight { background-color: rgba(255,241,176,0.05); } - .read-marker { border-top: {%dl AuthUser.ChatReadMarkerSize %}px solid {%s AuthUser.ChatReadMarkerColor %}; } - #msgs { {% if !AuthUser.HideRightColumn %}width: calc(100% - 170px); float: left; {% endif %}line-height: 1.2; } - #no-msg { padding-left: 10px; color: #ddd; } - #rgt-pane { width: 150px; height: 100%; float: left; margin-left: 20px; position: fixed; right: 0; overflow-y: auto; line-height: 1.15; } - .rgt-title { font-weight: bolder; color: #ced4da; } - .mb-20px { margin-bottom: 20px; } - .mb-30px { margin-bottom: 30px; } - .mt-5px { margin-top: 5px; } - .mt-10px { margin-top: 10px; } - .notif, .notif:hover { color: #e74c3c; } - #msg-err { background-color: #8f2d2d; color: #ffffff; padding: 1px 5px 2px 5px; display: block; text-decoration: none; } </style> + {%-= GenerateStyle(AuthUser, Data) -%} </head> <body> @@ -202,119 +206,7 @@ {%- endif -%} <div id="msgs"> - {%- code - baseTopBarURL := "/api/v1/chat/top-bar/" + Data.RoomName - readMarkerRendered := false - isFirstMsg := true - -%} - {%- for idx, e := range Data.Messages -%} - {%- if e.UserCanSee(*AuthUser) -%} - <div id="msgid-{%s e.UUID %}" class="msg - {%- if (e.User.IsHellbanned || e.IsHellbanned) && AuthUser.DisplayHellbanned %} hb-row - {%- elseif AuthUser.ID == e.User.ID && AuthUser.HighlightOwnMessages %} own-highlight{%- endif -%} - {%- if AuthUser.ChatReadMarkerEnabled && e.CreatedAt.Before(Data.ReadMarker.ReadAt) && !readMarkerRendered %} - {%- if idx > 0 -%} read-marker{%- endif -%} - {%- code readMarkerRendered = true -%} - {%- endif -%} - "> - {%- if e.UserCanDelete(*AuthUser) -%} - {%- if !e.TooOldToDelete() -%} - {%- if AuthUser.DisplayDeleteButton -%} - <form method="post" action="/api/v1/chat/messages/delete/{%s e.UUID %}" class="d-inline"> - <input type="hidden" name="csrf" value="{%s CSRF %}" /> - <button class="mod-btn delete_msg_btn" title="delete"></button> - </form> - {%- endif -%} - {%- elseif (AuthUser.IsModerator() && e.TooOldToDelete() && e.UserID != AuthUser.ID) || AuthUser.IsAdmin || (e.Room.OwnerUserID != nil && *e.Room.OwnerUserID == AuthUser.ID) -%} - {%- if AuthUser.DisplayDeleteButton -%} - <form method="post" action="/api/v1/chat/messages/delete/{%s e.UUID %}" class="d-inline"> - <input type="hidden" name="csrf" value="{%s CSRF %}" /> - <button class="mod-btn delete_msg_btn f-orange-clr" title="delete"></button> - </form> - {%- endif -%} - {%- elseif AuthUser.IsModerator() -%} - {%- if AuthUser.DisplayDeleteButton -%} - <div class="spacer16"></div> - {%- endif -%} - {%- else -%} - {%- if AuthUser.DisplayDeleteButton -%} - <div class="spacer16"></div> - {%- endif -%} - {%- endif -%} - {%- if AuthUser.IsModerator() -%} - {%- if e.UserID != AuthUser.ID -%} - {%- if AuthUser.DisplayHellbanButton -%} - {%- if e.User.Username == NullUsername -%} - <div class="spacer16"></div> - {%- else -%} - {%- if e.User.IsHellbanned -%} - <form method="post" action="/api/v1/users/{%s e.UserID.String() %}/unhellban" class="d-inline"> - <input type="hidden" name="csrf" value="{%s CSRF %}" /> - <button class="mod-btn hb_btn f-orange-clr line-through" title="unhellban"></button> - </form> - {%- else -%} - <form method="post" action="/api/v1/users/{%s e.UserID.String() %}/hellban" class="d-inline"> - <input type="hidden" name="csrf" value="{%s CSRF %}" /> - <button class="mod-btn hb_btn f-orange-clr" title="hellban"></button> - </form> - {%- endif -%} - {%- endif -%} - {%- endif -%} - {%- if AuthUser.DisplayKickButton -%} - <form method="post" action="/api/v1/users/{%s e.UserID.String() %}/kick" class="d-inline"> - <input type="hidden" name="csrf" value="{%s CSRF %}" /> - <button class="mod-btn k_btn f-orange-clr" title="kick"></button> - </form> - {%- endif -%} - {%- else -%} - {%- if AuthUser.DisplayKickButton && AuthUser.DisplayHellbanButton -%} - <div class="spacer36"></div> - {%- elseif AuthUser.DisplayKickButton || AuthUser.DisplayHellbanButton -%} - <div class="spacer16"></div> - {%- endif -%} - {%- endif -%} - {%- endif -%} - {%- else -%} - {%- if Data.NbButtons == 3 -%} - <div class="spacer56"></div> - {%- elseif Data.NbButtons == 2 -%} - <div class="spacer36"></div> - {%- elseif Data.NbButtons == 1 -%} - <div class="spacer16"></div> - {%- endif -%} - {%- endif -%} - {%- if Data.DateFormat != "" -%} - <a href="{%s baseTopBarURL %}?quote={%s e.UUID %}{%= unesc(Data.TopBarQueryParams) %}" target="iframe1" class="date date-link" title="{%s e.CreatedAt.Format("01-02 15:04:05") %}{% if isFirstMsg %} ({%s humanize.Time(e.CreatedAt) %}){% endif %}">{%s e.CreatedAt.Format(Data.DateFormat) %}</a> - {% code isFirstMsg = false %} - {%- endif -%} - <a href="/u/{%s e.GetProfile(AuthUser) %}" target="_blank" class="f-def-clr">-</a> - {%- if e.System -%} - <span class="sysmsg">{%= unesc(e.Message) %}</span> - {%- else -%} - {%- if e.Moderators -%}<span class="sysmsg">[<a href="{%s baseTopBarURL %}?m=1{%= unesc(Data.TopBarQueryParams) %}" target="iframe1" class="sysmsg f-white-clr">M</a>]</span>&nbsp;{%- endif -%} - {%- if e.GroupID != nil -%}<span class="sysmsg">[<a href="{%s baseTopBarURL %}?g={%s e.Group.Name %}{%= unesc(Data.TopBarQueryParams) %}" target="iframe1" class="sysmsg f-white-clr">{%s e.Group.Name %}</a>]</span>&nbsp;{%- endif -%} - {%- if e.ToUserID != nil -%} - [{%-= fromUsername(AuthUser, Data, e, baseTopBarURL) -%} - → - {%- if e.ToUser.ID == AuthUser.ID -%}<span {%= unesc(e.ToUser.GenerateChatStyle()) %}>{%s e.ToUser.Username %}</span>{%- else -%}<a {%= unesc(e.ToUser.GenerateChatStyle()) %} href="{%s baseTopBarURL %}?pm={%s e.ToUser.Username %}{%s Data.TopBarQueryParams %}" target="iframe1">{%s e.ToUser.Username %}</a>{%- endif -%}] - - {%- else -%} - {%-= fromUsername(AuthUser, Data, e, baseTopBarURL) -%} - {%- if !e.IsMe() -%} - {%- if AuthUser.CanSeeHB() && (e.IsHellbanned || e.User.IsHellbanned) && (e.ToUserID == nil) -%} - <a href="{%s baseTopBarURL %}?hbm=1{%= unesc(Data.TopBarQueryParams) %}" target="iframe1" class="f-def-clr">-</a> - {%- else -%} - - - {%- endif -%} - {%- endif -%} - {%- endif -%} - <span {%= unesc(e.User.GenerateChatStyle()) %}><span class="o-wrap">{%s= unesc(e.MsgToDisplay()) %}</span></span> - {%- endif -%} - </div> - {%- endif -%} - {% endfor %} - {% if len(Data.Messages) == 0 %} - <div id="no-msg"><em>No message yet</em></div> - {% endif %} + {%-= RenderMessages(AuthUser, Data, CSRF, NullUsername) -%} </div> {% if !AuthUser.HideRightColumn %} @@ -373,8 +265,129 @@ {% endfunc %} +{%- func RenderMessages(AuthUser *database.User, Data ChatMessagesData, CSRF, NullUsername string) -%} + {%- code + baseTopBarURL := "/api/v1/chat/top-bar/" + Data.RoomName + readMarkerRendered := false + isFirstMsg := true + -%} + {%- for idx, e := range Data.Messages -%} + {%-= RenderMessage(idx, e, AuthUser, Data, baseTopBarURL, &readMarkerRendered, &isFirstMsg, CSRF, NullUsername) -%} + {% endfor %} + {% if len(Data.Messages) == 0 %} + <div id="no-msg"><em>No message yet</em></div> + {% endif %} +{%- endfunc -%} + +{%- func RenderMessage(idx int, e database.ChatMessage, AuthUser *database.User, + Data ChatMessagesData, baseTopBarURL string, readMarkerRendered, isFirstMsg *bool, CSRF, NullUsername string) -%} + {%- if e.UserCanSee(*AuthUser) -%} + <div id="msgid-{%s e.UUID %}" class="msg + {%- if (e.User.IsHellbanned || e.IsHellbanned) && AuthUser.DisplayHellbanned %} hb-row + {%- elseif AuthUser.ID == e.User.ID && AuthUser.HighlightOwnMessages %} own-highlight{%- endif -%} + {%- if AuthUser.ChatReadMarkerEnabled && e.CreatedAt.Before(Data.ReadMarker.ReadAt) && !*readMarkerRendered %} + {%- if idx > 0 -%} read-marker{%- endif -%} + {%- code *readMarkerRendered = true -%} + {%- endif -%} + "> + {%- if e.UserCanDelete(*AuthUser) -%} + {%- if !e.TooOldToDelete() -%} + {%- if AuthUser.DisplayDeleteButton -%} + <form method="post" action="/api/v1/chat/messages/delete/{%s e.UUID %}" class="d-inline"> + <input type="hidden" name="csrf" value="{%s CSRF %}" /> + <button class="mod-btn delete_msg_btn" title="delete"></button> + </form> + {%- endif -%} + {%- elseif (AuthUser.IsModerator() && e.TooOldToDelete() && e.UserID != AuthUser.ID) || AuthUser.IsAdmin || (e.Room.OwnerUserID != nil && *e.Room.OwnerUserID == AuthUser.ID) -%} + {%- if AuthUser.DisplayDeleteButton -%} + <form method="post" action="/api/v1/chat/messages/delete/{%s e.UUID %}" class="d-inline"> + <input type="hidden" name="csrf" value="{%s CSRF %}" /> + <button class="mod-btn delete_msg_btn f-orange-clr" title="delete"></button> + </form> + {%- endif -%} + {%- elseif AuthUser.IsModerator() -%} + {%- if AuthUser.DisplayDeleteButton -%} + <div class="spacer16"></div> + {%- endif -%} + {%- else -%} + {%- if AuthUser.DisplayDeleteButton -%} + <div class="spacer16"></div> + {%- endif -%} + {%- endif -%} + {%- if AuthUser.IsModerator() -%} + {%- if e.UserID != AuthUser.ID -%} + {%- if AuthUser.DisplayHellbanButton -%} + {%- if e.User.Username == NullUsername -%} + <div class="spacer16"></div> + {%- else -%} + {%- if e.User.IsHellbanned -%} + <form method="post" action="/api/v1/users/{%s e.UserID.String() %}/unhellban" class="d-inline"> + <input type="hidden" name="csrf" value="{%s CSRF %}" /> + <button class="mod-btn hb_btn f-orange-clr line-through" title="unhellban"></button> + </form> + {%- else -%} + <form method="post" action="/api/v1/users/{%s e.UserID.String() %}/hellban" class="d-inline"> + <input type="hidden" name="csrf" value="{%s CSRF %}" /> + <button class="mod-btn hb_btn f-orange-clr" title="hellban"></button> + </form> + {%- endif -%} + {%- endif -%} + {%- endif -%} + {%- if AuthUser.DisplayKickButton -%} + <form method="post" action="/api/v1/users/{%s e.UserID.String() %}/kick" class="d-inline"> + <input type="hidden" name="csrf" value="{%s CSRF %}" /> + <button class="mod-btn k_btn f-orange-clr" title="kick"></button> + </form> + {%- endif -%} + {%- else -%} + {%- if AuthUser.DisplayKickButton && AuthUser.DisplayHellbanButton -%} + <div class="spacer36"></div> + {%- elseif AuthUser.DisplayKickButton || AuthUser.DisplayHellbanButton -%} + <div class="spacer16"></div> + {%- endif -%} + {%- endif -%} + {%- endif -%} + {%- else -%} + {%- if Data.NbButtons == 3 -%} + <div class="spacer56"></div> + {%- elseif Data.NbButtons == 2 -%} + <div class="spacer36"></div> + {%- elseif Data.NbButtons == 1 -%} + <div class="spacer16"></div> + {%- endif -%} + {%- endif -%} + {%- if AuthUser.GetDateFormat() != "" -%} + <a href="{%s baseTopBarURL %}?quote={%s e.UUID %}{%= unesc(Data.TopBarQueryParams) %}" target="iframe1" class="date date-link" title="{%s e.CreatedAt.Format("01-02 15:04:05") %}{% if *isFirstMsg %} ({%s humanize.Time(e.CreatedAt) %}){% endif %}">{%s e.CreatedAt.Format(AuthUser.GetDateFormat()) %}</a> + {% code *isFirstMsg = false %} + {%- endif -%} + <a href="/u/{%s e.GetProfile(AuthUser) %}" target="_blank" class="f-def-clr">-</a> + {%- if e.System -%} + <span class="sysmsg">{%= unesc(e.Message) %}</span> + {%- else -%} + {%- if e.Moderators -%}<span class="sysmsg">[<a href="{%s baseTopBarURL %}?m=1{%= unesc(Data.TopBarQueryParams) %}" target="iframe1" class="sysmsg f-white-clr">M</a>]</span>&nbsp;{%- endif -%} + {%- if e.GroupID != nil -%}<span class="sysmsg">[<a href="{%s baseTopBarURL %}?g={%s e.Group.Name %}{%= unesc(Data.TopBarQueryParams) %}" target="iframe1" class="sysmsg f-white-clr">{%s e.Group.Name %}</a>]</span>&nbsp;{%- endif -%} + {%- if e.ToUserID != nil -%} + [{%-= fromUsername(AuthUser, Data, e, baseTopBarURL) -%} + → + {%- if e.ToUser.ID == AuthUser.ID -%}<span {%= unesc(e.ToUser.GenerateChatStyle()) %}>{%s e.ToUser.Username %}</span>{%- else -%}<a {%= unesc(e.ToUser.GenerateChatStyle()) %} href="{%s baseTopBarURL %}?pm={%s e.ToUser.Username %}{%s Data.TopBarQueryParams %}" target="iframe1">{%s e.ToUser.Username %}</a>{%- endif -%}] - + {%- else -%} + {%-= fromUsername(AuthUser, Data, e, baseTopBarURL) -%} + {%- if !e.IsMe() -%} + {%- if AuthUser.CanSeeHB() && (e.IsHellbanned || e.User.IsHellbanned) && (e.ToUserID == nil) -%} + <a href="{%s baseTopBarURL %}?hbm=1{%= unesc(Data.TopBarQueryParams) %}" target="iframe1" class="f-def-clr">-</a> + {%- else -%} + - + {%- endif -%} + {%- endif -%} + {%- endif -%} + <span {%= unesc(e.User.GenerateChatStyle()) %}><span class="o-wrap">{%s= unesc(e.MsgToDisplay()) %}</span></span> + {%- endif -%} + </div> + {%- endif -%} +{%- endfunc -%} + -{% func Member(AuthUser *database.User, Data chatMessagesData, El managers.UserInfo) %} +{% func Member(AuthUser *database.User, Data ChatMessagesData, El managers.UserInfo) %} {%- code baseTopBarURL := "/api/v1/chat/top-bar/" + Data.RoomName -%} {%- if El.Username == AuthUser.Username -%} <div> @@ -413,7 +426,7 @@ {% endfunc %} -{%- func fromUsername(AuthUser *database.User, Data chatMessagesData, El database.ChatMessage, baseTopBarURL string) -%} +{%- func fromUsername(AuthUser *database.User, Data ChatMessagesData, El database.ChatMessage, baseTopBarURL string) -%} {%- code tagType := "tag" -%} {%- if El.ToUserID != nil -%} {%- code tagType = "pm" -%} diff --git a/pkg/web/handlers/api/v1/messages.qtpl.go b/pkg/web/handlers/api/v1/messages.qtpl.go @@ -27,33 +27,211 @@ var ( ) //line messages.qtpl:5 -func StreamMessages(qw422016 *qt422016.Writer, VERSION, CSRF, NullUsername string, AuthUser *database.User, Data chatMessagesData) { +func StreamGenerateStyle(qw422016 *qt422016.Writer, AuthUser *database.User, Data ChatMessagesData) { //line messages.qtpl:5 + qw422016.N().S(`<style> + i { font-style: italic; } + + /* Remove button padding in FF */ + button::-moz-focus-inner { + border:0; + padding:0; + } + + body { font-family: Lato,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"; } + a { color: #00bc8c; text-decoration: none; } + a:hover { color: #007053; text-decoration: underline; } + .unread_room { color: #2392da; text-decoration: none; } + .unread_room:hover { color: #004970; text-decoration: underline; } + .emoji { + font-family: "Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji", Times, Symbola, Aegyptus, Code2000, Code2001, Code2002, Musica, serif, LastResort; + font-size: 17px; + } + .mod-btn { + width: 16px; height: 16px; + margin: 0; padding: 0; + border: 1px solid gray; + display: inline; + text-align: center; + vertical-align: middle; + user-select: none; + background-color: #444; + color: #ea2a2a; + -webkit-box-shadow: 1px 1px 1px rgba(0,0,0,0.25); + -moz-box-shadow: 1px 1px 1px rgba(0,0,0,0.25); + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + } + .mod-btn:hover { + background-color: #222; + } + .delete_msg_btn { + font-size: 15px; + line-height: 1; + } + .delete_msg_btn::after { content: "×"; } + .hb_btn { + font-size: 10px; + line-height: 1.4; + } + .hb_btn::after { content: "hb"; } + .k_btn { + font-size: 10px; + line-height: 1.4; + } + .k_btn::after { content: "k"; } + #manualrefresh { + `) +//line messages.qtpl:58 + if !Data.ForceManualRefresh { +//line messages.qtpl:58 + qw422016.N().S(` + top: -200%; + animation: timeout_messages `) +//line messages.qtpl:60 + qw422016.N().DL(Data.ManualRefreshTimeout) +//line messages.qtpl:60 + qw422016.N().S(`s forwards; + `) +//line messages.qtpl:61 + } +//line messages.qtpl:61 + qw422016.N().S(` + color: #bf2718; + display: block; + position: fixed; + text-align: center; + left: calc(50% - 200px); + width: 400px; + z-index: 2; + background-color: #500000; + border: 2px solid #ff0000; + } + @keyframes timeout_messages { + 0% { top: -200%; } + 99% { top: -200%; } + 100% { top: 0; } + } + .date { color: #999; font-family: 'Courier New', Courier, monospace; font-size: 14px; } + .date-link:hover { color: #999; text-decoration: underline; } + .sysmsg { color: #fff; font-family: 'Courier New', Courier, monospace; font-size: 14px; } + small { font-size: 80%; font-weight: 400; } + .msg { padding: 3px 0 3px 8px; border-bottom: 1px solid #444; color: #888; position: relative; } + .msg p:first-of-type { display: inline; } + strong { font-weight: bold; } + em { font-style: italic; } + pre { border: 1px solid #2b442b; padding: 2px; margin: 2px 0; max-height: 300px; overflow: auto; background-color: rgba(39,40,34,0.6) !important; + font-family: SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace; } + code { border: 1px solid #2b442b; color: #f92672; padding: 0 2px; margin: 0px 0; background-color: rgba(39,40,34,0.6) !important; } + .censored { background-color: black; color: black; padding: 0 3px; } + .censored:hover { background-color: black; color: white; } + ul { list-style-type: disc; margin: 0 0 0 15px; } + * { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } + .afk-indicator { color: #ff9a27; } + .spacer16 { display: inline-block; width: 16px; } + .spacer36 { display: inline-block; width: 36px; } + .spacer56 { display: inline-block; width: 56px; } + .d-inline { display: inline; } + .o-wrap { overflow-wrap: break-word; } + .f-def-clr { color: #888; } + .f-orange-clr { color: orange; } + .f-white-clr, .f-white-clr:hover { color: white; } + .line-through { text-decoration: line-through; } + .hb-row { background-color: rgba(0, 0, 0, 0.7); opacity: `) +//line messages.qtpl:105 + qw422016.N().F(AuthUser.GetHellbanOpacityF64()) +//line messages.qtpl:105 + qw422016.N().S(`; } + .own-highlight { background-color: rgba(255,241,176,0.05); } + .read-marker { border-top: `) +//line messages.qtpl:107 + qw422016.N().DL(AuthUser.ChatReadMarkerSize) +//line messages.qtpl:107 + qw422016.N().S(`px solid `) +//line messages.qtpl:107 + qw422016.E().S(AuthUser.ChatReadMarkerColor) +//line messages.qtpl:107 + qw422016.N().S(`; } + #msgs { `) +//line messages.qtpl:108 + if !AuthUser.HideRightColumn { +//line messages.qtpl:108 + qw422016.N().S(`width: calc(100% - 170px); float: left; `) +//line messages.qtpl:108 + } +//line messages.qtpl:108 + qw422016.N().S(`line-height: 1.2; } + #no-msg { padding-left: 10px; color: #ddd; } + #rgt-pane { width: 150px; height: 100%; float: left; margin-left: 20px; position: fixed; right: 0; overflow-y: auto; line-height: 1.15; } + .rgt-title { font-weight: bolder; color: #ced4da; } + .mb-20px { margin-bottom: 20px; } + .mb-30px { margin-bottom: 30px; } + .mt-5px { margin-top: 5px; } + .mt-10px { margin-top: 10px; } + .notif, .notif:hover { color: #e74c3c; } + #msg-err { background-color: #8f2d2d; color: #ffffff; padding: 1px 5px 2px 5px; display: block; text-decoration: none; } +</style> +`) +//line messages.qtpl:119 +} + +//line messages.qtpl:119 +func WriteGenerateStyle(qq422016 qtio422016.Writer, AuthUser *database.User, Data ChatMessagesData) { +//line messages.qtpl:119 + qw422016 := qt422016.AcquireWriter(qq422016) +//line messages.qtpl:119 + StreamGenerateStyle(qw422016, AuthUser, Data) +//line messages.qtpl:119 + qt422016.ReleaseWriter(qw422016) +//line messages.qtpl:119 +} + +//line messages.qtpl:119 +func GenerateStyle(AuthUser *database.User, Data ChatMessagesData) string { +//line messages.qtpl:119 + qb422016 := qt422016.AcquireByteBuffer() +//line messages.qtpl:119 + WriteGenerateStyle(qb422016, AuthUser, Data) +//line messages.qtpl:119 + qs422016 := string(qb422016.B) +//line messages.qtpl:119 + qt422016.ReleaseByteBuffer(qb422016) +//line messages.qtpl:119 + return qs422016 +//line messages.qtpl:119 +} + +//line messages.qtpl:121 +func StreamMessages(qw422016 *qt422016.Writer, VERSION, CSRF, NullUsername string, AuthUser *database.User, Data ChatMessagesData) { +//line messages.qtpl:121 qw422016.N().S(`<html lang="en"> <head> <title></title> `) -//line messages.qtpl:9 +//line messages.qtpl:125 if !Data.PreventRefresh && !Data.ForceManualRefresh { -//line messages.qtpl:9 +//line messages.qtpl:125 qw422016.N().S(`<meta http-equiv="refresh" content="`) -//line messages.qtpl:9 +//line messages.qtpl:125 qw422016.N().DL(AuthUser.RefreshRate) -//line messages.qtpl:9 +//line messages.qtpl:125 qw422016.N().S(`">`) -//line messages.qtpl:9 +//line messages.qtpl:125 } -//line messages.qtpl:10 +//line messages.qtpl:126 if AuthUser.CollectMetadata { -//line messages.qtpl:10 +//line messages.qtpl:126 qw422016.N().S(`<link rel="stylesheet" type="text/css" href="/public/css/meta.css?v=`) -//line messages.qtpl:10 +//line messages.qtpl:126 qw422016.E().S(VERSION) -//line messages.qtpl:10 +//line messages.qtpl:126 qw422016.N().S(`" />`) -//line messages.qtpl:10 +//line messages.qtpl:126 } -//line messages.qtpl:10 +//line messages.qtpl:126 qw422016.N().S(` <style> /* http://meyerweb.com/eric/tools/css/reset/ @@ -104,173 +282,32 @@ func StreamMessages(qw422016 *qt422016.Writer, VERSION, CSRF, NullUsername strin border-spacing: 0; } /* --- end --- */ - - - i { font-style: italic; } - - /* Remove button padding in FF */ - button::-moz-focus-inner { - border:0; - padding:0; - } - - body { font-family: Lato,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"; } - a { color: #00bc8c; text-decoration: none; } - a:hover { color: #007053; text-decoration: underline; } - .unread_room { color: #2392da; text-decoration: none; } - .unread_room:hover { color: #004970; text-decoration: underline; } - .emoji { - font-family: "Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji", Times, Symbola, Aegyptus, Code2000, Code2001, Code2002, Musica, serif, LastResort; - font-size: 17px; - } - .mod-btn { - width: 16px; height: 16px; - margin: 0; padding: 0; - border: 1px solid gray; - display: inline; - text-align: center; - vertical-align: middle; - user-select: none; - background-color: #444; - color: #ea2a2a; - -webkit-box-shadow: 1px 1px 1px rgba(0,0,0,0.25); - -moz-box-shadow: 1px 1px 1px rgba(0,0,0,0.25); - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - } - .mod-btn:hover { - background-color: #222; - } - .delete_msg_btn { - font-size: 15px; - line-height: 1; - } - .delete_msg_btn::after { content: "×"; } - .hb_btn { - font-size: 10px; - line-height: 1.4; - } - .hb_btn::after { content: "hb"; } - .k_btn { - font-size: 10px; - line-height: 1.4; - } - .k_btn::after { content: "k"; } - #manualrefresh { - `) -//line messages.qtpl:114 - if !Data.ForceManualRefresh { -//line messages.qtpl:114 - qw422016.N().S(` - top: -200%; - animation: timeout_messages `) -//line messages.qtpl:116 - qw422016.N().DL(Data.ManualRefreshTimeout) -//line messages.qtpl:116 - qw422016.N().S(`s forwards; - `) -//line messages.qtpl:117 - } -//line messages.qtpl:117 - qw422016.N().S(` - color: #bf2718; - display: block; - position: fixed; - text-align: center; - left: calc(50% - 200px); - width: 400px; - z-index: 2; - background-color: #500000; - border: 2px solid #ff0000; - } - @keyframes timeout_messages { - 0% { top: -200%; } - 99% { top: -200%; } - 100% { top: 0; } - } - .date { color: #999; font-family: 'Courier New', Courier, monospace; font-size: 14px; } - .date-link:hover { color: #999; text-decoration: underline; } - .sysmsg { color: #fff; font-family: 'Courier New', Courier, monospace; font-size: 14px; } - small { font-size: 80%; font-weight: 400; } - .msg { padding: 3px 0 3px 8px; border-bottom: 1px solid #444; color: #888; position: relative; } - .msg p:first-of-type { display: inline; } - strong { font-weight: bold; } - em { font-style: italic; } - pre { border: 1px solid #2b442b; padding: 2px; margin: 2px 0; max-height: 300px; overflow: auto; background-color: rgba(39,40,34,0.6) !important; - font-family: SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace; } - code { border: 1px solid #2b442b; color: #f92672; padding: 0 2px; margin: 0px 0; background-color: rgba(39,40,34,0.6) !important; } - .censored { background-color: black; color: black; padding: 0 3px; } - .censored:hover { background-color: black; color: white; } - ul { list-style-type: disc; margin: 0 0 0 15px; } - * { - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - } - .afk-indicator { color: #ff9a27; } - .spacer16 { display: inline-block; width: 16px; } - .spacer36 { display: inline-block; width: 36px; } - .spacer56 { display: inline-block; width: 56px; } - .d-inline { display: inline; } - .o-wrap { overflow-wrap: break-word; } - .f-def-clr { color: #888; } - .f-orange-clr { color: orange; } - .f-white-clr, .f-white-clr:hover { color: white; } - .line-through { text-decoration: line-through; } - .hb-row { background-color: rgba(0, 0, 0, 0.7); opacity: `) -//line messages.qtpl:161 - qw422016.N().F(AuthUser.GetHellbanOpacityF64()) -//line messages.qtpl:161 - qw422016.N().S(`; } - .own-highlight { background-color: rgba(255,241,176,0.05); } - .read-marker { border-top: `) -//line messages.qtpl:163 - qw422016.N().DL(AuthUser.ChatReadMarkerSize) -//line messages.qtpl:163 - qw422016.N().S(`px solid `) -//line messages.qtpl:163 - qw422016.E().S(AuthUser.ChatReadMarkerColor) -//line messages.qtpl:163 - qw422016.N().S(`; } - #msgs { `) -//line messages.qtpl:164 - if !AuthUser.HideRightColumn { -//line messages.qtpl:164 - qw422016.N().S(`width: calc(100% - 170px); float: left; `) -//line messages.qtpl:164 - } -//line messages.qtpl:164 - qw422016.N().S(`line-height: 1.2; } - #no-msg { padding-left: 10px; color: #ddd; } - #rgt-pane { width: 150px; height: 100%; float: left; margin-left: 20px; position: fixed; right: 0; overflow-y: auto; line-height: 1.15; } - .rgt-title { font-weight: bolder; color: #ced4da; } - .mb-20px { margin-bottom: 20px; } - .mb-30px { margin-bottom: 30px; } - .mt-5px { margin-top: 5px; } - .mt-10px { margin-top: 10px; } - .notif, .notif:hover { color: #e74c3c; } - #msg-err { background-color: #8f2d2d; color: #ffffff; padding: 1px 5px 2px 5px; display: block; text-decoration: none; } </style> - </head> +`) +//line messages.qtpl:178 + StreamGenerateStyle(qw422016, AuthUser, Data) +//line messages.qtpl:178 + qw422016.N().S(` </head> <body> `) -//line messages.qtpl:178 +//line messages.qtpl:182 if Data.ForceManualRefresh { -//line messages.qtpl:178 +//line messages.qtpl:182 qw422016.N().S(` <div id="manualrefresh"> <h4>Manual refresh required</h4> <form method="get" action="/chat/`) -//line messages.qtpl:181 +//line messages.qtpl:185 qw422016.E().S(Data.RoomName) -//line messages.qtpl:181 +//line messages.qtpl:185 qw422016.N().S(`" target="_top"> <input type="submit" value="Reload" /> </form> </div> `) -//line messages.qtpl:185 +//line messages.qtpl:189 } else if !Data.PreventRefresh { -//line messages.qtpl:185 +//line messages.qtpl:189 qw422016.N().S(` <div id="manualrefresh"> <h4>Manual refresh required</h4> <form method="get"> @@ -278,962 +315,1033 @@ func StreamMessages(qw422016 *qt422016.Writer, VERSION, CSRF, NullUsername strin </form> </div> `) -//line messages.qtpl:192 +//line messages.qtpl:196 } -//line messages.qtpl:192 +//line messages.qtpl:196 qw422016.N().S(` `) -//line messages.qtpl:194 +//line messages.qtpl:198 if Data.Error != "" { -//line messages.qtpl:194 +//line messages.qtpl:198 qw422016.N().S(` <a href="/api/v1/chat/messages/`) -//line messages.qtpl:195 +//line messages.qtpl:199 qw422016.E().S(Data.RoomName) -//line messages.qtpl:195 +//line messages.qtpl:199 qw422016.N().S(`" id="msg-err">× `) -//line messages.qtpl:195 +//line messages.qtpl:199 qw422016.E().S(Data.Error) -//line messages.qtpl:195 +//line messages.qtpl:199 qw422016.N().S(`</a> `) -//line messages.qtpl:196 +//line messages.qtpl:200 } -//line messages.qtpl:196 +//line messages.qtpl:200 qw422016.N().S(` `) -//line messages.qtpl:198 +//line messages.qtpl:202 if Data.PmSound || Data.TaggedSound { -//line messages.qtpl:198 +//line messages.qtpl:202 qw422016.N().S(` <audio src="/public/mp3/sound5.mp3" autoplay></audio> `) -//line messages.qtpl:200 +//line messages.qtpl:204 } else if Data.NewMessageSound { -//line messages.qtpl:200 +//line messages.qtpl:204 qw422016.N().S(` <audio src="/public/mp3/sound6.mp3" autoplay></audio> `) -//line messages.qtpl:202 +//line messages.qtpl:206 } -//line messages.qtpl:202 +//line messages.qtpl:206 qw422016.N().S(` <div id="msgs"> `) -//line messages.qtpl:206 - baseTopBarURL := "/api/v1/chat/top-bar/" + Data.RoomName - readMarkerRendered := false - isFirstMsg := true +//line messages.qtpl:209 + StreamRenderMessages(qw422016, AuthUser, Data, CSRF, NullUsername) +//line messages.qtpl:209 + qw422016.N().S(` </div> -//line messages.qtpl:210 - for idx, e := range Data.Messages { -//line messages.qtpl:211 - if e.UserCanSee(*AuthUser) { -//line messages.qtpl:211 - qw422016.N().S(` <div id="msgid-`) + `) //line messages.qtpl:212 - qw422016.E().S(e.UUID) + if !AuthUser.HideRightColumn { //line messages.qtpl:212 - qw422016.N().S(`" class="msg -`) -//line messages.qtpl:213 - if (e.User.IsHellbanned || e.IsHellbanned) && AuthUser.DisplayHellbanned { -//line messages.qtpl:213 - qw422016.N().S(` hb-row -`) -//line messages.qtpl:214 - } else if AuthUser.ID == e.User.ID && AuthUser.HighlightOwnMessages { -//line messages.qtpl:214 - qw422016.N().S(` own-highlight`) -//line messages.qtpl:214 - } + qw422016.N().S(` + <div id="rgt-pane"> + <div class="mb-20px"> + <div class="rgt-title">Inbox (<a href="/settings/inbox" target="_top"`) //line messages.qtpl:215 - if AuthUser.ChatReadMarkerEnabled && e.CreatedAt.Before(Data.ReadMarker.ReadAt) && !readMarkerRendered { + if Data.InboxCount > 0 { //line messages.qtpl:215 - qw422016.N().S(` -`) -//line messages.qtpl:216 - if idx > 0 { -//line messages.qtpl:216 - qw422016.N().S(`read-marker`) -//line messages.qtpl:216 - } -//line messages.qtpl:217 - readMarkerRendered = true - -//line messages.qtpl:218 - } -//line messages.qtpl:218 - qw422016.N().S(` "> + qw422016.N().S(`class="notif"`) +//line messages.qtpl:215 + } +//line messages.qtpl:215 + qw422016.N().S(`>`) +//line messages.qtpl:215 + qw422016.N().DL(Data.InboxCount) +//line messages.qtpl:215 + qw422016.N().S(`</a>)</div> + </div> + <div class="mb-20px"> + <div class="rgt-title">Rooms:</div> `) +//line messages.qtpl:219 + for _, e := range Data.OfficialRooms { //line messages.qtpl:220 - if e.UserCanDelete(*AuthUser) { + if e.Name == "club" { //line messages.qtpl:221 - if !e.TooOldToDelete() { + if AuthUser.IsClubMember { +//line messages.qtpl:221 + qw422016.N().S(` <div><a href="/chat/club" target="_top"`) +//line messages.qtpl:222 + if e.IsUnread { //line messages.qtpl:222 - if AuthUser.DisplayDeleteButton { + qw422016.N().S(` class="unread_room"`) //line messages.qtpl:222 - qw422016.N().S(` <form method="post" action="/api/v1/chat/messages/delete/`) -//line messages.qtpl:223 - qw422016.E().S(e.UUID) + } +//line messages.qtpl:222 + qw422016.N().S(`>#club</a></div> +`) //line messages.qtpl:223 - qw422016.N().S(`" class="d-inline"> - <input type="hidden" name="csrf" value="`) -//line messages.qtpl:224 - qw422016.E().S(CSRF) + } //line messages.qtpl:224 - qw422016.N().S(`" /> - <button class="mod-btn delete_msg_btn" title="delete"></button> - </form> + } else if e.Name == "moderators" { +//line messages.qtpl:225 + if AuthUser.IsModerator() { +//line messages.qtpl:225 + qw422016.N().S(` <div><a href="/chat/moderators" target="_top"`) +//line messages.qtpl:226 + if e.IsUnread { +//line messages.qtpl:226 + qw422016.N().S(` class="unread_room"`) +//line messages.qtpl:226 + } +//line messages.qtpl:226 + qw422016.N().S(`>#moderators</a></div> `) //line messages.qtpl:227 - } + } +//line messages.qtpl:228 + } else { //line messages.qtpl:228 - } else if (AuthUser.IsModerator() && e.TooOldToDelete() && e.UserID != AuthUser.ID) || AuthUser.IsAdmin || (e.Room.OwnerUserID != nil && *e.Room.OwnerUserID == AuthUser.ID) { + qw422016.N().S(` <div><a href="/chat/`) //line messages.qtpl:229 - if AuthUser.DisplayDeleteButton { + qw422016.E().S(e.Name) //line messages.qtpl:229 - qw422016.N().S(` <form method="post" action="/api/v1/chat/messages/delete/`) -//line messages.qtpl:230 - qw422016.E().S(e.UUID) + qw422016.N().S(`" target="_top"`) +//line messages.qtpl:229 + if e.IsUnread { +//line messages.qtpl:229 + qw422016.N().S(` class="unread_room"`) +//line messages.qtpl:229 + } +//line messages.qtpl:229 + qw422016.N().S(`>#`) +//line messages.qtpl:229 + qw422016.E().S(e.Name) +//line messages.qtpl:229 + qw422016.N().S(`</a></div> +`) //line messages.qtpl:230 - qw422016.N().S(`" class="d-inline"> - <input type="hidden" name="csrf" value="`) -//line messages.qtpl:231 - qw422016.E().S(CSRF) + } //line messages.qtpl:231 - qw422016.N().S(`" /> - <button class="mod-btn delete_msg_btn f-orange-clr" title="delete"></button> - </form> + } +//line messages.qtpl:232 + if len(Data.SubscribedRooms) > 0 { +//line messages.qtpl:232 + qw422016.N().S(` <div class="mt-10px"></div> `) //line messages.qtpl:234 - } + for _, e := range Data.SubscribedRooms { +//line messages.qtpl:234 + qw422016.N().S(` <div><a href="/chat/`) //line messages.qtpl:235 - } else if AuthUser.IsModerator() { -//line messages.qtpl:236 - if AuthUser.DisplayDeleteButton { -//line messages.qtpl:236 - qw422016.N().S(` <div class="spacer16"></div> + qw422016.E().S(e.Name) +//line messages.qtpl:235 + qw422016.N().S(`" target="_top"`) +//line messages.qtpl:235 + if e.IsUnread { +//line messages.qtpl:235 + qw422016.N().S(` class="unread_room"`) +//line messages.qtpl:235 + } +//line messages.qtpl:235 + qw422016.N().S(`>#`) +//line messages.qtpl:235 + qw422016.E().S(e.Name) +//line messages.qtpl:235 + qw422016.N().S(`</a></div> `) -//line messages.qtpl:238 - } -//line messages.qtpl:239 - } else { -//line messages.qtpl:240 - if AuthUser.DisplayDeleteButton { -//line messages.qtpl:240 - qw422016.N().S(` <div class="spacer16"></div> +//line messages.qtpl:236 + } +//line messages.qtpl:237 + } +//line messages.qtpl:237 + qw422016.N().S(` <div class="mt-5px"><a href="/rooms" target="_top">[...]</a></div> + </div> + <div class="mb-20px"> + <div class="rgt-title">In this room:</div> `) //line messages.qtpl:242 - } + for _, e := range Data.Members { +//line messages.qtpl:242 + qw422016.N().S(` `) //line messages.qtpl:243 - } + StreamMember(qw422016, AuthUser, Data, e) +//line messages.qtpl:243 + qw422016.N().S(` +`) //line messages.qtpl:244 - if AuthUser.IsModerator() { -//line messages.qtpl:245 - if e.UserID != AuthUser.ID { + } +//line messages.qtpl:244 + qw422016.N().S(` </div> +`) +//line messages.qtpl:246 + if Data.VisibleMemberInChat || AuthUser.DisplayHellbanned { //line messages.qtpl:246 - if AuthUser.DisplayHellbanButton { -//line messages.qtpl:247 - if e.User.Username == NullUsername { -//line messages.qtpl:247 - qw422016.N().S(` <div class="spacer16"></div> + qw422016.N().S(` <div class="mb-30px"> +`) +//line messages.qtpl:248 + if len(Data.MembersInChat) > 0 { +//line messages.qtpl:248 + qw422016.N().S(` <div class="rgt-title">In other rooms:</div> `) -//line messages.qtpl:249 - } else { //line messages.qtpl:250 - if e.User.IsHellbanned { + for _, e := range Data.MembersInChat { //line messages.qtpl:250 - qw422016.N().S(` <form method="post" action="/api/v1/users/`) + qw422016.N().S(` `) //line messages.qtpl:251 - qw422016.E().S(e.UserID.String()) + StreamMember(qw422016, AuthUser, Data, e) //line messages.qtpl:251 - qw422016.N().S(`/unhellban" class="d-inline"> - <input type="hidden" name="csrf" value="`) -//line messages.qtpl:252 - qw422016.E().S(CSRF) + qw422016.N().S(` +`) //line messages.qtpl:252 - qw422016.N().S(`" /> - <button class="mod-btn hb_btn f-orange-clr line-through" title="unhellban"></button> - </form> + } +//line messages.qtpl:253 + } +//line messages.qtpl:253 + qw422016.N().S(` </div> `) //line messages.qtpl:255 - } else { + } //line messages.qtpl:255 - qw422016.N().S(` <form method="post" action="/api/v1/users/`) -//line messages.qtpl:256 - qw422016.E().S(e.UserID.String()) -//line messages.qtpl:256 - qw422016.N().S(`/hellban" class="d-inline"> - <input type="hidden" name="csrf" value="`) -//line messages.qtpl:257 - qw422016.E().S(CSRF) + qw422016.N().S(` </div> +`) //line messages.qtpl:257 - qw422016.N().S(`" /> - <button class="mod-btn hb_btn f-orange-clr" title="hellban"></button> - </form> + } +//line messages.qtpl:258 + if AuthUser.CollectMetadata { +//line messages.qtpl:258 + qw422016.N().S(` <div class="div_1"></div> + <div class="div_2"></div> + <div class="div_f0">a</div> `) -//line messages.qtpl:260 - } -//line messages.qtpl:261 - } //line messages.qtpl:262 - } -//line messages.qtpl:263 - if AuthUser.DisplayKickButton { -//line messages.qtpl:263 - qw422016.N().S(` <form method="post" action="/api/v1/users/`) -//line messages.qtpl:264 - qw422016.E().S(e.UserID.String()) -//line messages.qtpl:264 - qw422016.N().S(`/kick" class="d-inline"> - <input type="hidden" name="csrf" value="`) -//line messages.qtpl:265 - qw422016.E().S(CSRF) -//line messages.qtpl:265 - qw422016.N().S(`" /> - <button class="mod-btn k_btn f-orange-clr" title="kick"></button> - </form> -`) + } +//line messages.qtpl:262 + qw422016.N().S(` </body> +</html> +`) +//line messages.qtpl:265 +} + +//line messages.qtpl:265 +func WriteMessages(qq422016 qtio422016.Writer, VERSION, CSRF, NullUsername string, AuthUser *database.User, Data ChatMessagesData) { +//line messages.qtpl:265 + qw422016 := qt422016.AcquireWriter(qq422016) +//line messages.qtpl:265 + StreamMessages(qw422016, VERSION, CSRF, NullUsername, AuthUser, Data) +//line messages.qtpl:265 + qt422016.ReleaseWriter(qw422016) +//line messages.qtpl:265 +} + +//line messages.qtpl:265 +func Messages(VERSION, CSRF, NullUsername string, AuthUser *database.User, Data ChatMessagesData) string { +//line messages.qtpl:265 + qb422016 := qt422016.AcquireByteBuffer() +//line messages.qtpl:265 + WriteMessages(qb422016, VERSION, CSRF, NullUsername, AuthUser, Data) +//line messages.qtpl:265 + qs422016 := string(qb422016.B) +//line messages.qtpl:265 + qt422016.ReleaseByteBuffer(qb422016) +//line messages.qtpl:265 + return qs422016 +//line messages.qtpl:265 +} + //line messages.qtpl:268 - } -//line messages.qtpl:269 - } else { +func StreamRenderMessages(qw422016 *qt422016.Writer, AuthUser *database.User, Data ChatMessagesData, CSRF, NullUsername string) { //line messages.qtpl:270 - if AuthUser.DisplayKickButton && AuthUser.DisplayHellbanButton { -//line messages.qtpl:270 - qw422016.N().S(` <div class="spacer36"></div> -`) -//line messages.qtpl:272 - } else if AuthUser.DisplayKickButton || AuthUser.DisplayHellbanButton { -//line messages.qtpl:272 - qw422016.N().S(` <div class="spacer16"></div> -`) + baseTopBarURL := "/api/v1/chat/top-bar/" + Data.RoomName + readMarkerRendered := false + isFirstMsg := true + //line messages.qtpl:274 - } + for idx, e := range Data.Messages { //line messages.qtpl:275 - } + StreamRenderMessage(qw422016, idx, e, AuthUser, Data, baseTopBarURL, &readMarkerRendered, &isFirstMsg, CSRF, NullUsername) +//line messages.qtpl:275 + qw422016.N().S(` `) //line messages.qtpl:276 - } + } +//line messages.qtpl:276 + qw422016.N().S(` + `) //line messages.qtpl:277 - } else { -//line messages.qtpl:278 - if Data.NbButtons == 3 { -//line messages.qtpl:278 - qw422016.N().S(` <div class="spacer56"></div> + if len(Data.Messages) == 0 { +//line messages.qtpl:277 + qw422016.N().S(` + <div id="no-msg"><em>No message yet</em></div> + `) +//line messages.qtpl:279 + } +//line messages.qtpl:279 + qw422016.N().S(` `) //line messages.qtpl:280 - } else if Data.NbButtons == 2 { +} + //line messages.qtpl:280 - qw422016.N().S(` <div class="spacer36"></div> -`) -//line messages.qtpl:282 - } else if Data.NbButtons == 1 { +func WriteRenderMessages(qq422016 qtio422016.Writer, AuthUser *database.User, Data ChatMessagesData, CSRF, NullUsername string) { +//line messages.qtpl:280 + qw422016 := qt422016.AcquireWriter(qq422016) +//line messages.qtpl:280 + StreamRenderMessages(qw422016, AuthUser, Data, CSRF, NullUsername) +//line messages.qtpl:280 + qt422016.ReleaseWriter(qw422016) +//line messages.qtpl:280 +} + +//line messages.qtpl:280 +func RenderMessages(AuthUser *database.User, Data ChatMessagesData, CSRF, NullUsername string) string { +//line messages.qtpl:280 + qb422016 := qt422016.AcquireByteBuffer() +//line messages.qtpl:280 + WriteRenderMessages(qb422016, AuthUser, Data, CSRF, NullUsername) +//line messages.qtpl:280 + qs422016 := string(qb422016.B) +//line messages.qtpl:280 + qt422016.ReleaseByteBuffer(qb422016) +//line messages.qtpl:280 + return qs422016 +//line messages.qtpl:280 +} + //line messages.qtpl:282 - qw422016.N().S(` <div class="spacer16"></div> -`) +func StreamRenderMessage(qw422016 *qt422016.Writer, idx int, e database.ChatMessage, AuthUser *database.User, + Data ChatMessagesData, baseTopBarURL string, readMarkerRendered, isFirstMsg *bool, CSRF, NullUsername string) { //line messages.qtpl:284 - } + if e.UserCanSee(*AuthUser) { +//line messages.qtpl:284 + qw422016.N().S(` <div id="msgid-`) //line messages.qtpl:285 - } + qw422016.E().S(e.UUID) +//line messages.qtpl:285 + qw422016.N().S(`" class="msg +`) //line messages.qtpl:286 - if Data.DateFormat != "" { + if (e.User.IsHellbanned || e.IsHellbanned) && AuthUser.DisplayHellbanned { //line messages.qtpl:286 - qw422016.N().S(` <a href="`) -//line messages.qtpl:287 - qw422016.E().S(baseTopBarURL) -//line messages.qtpl:287 - qw422016.N().S(`?quote=`) -//line messages.qtpl:287 - qw422016.E().S(e.UUID) -//line messages.qtpl:287 - streamunesc(qw422016, Data.TopBarQueryParams) -//line messages.qtpl:287 - qw422016.N().S(`" target="iframe1" class="date date-link" title="`) -//line messages.qtpl:287 - qw422016.E().S(e.CreatedAt.Format("01-02 15:04:05")) -//line messages.qtpl:287 - if isFirstMsg { -//line messages.qtpl:287 - qw422016.N().S(` (`) -//line messages.qtpl:287 - qw422016.E().S(humanize.Time(e.CreatedAt)) -//line messages.qtpl:287 - qw422016.N().S(`)`) -//line messages.qtpl:287 - } + qw422016.N().S(` hb-row +`) //line messages.qtpl:287 - qw422016.N().S(`">`) + } else if AuthUser.ID == e.User.ID && AuthUser.HighlightOwnMessages { //line messages.qtpl:287 - qw422016.E().S(e.CreatedAt.Format(Data.DateFormat)) + qw422016.N().S(` own-highlight`) //line messages.qtpl:287 - qw422016.N().S(`</a> - `) + } //line messages.qtpl:288 - isFirstMsg = false - + if AuthUser.ChatReadMarkerEnabled && e.CreatedAt.Before(Data.ReadMarker.ReadAt) && !*readMarkerRendered { //line messages.qtpl:288 - qw422016.N().S(` + qw422016.N().S(` `) //line messages.qtpl:289 - } + if idx > 0 { //line messages.qtpl:289 - qw422016.N().S(` <a href="/u/`) -//line messages.qtpl:290 - qw422016.E().S(e.GetProfile(AuthUser)) + qw422016.N().S(`read-marker`) +//line messages.qtpl:289 + } //line messages.qtpl:290 - qw422016.N().S(`" target="_blank" class="f-def-clr">-</a> -`) + *readMarkerRendered = true + //line messages.qtpl:291 - if e.System { + } //line messages.qtpl:291 - qw422016.N().S(` <span class="sysmsg">`) -//line messages.qtpl:292 - streamunesc(qw422016, e.Message) -//line messages.qtpl:292 - qw422016.N().S(`</span> + qw422016.N().S(` "> `) //line messages.qtpl:293 - } else { -//line messages.qtpl:294 - if e.Moderators { -//line messages.qtpl:294 - qw422016.N().S(`<span class="sysmsg">[<a href="`) -//line messages.qtpl:294 - qw422016.E().S(baseTopBarURL) -//line messages.qtpl:294 - qw422016.N().S(`?m=1`) -//line messages.qtpl:294 - streamunesc(qw422016, Data.TopBarQueryParams) + if e.UserCanDelete(*AuthUser) { //line messages.qtpl:294 - qw422016.N().S(`" target="iframe1" class="sysmsg f-white-clr">M</a>]</span>&nbsp;`) -//line messages.qtpl:294 - } -//line messages.qtpl:295 - if e.GroupID != nil { -//line messages.qtpl:295 - qw422016.N().S(`<span class="sysmsg">[<a href="`) -//line messages.qtpl:295 - qw422016.E().S(baseTopBarURL) + if !e.TooOldToDelete() { //line messages.qtpl:295 - qw422016.N().S(`?g=`) + if AuthUser.DisplayDeleteButton { //line messages.qtpl:295 - qw422016.E().S(e.Group.Name) -//line messages.qtpl:295 - streamunesc(qw422016, Data.TopBarQueryParams) -//line messages.qtpl:295 - qw422016.N().S(`" target="iframe1" class="sysmsg f-white-clr">`) -//line messages.qtpl:295 - qw422016.E().S(e.Group.Name) -//line messages.qtpl:295 - qw422016.N().S(`</a>]</span>&nbsp;`) -//line messages.qtpl:295 - } + qw422016.N().S(` <form method="post" action="/api/v1/chat/messages/delete/`) //line messages.qtpl:296 - if e.ToUserID != nil { + qw422016.E().S(e.UUID) //line messages.qtpl:296 - qw422016.N().S(` [`) + qw422016.N().S(`" class="d-inline"> + <input type="hidden" name="csrf" value="`) //line messages.qtpl:297 - streamfromUsername(qw422016, AuthUser, Data, e, baseTopBarURL) + qw422016.E().S(CSRF) //line messages.qtpl:297 - qw422016.N().S(` → -`) -//line messages.qtpl:299 - if e.ToUser.ID == AuthUser.ID { -//line messages.qtpl:299 - qw422016.N().S(`<span `) -//line messages.qtpl:299 - streamunesc(qw422016, e.ToUser.GenerateChatStyle()) -//line messages.qtpl:299 - qw422016.N().S(`>`) -//line messages.qtpl:299 - qw422016.E().S(e.ToUser.Username) -//line messages.qtpl:299 - qw422016.N().S(`</span>`) -//line messages.qtpl:299 - } else { -//line messages.qtpl:299 - qw422016.N().S(`<a `) -//line messages.qtpl:299 - streamunesc(qw422016, e.ToUser.GenerateChatStyle()) -//line messages.qtpl:299 - qw422016.N().S(` href="`) -//line messages.qtpl:299 - qw422016.E().S(baseTopBarURL) -//line messages.qtpl:299 - qw422016.N().S(`?pm=`) -//line messages.qtpl:299 - qw422016.E().S(e.ToUser.Username) -//line messages.qtpl:299 - qw422016.E().S(Data.TopBarQueryParams) -//line messages.qtpl:299 - qw422016.N().S(`" target="iframe1">`) -//line messages.qtpl:299 - qw422016.E().S(e.ToUser.Username) -//line messages.qtpl:299 - qw422016.N().S(`</a>`) -//line messages.qtpl:299 - } -//line messages.qtpl:299 - qw422016.N().S(`] - + qw422016.N().S(`" /> + <button class="mod-btn delete_msg_btn" title="delete"></button> + </form> `) //line messages.qtpl:300 - } else { + } //line messages.qtpl:301 - streamfromUsername(qw422016, AuthUser, Data, e, baseTopBarURL) + } else if (AuthUser.IsModerator() && e.TooOldToDelete() && e.UserID != AuthUser.ID) || AuthUser.IsAdmin || (e.Room.OwnerUserID != nil && *e.Room.OwnerUserID == AuthUser.ID) { +//line messages.qtpl:302 + if AuthUser.DisplayDeleteButton { //line messages.qtpl:302 - if !e.IsMe() { + qw422016.N().S(` <form method="post" action="/api/v1/chat/messages/delete/`) //line messages.qtpl:303 - if AuthUser.CanSeeHB() && (e.IsHellbanned || e.User.IsHellbanned) && (e.ToUserID == nil) { + qw422016.E().S(e.UUID) //line messages.qtpl:303 - qw422016.N().S(` <a href="`) + qw422016.N().S(`" class="d-inline"> + <input type="hidden" name="csrf" value="`) //line messages.qtpl:304 - qw422016.E().S(baseTopBarURL) + qw422016.E().S(CSRF) //line messages.qtpl:304 - qw422016.N().S(`?hbm=1`) -//line messages.qtpl:304 - streamunesc(qw422016, Data.TopBarQueryParams) -//line messages.qtpl:304 - qw422016.N().S(`" target="iframe1" class="f-def-clr">-</a> -`) -//line messages.qtpl:305 - } else { -//line messages.qtpl:305 - qw422016.N().S(` - + qw422016.N().S(`" /> + <button class="mod-btn delete_msg_btn f-orange-clr" title="delete"></button> + </form> `) //line messages.qtpl:307 - } + } //line messages.qtpl:308 - } + } else if AuthUser.IsModerator() { //line messages.qtpl:309 - } + if AuthUser.DisplayDeleteButton { //line messages.qtpl:309 - qw422016.N().S(` <span `) -//line messages.qtpl:310 - streamunesc(qw422016, e.User.GenerateChatStyle()) -//line messages.qtpl:310 - qw422016.N().S(`><span class="o-wrap">`) -//line messages.qtpl:310 - qw422016.N().S(unesc(e.MsgToDisplay())) -//line messages.qtpl:310 - qw422016.N().S(`</span></span> + qw422016.N().S(` <div class="spacer16"></div> `) //line messages.qtpl:311 - } -//line messages.qtpl:311 - qw422016.N().S(` </div> -`) + } +//line messages.qtpl:312 + } else { //line messages.qtpl:313 - } + if AuthUser.DisplayDeleteButton { //line messages.qtpl:313 - qw422016.N().S(` `) -//line messages.qtpl:314 - } -//line messages.qtpl:314 - qw422016.N().S(` - `) -//line messages.qtpl:315 - if len(Data.Messages) == 0 { + qw422016.N().S(` <div class="spacer16"></div> +`) //line messages.qtpl:315 - qw422016.N().S(` - <div id="no-msg"><em>No message yet</em></div> - `) -//line messages.qtpl:317 - } + } +//line messages.qtpl:316 + } //line messages.qtpl:317 - qw422016.N().S(` - </div> - - `) + if AuthUser.IsModerator() { +//line messages.qtpl:318 + if e.UserID != AuthUser.ID { +//line messages.qtpl:319 + if AuthUser.DisplayHellbanButton { //line messages.qtpl:320 - if !AuthUser.HideRightColumn { + if e.User.Username == NullUsername { //line messages.qtpl:320 - qw422016.N().S(` - <div id="rgt-pane"> - <div class="mb-20px"> - <div class="rgt-title">Inbox (<a href="/settings/inbox" target="_top"`) -//line messages.qtpl:323 - if Data.InboxCount > 0 { -//line messages.qtpl:323 - qw422016.N().S(`class="notif"`) -//line messages.qtpl:323 - } -//line messages.qtpl:323 - qw422016.N().S(`>`) + qw422016.N().S(` <div class="spacer16"></div> +`) +//line messages.qtpl:322 + } else { //line messages.qtpl:323 - qw422016.N().DL(Data.InboxCount) + if e.User.IsHellbanned { //line messages.qtpl:323 - qw422016.N().S(`</a>)</div> - </div> - <div class="mb-20px"> - <div class="rgt-title">Rooms:</div> + qw422016.N().S(` <form method="post" action="/api/v1/users/`) +//line messages.qtpl:324 + qw422016.E().S(e.UserID.String()) +//line messages.qtpl:324 + qw422016.N().S(`/unhellban" class="d-inline"> + <input type="hidden" name="csrf" value="`) +//line messages.qtpl:325 + qw422016.E().S(CSRF) +//line messages.qtpl:325 + qw422016.N().S(`" /> + <button class="mod-btn hb_btn f-orange-clr line-through" title="unhellban"></button> + </form> `) -//line messages.qtpl:327 - for _, e := range Data.OfficialRooms { //line messages.qtpl:328 - if e.Name == "club" { + } else { +//line messages.qtpl:328 + qw422016.N().S(` <form method="post" action="/api/v1/users/`) //line messages.qtpl:329 - if AuthUser.IsClubMember { + qw422016.E().S(e.UserID.String()) //line messages.qtpl:329 - qw422016.N().S(` <div><a href="/chat/club" target="_top"`) -//line messages.qtpl:330 - if e.IsUnread { + qw422016.N().S(`/hellban" class="d-inline"> + <input type="hidden" name="csrf" value="`) //line messages.qtpl:330 - qw422016.N().S(` class="unread_room"`) + qw422016.E().S(CSRF) //line messages.qtpl:330 - } -//line messages.qtpl:330 - qw422016.N().S(`>#club</a></div> + qw422016.N().S(`" /> + <button class="mod-btn hb_btn f-orange-clr" title="hellban"></button> + </form> `) -//line messages.qtpl:331 - } -//line messages.qtpl:332 - } else if e.Name == "moderators" { //line messages.qtpl:333 - if AuthUser.IsModerator() { -//line messages.qtpl:333 - qw422016.N().S(` <div><a href="/chat/moderators" target="_top"`) -//line messages.qtpl:334 - if e.IsUnread { -//line messages.qtpl:334 - qw422016.N().S(` class="unread_room"`) -//line messages.qtpl:334 - } + } //line messages.qtpl:334 - qw422016.N().S(`>#moderators</a></div> -`) + } //line messages.qtpl:335 - } + } //line messages.qtpl:336 - } else { + if AuthUser.DisplayKickButton { //line messages.qtpl:336 - qw422016.N().S(` <div><a href="/chat/`) -//line messages.qtpl:337 - qw422016.E().S(e.Name) -//line messages.qtpl:337 - qw422016.N().S(`" target="_top"`) -//line messages.qtpl:337 - if e.IsUnread { -//line messages.qtpl:337 - qw422016.N().S(` class="unread_room"`) -//line messages.qtpl:337 - } + qw422016.N().S(` <form method="post" action="/api/v1/users/`) //line messages.qtpl:337 - qw422016.N().S(`>#`) -//line messages.qtpl:337 - qw422016.E().S(e.Name) + qw422016.E().S(e.UserID.String()) //line messages.qtpl:337 - qw422016.N().S(`</a></div> -`) + qw422016.N().S(`/kick" class="d-inline"> + <input type="hidden" name="csrf" value="`) //line messages.qtpl:338 - } -//line messages.qtpl:339 - } -//line messages.qtpl:340 - if len(Data.SubscribedRooms) > 0 { -//line messages.qtpl:340 - qw422016.N().S(` <div class="mt-10px"></div> + qw422016.E().S(CSRF) +//line messages.qtpl:338 + qw422016.N().S(`" /> + <button class="mod-btn k_btn f-orange-clr" title="kick"></button> + </form> `) +//line messages.qtpl:341 + } //line messages.qtpl:342 - for _, e := range Data.SubscribedRooms { -//line messages.qtpl:342 - qw422016.N().S(` <div><a href="/chat/`) -//line messages.qtpl:343 - qw422016.E().S(e.Name) -//line messages.qtpl:343 - qw422016.N().S(`" target="_top"`) -//line messages.qtpl:343 - if e.IsUnread { -//line messages.qtpl:343 - qw422016.N().S(` class="unread_room"`) -//line messages.qtpl:343 - } -//line messages.qtpl:343 - qw422016.N().S(`>#`) + } else { //line messages.qtpl:343 - qw422016.E().S(e.Name) + if AuthUser.DisplayKickButton && AuthUser.DisplayHellbanButton { //line messages.qtpl:343 - qw422016.N().S(`</a></div> + qw422016.N().S(` <div class="spacer36"></div> `) -//line messages.qtpl:344 - } //line messages.qtpl:345 - } + } else if AuthUser.DisplayKickButton || AuthUser.DisplayHellbanButton { //line messages.qtpl:345 - qw422016.N().S(` <div class="mt-5px"><a href="/rooms" target="_top">[...]</a></div> - </div> - <div class="mb-20px"> - <div class="rgt-title">In this room:</div> + qw422016.N().S(` <div class="spacer16"></div> `) +//line messages.qtpl:347 + } +//line messages.qtpl:348 + } +//line messages.qtpl:349 + } //line messages.qtpl:350 - for _, e := range Data.Members { -//line messages.qtpl:350 - qw422016.N().S(` `) + } else { //line messages.qtpl:351 - StreamMember(qw422016, AuthUser, Data, e) + if Data.NbButtons == 3 { //line messages.qtpl:351 - qw422016.N().S(` -`) -//line messages.qtpl:352 - } -//line messages.qtpl:352 - qw422016.N().S(` </div> + qw422016.N().S(` <div class="spacer56"></div> `) -//line messages.qtpl:354 - if Data.VisibleMemberInChat || AuthUser.DisplayHellbanned { -//line messages.qtpl:354 - qw422016.N().S(` <div class="mb-30px"> +//line messages.qtpl:353 + } else if Data.NbButtons == 2 { +//line messages.qtpl:353 + qw422016.N().S(` <div class="spacer36"></div> `) -//line messages.qtpl:356 - if len(Data.MembersInChat) > 0 { -//line messages.qtpl:356 - qw422016.N().S(` <div class="rgt-title">In other rooms:</div> +//line messages.qtpl:355 + } else if Data.NbButtons == 1 { +//line messages.qtpl:355 + qw422016.N().S(` <div class="spacer16"></div> `) +//line messages.qtpl:357 + } //line messages.qtpl:358 - for _, e := range Data.MembersInChat { -//line messages.qtpl:358 - qw422016.N().S(` `) + } //line messages.qtpl:359 - StreamMember(qw422016, AuthUser, Data, e) + if AuthUser.GetDateFormat() != "" { //line messages.qtpl:359 - qw422016.N().S(` -`) + qw422016.N().S(` <a href="`) +//line messages.qtpl:360 + qw422016.E().S(baseTopBarURL) +//line messages.qtpl:360 + qw422016.N().S(`?quote=`) +//line messages.qtpl:360 + qw422016.E().S(e.UUID) +//line messages.qtpl:360 + streamunesc(qw422016, Data.TopBarQueryParams) +//line messages.qtpl:360 + qw422016.N().S(`" target="iframe1" class="date date-link" title="`) +//line messages.qtpl:360 + qw422016.E().S(e.CreatedAt.Format("01-02 15:04:05")) +//line messages.qtpl:360 + if *isFirstMsg { +//line messages.qtpl:360 + qw422016.N().S(` (`) +//line messages.qtpl:360 + qw422016.E().S(humanize.Time(e.CreatedAt)) +//line messages.qtpl:360 + qw422016.N().S(`)`) //line messages.qtpl:360 - } -//line messages.qtpl:361 } +//line messages.qtpl:360 + qw422016.N().S(`">`) +//line messages.qtpl:360 + qw422016.E().S(e.CreatedAt.Format(AuthUser.GetDateFormat())) +//line messages.qtpl:360 + qw422016.N().S(`</a> + `) //line messages.qtpl:361 - qw422016.N().S(` </div> + *isFirstMsg = false + +//line messages.qtpl:361 + qw422016.N().S(` `) -//line messages.qtpl:363 +//line messages.qtpl:362 } +//line messages.qtpl:362 + qw422016.N().S(` <a href="/u/`) //line messages.qtpl:363 - qw422016.N().S(` </div> + qw422016.E().S(e.GetProfile(AuthUser)) +//line messages.qtpl:363 + qw422016.N().S(`" target="_blank" class="f-def-clr">-</a> `) +//line messages.qtpl:364 + if e.System { +//line messages.qtpl:364 + qw422016.N().S(` <span class="sysmsg">`) //line messages.qtpl:365 - } -//line messages.qtpl:366 - if AuthUser.CollectMetadata { -//line messages.qtpl:366 - qw422016.N().S(` <div class="div_1"></div> - <div class="div_2"></div> - <div class="div_f0">a</div> + streamunesc(qw422016, e.Message) +//line messages.qtpl:365 + qw422016.N().S(`</span> `) +//line messages.qtpl:366 + } else { +//line messages.qtpl:367 + if e.Moderators { +//line messages.qtpl:367 + qw422016.N().S(`<span class="sysmsg">[<a href="`) +//line messages.qtpl:367 + qw422016.E().S(baseTopBarURL) +//line messages.qtpl:367 + qw422016.N().S(`?m=1`) +//line messages.qtpl:367 + streamunesc(qw422016, Data.TopBarQueryParams) +//line messages.qtpl:367 + qw422016.N().S(`" target="iframe1" class="sysmsg f-white-clr">M</a>]</span>&nbsp;`) +//line messages.qtpl:367 + } +//line messages.qtpl:368 + if e.GroupID != nil { +//line messages.qtpl:368 + qw422016.N().S(`<span class="sysmsg">[<a href="`) +//line messages.qtpl:368 + qw422016.E().S(baseTopBarURL) +//line messages.qtpl:368 + qw422016.N().S(`?g=`) +//line messages.qtpl:368 + qw422016.E().S(e.Group.Name) +//line messages.qtpl:368 + streamunesc(qw422016, Data.TopBarQueryParams) +//line messages.qtpl:368 + qw422016.N().S(`" target="iframe1" class="sysmsg f-white-clr">`) +//line messages.qtpl:368 + qw422016.E().S(e.Group.Name) +//line messages.qtpl:368 + qw422016.N().S(`</a>]</span>&nbsp;`) +//line messages.qtpl:368 + } +//line messages.qtpl:369 + if e.ToUserID != nil { +//line messages.qtpl:369 + qw422016.N().S(` [`) //line messages.qtpl:370 - } + streamfromUsername(qw422016, AuthUser, Data, e, baseTopBarURL) //line messages.qtpl:370 - qw422016.N().S(` </body> -</html> + qw422016.N().S(` → +`) +//line messages.qtpl:372 + if e.ToUser.ID == AuthUser.ID { +//line messages.qtpl:372 + qw422016.N().S(`<span `) +//line messages.qtpl:372 + streamunesc(qw422016, e.ToUser.GenerateChatStyle()) +//line messages.qtpl:372 + qw422016.N().S(`>`) +//line messages.qtpl:372 + qw422016.E().S(e.ToUser.Username) +//line messages.qtpl:372 + qw422016.N().S(`</span>`) +//line messages.qtpl:372 + } else { +//line messages.qtpl:372 + qw422016.N().S(`<a `) +//line messages.qtpl:372 + streamunesc(qw422016, e.ToUser.GenerateChatStyle()) +//line messages.qtpl:372 + qw422016.N().S(` href="`) +//line messages.qtpl:372 + qw422016.E().S(baseTopBarURL) +//line messages.qtpl:372 + qw422016.N().S(`?pm=`) +//line messages.qtpl:372 + qw422016.E().S(e.ToUser.Username) +//line messages.qtpl:372 + qw422016.E().S(Data.TopBarQueryParams) +//line messages.qtpl:372 + qw422016.N().S(`" target="iframe1">`) +//line messages.qtpl:372 + qw422016.E().S(e.ToUser.Username) +//line messages.qtpl:372 + qw422016.N().S(`</a>`) +//line messages.qtpl:372 + } +//line messages.qtpl:372 + qw422016.N().S(`] - `) //line messages.qtpl:373 + } else { +//line messages.qtpl:374 + streamfromUsername(qw422016, AuthUser, Data, e, baseTopBarURL) +//line messages.qtpl:375 + if !e.IsMe() { +//line messages.qtpl:376 + if AuthUser.CanSeeHB() && (e.IsHellbanned || e.User.IsHellbanned) && (e.ToUserID == nil) { +//line messages.qtpl:376 + qw422016.N().S(` <a href="`) +//line messages.qtpl:377 + qw422016.E().S(baseTopBarURL) +//line messages.qtpl:377 + qw422016.N().S(`?hbm=1`) +//line messages.qtpl:377 + streamunesc(qw422016, Data.TopBarQueryParams) +//line messages.qtpl:377 + qw422016.N().S(`" target="iframe1" class="f-def-clr">-</a> +`) +//line messages.qtpl:378 + } else { +//line messages.qtpl:378 + qw422016.N().S(` - +`) +//line messages.qtpl:380 + } +//line messages.qtpl:381 + } +//line messages.qtpl:382 + } +//line messages.qtpl:382 + qw422016.N().S(` <span `) +//line messages.qtpl:383 + streamunesc(qw422016, e.User.GenerateChatStyle()) +//line messages.qtpl:383 + qw422016.N().S(`><span class="o-wrap">`) +//line messages.qtpl:383 + qw422016.N().S(unesc(e.MsgToDisplay())) +//line messages.qtpl:383 + qw422016.N().S(`</span></span> +`) +//line messages.qtpl:384 + } +//line messages.qtpl:384 + qw422016.N().S(` </div> +`) +//line messages.qtpl:386 + } +//line messages.qtpl:387 } -//line messages.qtpl:373 -func WriteMessages(qq422016 qtio422016.Writer, VERSION, CSRF, NullUsername string, AuthUser *database.User, Data chatMessagesData) { -//line messages.qtpl:373 +//line messages.qtpl:387 +func WriteRenderMessage(qq422016 qtio422016.Writer, idx int, e database.ChatMessage, AuthUser *database.User, + Data ChatMessagesData, baseTopBarURL string, readMarkerRendered, isFirstMsg *bool, CSRF, NullUsername string) { +//line messages.qtpl:387 qw422016 := qt422016.AcquireWriter(qq422016) -//line messages.qtpl:373 - StreamMessages(qw422016, VERSION, CSRF, NullUsername, AuthUser, Data) -//line messages.qtpl:373 +//line messages.qtpl:387 + StreamRenderMessage(qw422016, idx, e, AuthUser, Data, baseTopBarURL, readMarkerRendered, isFirstMsg, CSRF, NullUsername) +//line messages.qtpl:387 qt422016.ReleaseWriter(qw422016) -//line messages.qtpl:373 +//line messages.qtpl:387 } -//line messages.qtpl:373 -func Messages(VERSION, CSRF, NullUsername string, AuthUser *database.User, Data chatMessagesData) string { -//line messages.qtpl:373 +//line messages.qtpl:387 +func RenderMessage(idx int, e database.ChatMessage, AuthUser *database.User, + Data ChatMessagesData, baseTopBarURL string, readMarkerRendered, isFirstMsg *bool, CSRF, NullUsername string) string { +//line messages.qtpl:387 qb422016 := qt422016.AcquireByteBuffer() -//line messages.qtpl:373 - WriteMessages(qb422016, VERSION, CSRF, NullUsername, AuthUser, Data) -//line messages.qtpl:373 +//line messages.qtpl:387 + WriteRenderMessage(qb422016, idx, e, AuthUser, Data, baseTopBarURL, readMarkerRendered, isFirstMsg, CSRF, NullUsername) +//line messages.qtpl:387 qs422016 := string(qb422016.B) -//line messages.qtpl:373 +//line messages.qtpl:387 qt422016.ReleaseByteBuffer(qb422016) -//line messages.qtpl:373 +//line messages.qtpl:387 return qs422016 -//line messages.qtpl:373 +//line messages.qtpl:387 } -//line messages.qtpl:377 -func StreamMember(qw422016 *qt422016.Writer, AuthUser *database.User, Data chatMessagesData, El managers.UserInfo) { -//line messages.qtpl:377 +//line messages.qtpl:390 +func StreamMember(qw422016 *qt422016.Writer, AuthUser *database.User, Data ChatMessagesData, El managers.UserInfo) { +//line messages.qtpl:390 qw422016.N().S(` `) -//line messages.qtpl:378 +//line messages.qtpl:391 baseTopBarURL := "/api/v1/chat/top-bar/" + Data.RoomName -//line messages.qtpl:379 +//line messages.qtpl:392 if El.Username == AuthUser.Username { -//line messages.qtpl:379 +//line messages.qtpl:392 qw422016.N().S(` <div> <span style="color: `) -//line messages.qtpl:381 +//line messages.qtpl:394 qw422016.E().S(El.Color) -//line messages.qtpl:381 +//line messages.qtpl:394 qw422016.N().S(`;">`) -//line messages.qtpl:381 +//line messages.qtpl:394 qw422016.E().S(El.Username) -//line messages.qtpl:381 +//line messages.qtpl:394 qw422016.N().S(`</span> `) -//line messages.qtpl:382 +//line messages.qtpl:395 if El.AfkIndicatorEnabled { -//line messages.qtpl:382 +//line messages.qtpl:395 qw422016.N().S(` <small class="afk-indicator">afk</small> `) -//line messages.qtpl:384 +//line messages.qtpl:397 } -//line messages.qtpl:384 +//line messages.qtpl:397 qw422016.N().S(` </div> `) -//line messages.qtpl:386 +//line messages.qtpl:399 } else { -//line messages.qtpl:387 +//line messages.qtpl:400 if !El.IsHellbanned || AuthUser.ID == El.UserID || (El.IsHellbanned && AuthUser.IsHellbanned) || AuthUser.DisplayHellbanned { -//line messages.qtpl:387 +//line messages.qtpl:400 qw422016.N().S(` <div> `) -//line messages.qtpl:389 +//line messages.qtpl:402 tagType := "tag" -//line messages.qtpl:390 +//line messages.qtpl:403 if AuthUser.CanSeeHB() && El.IsHellbanned { -//line messages.qtpl:391 +//line messages.qtpl:404 tagType = "htag" -//line messages.qtpl:392 +//line messages.qtpl:405 } -//line messages.qtpl:393 +//line messages.qtpl:406 qw422016.N().S(`<a href="`) -//line messages.qtpl:394 +//line messages.qtpl:407 qw422016.E().S(baseTopBarURL) -//line messages.qtpl:394 +//line messages.qtpl:407 qw422016.N().S(`?`) -//line messages.qtpl:394 +//line messages.qtpl:407 qw422016.E().S(tagType) -//line messages.qtpl:394 +//line messages.qtpl:407 qw422016.N().S(`=`) -//line messages.qtpl:394 +//line messages.qtpl:407 qw422016.E().S(El.Username) -//line messages.qtpl:394 +//line messages.qtpl:407 streamunesc(qw422016, Data.TopBarQueryParams) -//line messages.qtpl:394 +//line messages.qtpl:407 qw422016.N().S(`"target="iframe1"`) -//line messages.qtpl:396 +//line messages.qtpl:409 if El.IsHellbanned && AuthUser.DisplayHellbanned { -//line messages.qtpl:396 +//line messages.qtpl:409 qw422016.N().S(`class="hb-row"`) -//line messages.qtpl:396 +//line messages.qtpl:409 } -//line messages.qtpl:396 +//line messages.qtpl:409 qw422016.N().S(`style="color:`) -//line messages.qtpl:397 +//line messages.qtpl:410 qw422016.E().S(El.Color) -//line messages.qtpl:397 +//line messages.qtpl:410 qw422016.N().S(`;">`) -//line messages.qtpl:397 +//line messages.qtpl:410 qw422016.E().S(string(El.Username[0])) -//line messages.qtpl:397 +//line messages.qtpl:410 qw422016.N().S(`</a><a href="`) -//line messages.qtpl:398 +//line messages.qtpl:411 qw422016.E().S(baseTopBarURL) -//line messages.qtpl:398 +//line messages.qtpl:411 qw422016.N().S(`?pm=`) -//line messages.qtpl:398 +//line messages.qtpl:411 qw422016.E().S(El.Username) -//line messages.qtpl:398 +//line messages.qtpl:411 streamunesc(qw422016, Data.TopBarQueryParams) -//line messages.qtpl:398 +//line messages.qtpl:411 qw422016.N().S(`"target="iframe1"`) -//line messages.qtpl:400 +//line messages.qtpl:413 if El.IsHellbanned && AuthUser.DisplayHellbanned { -//line messages.qtpl:400 +//line messages.qtpl:413 qw422016.N().S(`class="hb-row"`) -//line messages.qtpl:400 +//line messages.qtpl:413 } -//line messages.qtpl:400 +//line messages.qtpl:413 qw422016.N().S(`style="color:`) -//line messages.qtpl:401 +//line messages.qtpl:414 qw422016.E().S(El.Color) -//line messages.qtpl:401 +//line messages.qtpl:414 qw422016.N().S(`;">`) -//line messages.qtpl:401 +//line messages.qtpl:414 qw422016.E().S(string(El.Username[1 : len(El.Username)-1])) -//line messages.qtpl:401 +//line messages.qtpl:414 qw422016.N().S(`</a><a href="/u/`) -//line messages.qtpl:402 +//line messages.qtpl:415 qw422016.E().S(El.Username) -//line messages.qtpl:402 +//line messages.qtpl:415 qw422016.N().S(`"rel="noopener noreferrer" target="_blank"`) -//line messages.qtpl:404 +//line messages.qtpl:417 if El.IsHellbanned && AuthUser.DisplayHellbanned { -//line messages.qtpl:404 +//line messages.qtpl:417 qw422016.N().S(`class="hb-row"`) -//line messages.qtpl:404 +//line messages.qtpl:417 } -//line messages.qtpl:404 +//line messages.qtpl:417 qw422016.N().S(`style="color:`) -//line messages.qtpl:405 +//line messages.qtpl:418 qw422016.E().S(El.Color) -//line messages.qtpl:405 +//line messages.qtpl:418 qw422016.N().S(`;">`) -//line messages.qtpl:405 +//line messages.qtpl:418 qw422016.E().S(string(El.Username[len(El.Username)-1])) -//line messages.qtpl:405 +//line messages.qtpl:418 qw422016.N().S(`</a>`) -//line messages.qtpl:407 +//line messages.qtpl:420 if El.AfkIndicatorEnabled { -//line messages.qtpl:407 +//line messages.qtpl:420 qw422016.N().S(` <small class="afk-indicator">afk</small> `) -//line messages.qtpl:409 +//line messages.qtpl:422 } -//line messages.qtpl:409 +//line messages.qtpl:422 qw422016.N().S(` </div> `) -//line messages.qtpl:411 +//line messages.qtpl:424 } -//line messages.qtpl:412 +//line messages.qtpl:425 } -//line messages.qtpl:413 +//line messages.qtpl:426 } -//line messages.qtpl:413 -func WriteMember(qq422016 qtio422016.Writer, AuthUser *database.User, Data chatMessagesData, El managers.UserInfo) { -//line messages.qtpl:413 +//line messages.qtpl:426 +func WriteMember(qq422016 qtio422016.Writer, AuthUser *database.User, Data ChatMessagesData, El managers.UserInfo) { +//line messages.qtpl:426 qw422016 := qt422016.AcquireWriter(qq422016) -//line messages.qtpl:413 +//line messages.qtpl:426 StreamMember(qw422016, AuthUser, Data, El) -//line messages.qtpl:413 +//line messages.qtpl:426 qt422016.ReleaseWriter(qw422016) -//line messages.qtpl:413 +//line messages.qtpl:426 } -//line messages.qtpl:413 -func Member(AuthUser *database.User, Data chatMessagesData, El managers.UserInfo) string { -//line messages.qtpl:413 +//line messages.qtpl:426 +func Member(AuthUser *database.User, Data ChatMessagesData, El managers.UserInfo) string { +//line messages.qtpl:426 qb422016 := qt422016.AcquireByteBuffer() -//line messages.qtpl:413 +//line messages.qtpl:426 WriteMember(qb422016, AuthUser, Data, El) -//line messages.qtpl:413 +//line messages.qtpl:426 qs422016 := string(qb422016.B) -//line messages.qtpl:413 +//line messages.qtpl:426 qt422016.ReleaseByteBuffer(qb422016) -//line messages.qtpl:413 +//line messages.qtpl:426 return qs422016 -//line messages.qtpl:413 +//line messages.qtpl:426 } -//line messages.qtpl:416 -func streamfromUsername(qw422016 *qt422016.Writer, AuthUser *database.User, Data chatMessagesData, El database.ChatMessage, baseTopBarURL string) { -//line messages.qtpl:417 +//line messages.qtpl:429 +func streamfromUsername(qw422016 *qt422016.Writer, AuthUser *database.User, Data ChatMessagesData, El database.ChatMessage, baseTopBarURL string) { +//line messages.qtpl:430 tagType := "tag" -//line messages.qtpl:418 +//line messages.qtpl:431 if El.ToUserID != nil { -//line messages.qtpl:419 +//line messages.qtpl:432 tagType = "pm" -//line messages.qtpl:420 +//line messages.qtpl:433 } else if AuthUser.CanSeeHB() && (El.IsHellbanned || El.User.IsHellbanned) { -//line messages.qtpl:421 +//line messages.qtpl:434 tagType = "htag" -//line messages.qtpl:422 +//line messages.qtpl:435 } else if AuthUser.IsModerator() && El.Moderators { -//line messages.qtpl:423 +//line messages.qtpl:436 tagType = "mtag" -//line messages.qtpl:424 +//line messages.qtpl:437 } -//line messages.qtpl:425 +//line messages.qtpl:438 if El.User.ID == AuthUser.ID { -//line messages.qtpl:426 +//line messages.qtpl:439 if El.CanBeEdited() { -//line messages.qtpl:426 +//line messages.qtpl:439 qw422016.N().S(`<a `) -//line messages.qtpl:426 +//line messages.qtpl:439 streamunesc(qw422016, El.User.GenerateChatStyle()) -//line messages.qtpl:426 +//line messages.qtpl:439 qw422016.N().S(` href="`) -//line messages.qtpl:426 +//line messages.qtpl:439 qw422016.E().S(baseTopBarURL) -//line messages.qtpl:426 +//line messages.qtpl:439 qw422016.N().S(`?e=`) -//line messages.qtpl:426 +//line messages.qtpl:439 qw422016.E().S(El.CreatedAt.Format("15:04:05")) -//line messages.qtpl:426 +//line messages.qtpl:439 streamunesc(qw422016, Data.TopBarQueryParams) -//line messages.qtpl:426 +//line messages.qtpl:439 qw422016.N().S(`" target="iframe1">`) -//line messages.qtpl:426 +//line messages.qtpl:439 qw422016.E().S(El.User.Username) -//line messages.qtpl:426 +//line messages.qtpl:439 qw422016.N().S(`</a>`) -//line messages.qtpl:426 +//line messages.qtpl:439 } else { -//line messages.qtpl:426 +//line messages.qtpl:439 qw422016.N().S(`<span `) -//line messages.qtpl:426 +//line messages.qtpl:439 streamunesc(qw422016, El.User.GenerateChatStyle()) -//line messages.qtpl:426 +//line messages.qtpl:439 qw422016.N().S(`>`) -//line messages.qtpl:426 +//line messages.qtpl:439 qw422016.E().S(El.User.Username) -//line messages.qtpl:426 +//line messages.qtpl:439 qw422016.N().S(`</span>`) -//line messages.qtpl:426 +//line messages.qtpl:439 } -//line messages.qtpl:427 +//line messages.qtpl:440 } else { -//line messages.qtpl:427 +//line messages.qtpl:440 qw422016.N().S(`<a `) -//line messages.qtpl:427 +//line messages.qtpl:440 streamunesc(qw422016, El.User.GenerateChatStyle()) -//line messages.qtpl:427 +//line messages.qtpl:440 qw422016.N().S(` href="`) -//line messages.qtpl:427 +//line messages.qtpl:440 qw422016.E().S(baseTopBarURL) -//line messages.qtpl:427 +//line messages.qtpl:440 qw422016.N().S(`?`) -//line messages.qtpl:427 +//line messages.qtpl:440 qw422016.E().S(tagType) -//line messages.qtpl:427 +//line messages.qtpl:440 qw422016.N().S(`=`) -//line messages.qtpl:427 +//line messages.qtpl:440 qw422016.E().S(El.User.Username) -//line messages.qtpl:427 +//line messages.qtpl:440 streamunesc(qw422016, Data.TopBarQueryParams) -//line messages.qtpl:427 +//line messages.qtpl:440 qw422016.N().S(`" target="iframe1">`) -//line messages.qtpl:427 +//line messages.qtpl:440 qw422016.E().S(El.User.Username) -//line messages.qtpl:427 +//line messages.qtpl:440 qw422016.N().S(`</a>`) -//line messages.qtpl:427 +//line messages.qtpl:440 } -//line messages.qtpl:428 +//line messages.qtpl:441 } -//line messages.qtpl:428 -func writefromUsername(qq422016 qtio422016.Writer, AuthUser *database.User, Data chatMessagesData, El database.ChatMessage, baseTopBarURL string) { -//line messages.qtpl:428 +//line messages.qtpl:441 +func writefromUsername(qq422016 qtio422016.Writer, AuthUser *database.User, Data ChatMessagesData, El database.ChatMessage, baseTopBarURL string) { +//line messages.qtpl:441 qw422016 := qt422016.AcquireWriter(qq422016) -//line messages.qtpl:428 +//line messages.qtpl:441 streamfromUsername(qw422016, AuthUser, Data, El, baseTopBarURL) -//line messages.qtpl:428 +//line messages.qtpl:441 qt422016.ReleaseWriter(qw422016) -//line messages.qtpl:428 +//line messages.qtpl:441 } -//line messages.qtpl:428 -func fromUsername(AuthUser *database.User, Data chatMessagesData, El database.ChatMessage, baseTopBarURL string) string { -//line messages.qtpl:428 +//line messages.qtpl:441 +func fromUsername(AuthUser *database.User, Data ChatMessagesData, El database.ChatMessage, baseTopBarURL string) string { +//line messages.qtpl:441 qb422016 := qt422016.AcquireByteBuffer() -//line messages.qtpl:428 +//line messages.qtpl:441 writefromUsername(qb422016, AuthUser, Data, El, baseTopBarURL) -//line messages.qtpl:428 +//line messages.qtpl:441 qs422016 := string(qb422016.B) -//line messages.qtpl:428 +//line messages.qtpl:441 qt422016.ReleaseByteBuffer(qb422016) -//line messages.qtpl:428 +//line messages.qtpl:441 return qs422016 -//line messages.qtpl:428 +//line messages.qtpl:441 } diff --git a/pkg/web/handlers/handlers.go b/pkg/web/handlers/handlers.go @@ -4874,3 +4874,122 @@ Loop: } return nil } + +func ChatStreamHandler(c echo.Context) error { + db := c.Get("database").(*database.DkfDB) + authUser := c.Get("authUser").(*database.User) + + roomName := c.Param("roomName") + room, err := db.GetChatRoomByName(roomName) + if err != nil { + return c.Redirect(http.StatusFound, "/") + } + + quit := make(chan bool) + quit1 := make(chan bool) + + // Listen to the closing of HTTP connection via CloseNotifier + notify := c.Request().Context().Done() + utils.SGo(func() { + select { + case <-notify: + case <-quit1: + } + close(quit) + }) + + notify1 := make(chan os.Signal) + signal.Notify(notify1, os.Interrupt) + utils.SGo(func() { + select { + case <-notify1: + case <-quit: + } + close(quit1) + }) + + c.Response().Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8) + c.Response().WriteHeader(http.StatusOK) + c.Response().Header().Set("Transfer-Encoding", "chunked") + c.Response().Header().Set("Connection", "keep-alive") + + chatQueryParams := "" + _, _ = c.Response().Write([]byte(fmt.Sprintf(` +<style> +#chat-top-bar { + border: 0; + height: 57px; + width: 800px; +} +.container-fluid { + width: 800px; +} +</style> +<div class="container-fluid"> + <iframe id="chat-top-bar" name="iframe1" src="/api/v1/chat/top-bar/` + room.Name + chatQueryParams + `" sandbox="allow-forms allow-scripts allow-same-origin allow-top-navigation-by-user-activation"></iframe> +</div> +`))) + + _, _ = c.Response().Write([]byte(cssReset)) + data := v1.ChatMessagesData{} + data.RoomName = room.Name + _, _ = c.Response().Write([]byte(v1.GenerateStyle(authUser, data))) + _, _ = c.Response().Write([]byte(fmt.Sprintf(`<div style="display:flex;flex-direction:column-reverse;">`))) + c.Response().Flush() + + csrf, _ := c.Get("csrf").(string) + pmOnlyQuery := dutils.DoParsePmDisplayMode(c.QueryParam("pmonly")) + mentionsOnlyQuery := utils.DoParseBool(c.QueryParam("mentionsOnly")) + displayHellbanned := authUser.DisplayHellbanned || authUser.IsHellbanned + displayIgnoredMessages := false + msgs, _ := db.GetChatMessages(room.ID, authUser.Username, authUser.ID, pmOnlyQuery, mentionsOnlyQuery, displayHellbanned, authUser.DisplayIgnored, authUser.DisplayModerators, displayIgnoredMessages) + data.Messages = msgs + _, _ = c.Response().Write([]byte("<div>" + v1.RenderMessages(authUser, data, csrf, config.NullUsername) + "</div>")) + c.Response().Flush() + + authorizedChannels := make([]string, 0) + authorizedChannels = append(authorizedChannels, "room_"+utils.FormatInt64(int64(room.ID))) + sub := database.MsgPubSub.Subscribe(authorizedChannels) + defer sub.Close() + + i := 0 +Loop: + for { + select { + case <-quit: + break Loop + case <-quit1: + break Loop + default: + } + + _, msg, err := sub.ReceiveTimeout(1 * time.Second) + if err != nil { + continue + } + + i++ + + user, _ := db.GetUserByID(msg.UserID) + msg.User = user + if msg.ToUserID != nil { + toUser, _ := db.GetUserByID(*msg.ToUserID) + msg.ToUser = &toUser + if user.ID != authUser.ID && toUser.ID != authUser.ID { + continue + } + } + baseTopBarURL := "" + readMarkerRendered := true + isFirstMsg := false + s := v1.RenderMessage(1, *msg, authUser, data, baseTopBarURL, &readMarkerRendered, &isFirstMsg, csrf, config.NullUsername) + _, _ = c.Response().Write([]byte(fmt.Sprintf(`%s`, s))) + c.Response().Flush() + + // Refresh the page to prevent having it growing infinitely bigger + if i == 5000 { + _, _ = c.Response().Write([]byte(fmt.Sprintf(`<meta http-equiv="refresh" content="0">`))) + } + } + return nil +} diff --git a/pkg/web/middlewares/middlewares.go b/pkg/web/middlewares/middlewares.go @@ -31,6 +31,7 @@ var GzipMiddleware = middleware.GzipWithConfig( c.Path() == "/vip/downloads/:filename" || c.Path() == "/vip/challenges/re-1/:filename" || c.Path() == "/chess/:key" || + c.Path() == "/chat/:roomName/stream" || c.Path() == "/uploads/:filename" || c.Path() == "/" { return true diff --git a/pkg/web/web.go b/pkg/web/web.go @@ -211,6 +211,7 @@ func getMainServer(db *database.DkfDB, i18nBundle *i18n.Bundle, renderer *tmp.Te authGroup.GET("/chat/help", handlers.ChatHelpHandler) authGroup.GET("/chat/create-room", handlers.ChatCreateRoomHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2)) authGroup.POST("/chat/create-room", handlers.ChatCreateRoomHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2)) + authGroup.GET("/chat/:roomName/stream", handlers.ChatStreamHandler) authGroup.GET("/chat/:roomName/archive", handlers.ChatArchiveHandler) authGroup.GET("/chat/:roomName/delete", handlers.ChatDeleteHandler) authGroup.POST("/chat/:roomName/delete", handlers.ChatDeleteHandler)