0

Merge remote-tracking branch 'origin/develop' into webv2

This commit is contained in:
Gabe Kangas 2022-11-29 16:37:29 -08:00
commit 0ecaf11a25
No known key found for this signature in database
GPG Key ID: 4345B2060657F330
12 changed files with 627 additions and 468 deletions

View File

@ -18,7 +18,12 @@ func handleUndoInboxRequest(c context.Context, activity vocab.ActivityStreamsUnd
return err
}
} else {
log.Traceln("Undo", iter.GetType().GetTypeName(), "ignored")
t := iter.GetType()
if t != nil {
log.Traceln("Undo", t.GetTypeName(), "ignored")
} else {
log.Traceln("Undo (no type) ignored")
}
return nil
}
}

View File

@ -5,11 +5,11 @@
"requires": true,
"dependencies": {
"@babel/runtime": {
"version": "7.19.4",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.4.tgz",
"integrity": "sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==",
"version": "7.20.6",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.6.tgz",
"integrity": "sha512-Q+8MqP7TiHMWzSfwiJwXCjyf4GYA4Dgw3emg/7xmwsdLJOZUp+nMqcOwOzzYheuM1rhDu8FSj2l0aoMygEuXuA==",
"requires": {
"regenerator-runtime": "^0.13.4"
"regenerator-runtime": "^0.13.11"
}
},
"@fortawesome/fontawesome-common-types": {
@ -192,9 +192,9 @@
}
},
"@xmldom/xmldom": {
"version": "0.7.6",
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.6.tgz",
"integrity": "sha512-HHXP9hskkFQHy8QxxUXkS7946FFIhYVfGqsk0WLwllmexN9x/+R4UBLvurHEuyXRfVEObVR8APuQehykLviwSQ=="
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.9.tgz",
"integrity": "sha512-yceMpm/xd4W2a85iqZyO09gTnHvXF6pyiWjD2jcOJs7hRoZtNNOO1eJlhHj1ixA+xip2hOyGn+LgcvLCMo5zXA=="
},
"acorn": {
"version": "7.4.1",
@ -242,9 +242,9 @@
}
},
"anymatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true,
"requires": {
"normalize-path": "^3.0.0",
@ -350,9 +350,9 @@
}
},
"caniuse-lite": {
"version": "1.0.30001423",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001423.tgz",
"integrity": "sha512-09iwWGOlifvE1XuHokFMP7eR38a0JnajoyL3/i87c8ZjRWRrdKo1fqjNfugfBD0UDBIOz0U+jtNhJ0EPm1VleQ=="
"version": "1.0.30001434",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz",
"integrity": "sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA=="
},
"chalk": {
"version": "4.1.2",
@ -527,25 +527,25 @@
}
},
"cssnano-preset-default": {
"version": "5.2.12",
"resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.12.tgz",
"integrity": "sha512-OyCBTZi+PXgylz9HAA5kHyoYhfGcYdwFmyaJzWnzxuGRtnMw/kR6ilW9XzlzlRAtB6PLT/r+prYgkef7hngFew==",
"version": "5.2.13",
"resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.13.tgz",
"integrity": "sha512-PX7sQ4Pb+UtOWuz8A1d+Rbi+WimBIxJTRyBdgGp1J75VU0r/HFQeLnMYgHiCAp6AR4rqrc7Y4R+1Rjk3KJz6DQ==",
"dev": true,
"requires": {
"css-declaration-sorter": "^6.3.0",
"css-declaration-sorter": "^6.3.1",
"cssnano-utils": "^3.1.0",
"postcss-calc": "^8.2.3",
"postcss-colormin": "^5.3.0",
"postcss-convert-values": "^5.1.2",
"postcss-convert-values": "^5.1.3",
"postcss-discard-comments": "^5.1.2",
"postcss-discard-duplicates": "^5.1.0",
"postcss-discard-empty": "^5.1.1",
"postcss-discard-overridden": "^5.1.0",
"postcss-merge-longhand": "^5.1.6",
"postcss-merge-rules": "^5.1.2",
"postcss-merge-longhand": "^5.1.7",
"postcss-merge-rules": "^5.1.3",
"postcss-minify-font-values": "^5.1.0",
"postcss-minify-gradients": "^5.1.1",
"postcss-minify-params": "^5.1.3",
"postcss-minify-params": "^5.1.4",
"postcss-minify-selectors": "^5.2.1",
"postcss-normalize-charset": "^5.1.0",
"postcss-normalize-display-values": "^5.1.0",
@ -553,11 +553,11 @@
"postcss-normalize-repeat-style": "^5.1.1",
"postcss-normalize-string": "^5.1.0",
"postcss-normalize-timing-functions": "^5.1.0",
"postcss-normalize-unicode": "^5.1.0",
"postcss-normalize-unicode": "^5.1.1",
"postcss-normalize-url": "^5.1.0",
"postcss-normalize-whitespace": "^5.1.1",
"postcss-ordered-values": "^5.1.3",
"postcss-reduce-initial": "^5.1.0",
"postcss-reduce-initial": "^5.1.1",
"postcss-reduce-transforms": "^5.1.0",
"postcss-svgo": "^5.1.0",
"postcss-unique-selectors": "^5.1.1"
@ -856,9 +856,9 @@
}
},
"ignore": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
"integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz",
"integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==",
"dev": true
},
"individual": {
@ -1263,12 +1263,12 @@
}
},
"postcss-convert-values": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.2.tgz",
"integrity": "sha512-c6Hzc4GAv95B7suy4udszX9Zy4ETyMCgFPUDtWjdFTKH1SE9eFY/jEpHSwTH1QPuwxHpWslhckUQWbNRM4ho5g==",
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz",
"integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==",
"dev": true,
"requires": {
"browserslist": "^4.20.3",
"browserslist": "^4.21.4",
"postcss-value-parser": "^4.2.0"
}
},
@ -1396,22 +1396,22 @@
}
},
"postcss-merge-longhand": {
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.6.tgz",
"integrity": "sha512-6C/UGF/3T5OE2CEbOuX7iNO63dnvqhGZeUnKkDeifebY0XqkkvrctYSZurpNE902LDf2yKwwPFgotnfSoPhQiw==",
"version": "5.1.7",
"resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz",
"integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==",
"dev": true,
"requires": {
"postcss-value-parser": "^4.2.0",
"stylehacks": "^5.1.0"
"stylehacks": "^5.1.1"
}
},
"postcss-merge-rules": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.2.tgz",
"integrity": "sha512-zKMUlnw+zYCWoPN6yhPjtcEdlJaMUZ0WyVcxTAmw3lkkN/NDMRkOkiuctQEoWAOvH7twaxUUdvBWl0d4+hifRQ==",
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.3.tgz",
"integrity": "sha512-LbLd7uFC00vpOuMvyZop8+vvhnfRGpp2S+IMQKeuOZZapPRY4SMq5ErjQeHbHsjCUgJkRNrlU+LmxsKIqPKQlA==",
"dev": true,
"requires": {
"browserslist": "^4.16.6",
"browserslist": "^4.21.4",
"caniuse-api": "^3.0.0",
"cssnano-utils": "^3.1.0",
"postcss-selector-parser": "^6.0.5"
@ -1438,12 +1438,12 @@
}
},
"postcss-minify-params": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.3.tgz",
"integrity": "sha512-bkzpWcjykkqIujNL+EVEPOlLYi/eZ050oImVtHU7b4lFS82jPnsCb44gvC6pxaNt38Els3jWYDHTjHKf0koTgg==",
"version": "5.1.4",
"resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz",
"integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==",
"dev": true,
"requires": {
"browserslist": "^4.16.6",
"browserslist": "^4.21.4",
"cssnano-utils": "^3.1.0",
"postcss-value-parser": "^4.2.0"
}
@ -1529,12 +1529,12 @@
}
},
"postcss-normalize-unicode": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.0.tgz",
"integrity": "sha512-J6M3MizAAZ2dOdSjy2caayJLQT8E8K9XjLce8AUQMwOrCvjCHv24aLC/Lps1R1ylOfol5VIDMaM/Lo9NGlk1SQ==",
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz",
"integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==",
"dev": true,
"requires": {
"browserslist": "^4.16.6",
"browserslist": "^4.21.4",
"postcss-value-parser": "^4.2.0"
}
},
@ -1568,12 +1568,12 @@
}
},
"postcss-reduce-initial": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.0.tgz",
"integrity": "sha512-5OgTUviz0aeH6MtBjHfbr57tml13PuedK/Ecg8szzd4XRMbYxH4572JFG067z+FqBIf6Zp/d+0581glkvvWMFw==",
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.1.tgz",
"integrity": "sha512-//jeDqWcHPuXGZLoolFrUXBDyuEGbr9S2rMo19bkTIjBQ4PqkaO+oI8wua5BOUxpfi97i3PCoInsiFIEBfkm9w==",
"dev": true,
"requires": {
"browserslist": "^4.16.6",
"browserslist": "^4.21.4",
"caniuse-api": "^3.0.0"
}
},
@ -1605,9 +1605,9 @@
}
},
"postcss-selector-parser": {
"version": "6.0.10",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
"integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==",
"version": "6.0.11",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz",
"integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==",
"requires": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@ -1746,9 +1746,9 @@
}
},
"regenerator-runtime": {
"version": "0.13.10",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz",
"integrity": "sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw=="
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
},
"require-directory": {
"version": "2.1.1",
@ -1862,12 +1862,12 @@
}
},
"stylehacks": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.0.tgz",
"integrity": "sha512-SzLmvHQTrIWfSgljkQCw2++C9+Ne91d/6Sp92I8c5uHTcy/PgeHamwITIbBW9wnFTY/3ZfSXR9HIL6Ikqmcu6Q==",
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz",
"integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==",
"dev": true,
"requires": {
"browserslist": "^4.16.6",
"browserslist": "^4.21.4",
"postcss-selector-parser": "^6.0.4"
}
},
@ -2050,9 +2050,9 @@
}
},
"tslib": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
"integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA=="
},
"twemoji": {
"version": "12.1.6",
@ -2194,9 +2194,9 @@
"dev": true
},
"yargs": {
"version": "17.6.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz",
"integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==",
"version": "17.6.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz",
"integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==",
"dev": true,
"requires": {
"cliui": "^8.0.1",
@ -2205,7 +2205,7 @@
"require-directory": "^2.1.1",
"string-width": "^4.2.3",
"y18n": "^5.0.5",
"yargs-parser": "^21.0.0"
"yargs-parser": "^21.1.1"
}
},
"yargs-parser": {

View File

@ -3,7 +3,6 @@ package chat
import (
"context"
"database/sql"
"fmt"
"strings"
"time"
@ -209,20 +208,14 @@ type rowData struct {
userType *string
}
func getChat(query string) []interface{} {
func getChat(rows *sql.Rows) ([]interface{}, error) {
history := make([]interface{}, 0)
rows, err := _datastore.DB.Query(query)
if err != nil || rows.Err() != nil {
log.Errorln("error fetching chat history", err)
return history
}
defer rows.Close()
for rows.Next() {
row := rowData{}
// Convert a database row into a chat event
if err = rows.Scan(
if err := rows.Scan(
&row.id,
&row.userID,
&row.body,
@ -243,9 +236,7 @@ func getChat(query string) []interface{} {
&row.userScopes,
&row.userType,
); err != nil {
log.Errorln(err)
log.Errorln("There is a problem converting query to chat objects. Please report this:", query)
break
return nil, err
}
var message interface{}
@ -268,7 +259,7 @@ func getChat(query string) []interface{} {
history = append(history, message)
}
return history
return history, nil
}
var _historyCache *[]interface{}
@ -279,20 +270,87 @@ func GetChatModerationHistory() []interface{} {
return *_historyCache
}
tx, err := _datastore.DB.Begin()
if err != nil {
log.Errorln("error fetching chat moderation history", err)
return nil
}
defer tx.Rollback() // nolint
// Get all messages regardless of visibility
query := "SELECT messages.id, user_id, body, title, subtitle, image, link, eventType, hidden_at, timestamp, display_name, display_color, created_at, disabled_at, previous_names, namechanged_at, authenticated_at, scopes, type FROM messages INNER JOIN users ON messages.user_id = users.id ORDER BY timestamp DESC"
result := getChat(query)
stmt, err := tx.Prepare(query)
if err != nil {
log.Errorln("error fetching chat moderation history", err)
return nil
}
rows, err := stmt.Query()
if err != nil {
log.Errorln("error fetching chat moderation history", err)
return nil
}
defer stmt.Close()
defer rows.Close()
result, err := getChat(rows)
if err != nil {
log.Errorln(err)
log.Errorln("There is a problem enumerating chat message rows. Please report this:", query)
return nil
}
_historyCache = &result
if err = tx.Commit(); err != nil {
log.Errorln("error fetching chat moderation history", err)
return nil
}
return result
}
// GetChatHistory will return all the chat messages suitable for returning as user-facing chat history.
func GetChatHistory() []interface{} {
tx, err := _datastore.DB.Begin()
if err != nil {
log.Errorln("error fetching chat history", err)
return nil
}
defer tx.Rollback() // nolint
// Get all visible messages
query := fmt.Sprintf("SELECT messages.id, messages.user_id, messages.body, messages.title, messages.subtitle, messages.image, messages.link, messages.eventType, messages.hidden_at, messages.timestamp, users.display_name, users.display_color, users.created_at, users.disabled_at, users.previous_names, users.namechanged_at, users.authenticated_at, users.scopes, users.type FROM users JOIN messages ON users.id = messages.user_id WHERE hidden_at IS NULL AND disabled_at IS NULL ORDER BY timestamp DESC LIMIT %d", maxBacklogNumber)
m := getChat(query)
query := "SELECT messages.id, messages.user_id, messages.body, messages.title, messages.subtitle, messages.image, messages.link, messages.eventType, messages.hidden_at, messages.timestamp, users.display_name, users.display_color, users.created_at, users.disabled_at, users.previous_names, users.namechanged_at, users.authenticated_at, users.scopes, users.type FROM users JOIN messages ON users.id = messages.user_id WHERE hidden_at IS NULL AND disabled_at IS NULL ORDER BY timestamp DESC LIMIT ?"
stmt, err := tx.Prepare(query)
if err != nil {
log.Errorln("error fetching chat history", err)
return nil
}
rows, err := stmt.Query(maxBacklogNumber)
if err != nil {
log.Errorln("error fetching chat history", err)
return nil
}
defer stmt.Close()
defer rows.Close()
m, err := getChat(rows)
if err != nil {
log.Errorln(err)
log.Errorln("There is a problem enumerating chat message rows. Please report this:", query)
return nil
}
if err = tx.Commit(); err != nil {
log.Errorln("error fetching chat history", err)
return nil
}
// Invert order of messages
for i, j := 0, len(m)-1; i < j; i, j = i+1, j-1 {
@ -332,10 +390,39 @@ func SetMessageVisibilityForUserID(userID string, visible bool) error {
_historyCache = nil
}()
tx, err := _datastore.DB.Begin()
if err != nil {
log.Errorln("error while setting message visibility", err)
return nil
}
defer tx.Rollback() // nolint
query := "SELECT messages.id, user_id, body, title, subtitle, image, link, eventType, hidden_at, timestamp, display_name, display_color, created_at, disabled_at, previous_names, namechanged_at, authenticated_at, scopes, type FROM messages INNER JOIN users ON messages.user_id = users.id WHERE user_id IS ?"
stmt, err := tx.Prepare(query)
if err != nil {
log.Errorln("error while setting message visibility", err)
return nil
}
rows, err := stmt.Query(userID)
if err != nil {
log.Errorln("error while setting message visibility", err)
return nil
}
defer stmt.Close()
defer rows.Close()
// Get a list of IDs to send to the connected clients to hide
ids := make([]string, 0)
query := fmt.Sprintf("SELECT messages.id, user_id, body, title, subtitle, image, link, eventType, hidden_at, timestamp, display_name, display_color, created_at, disabled_at, previous_names, namechanged_at, authenticated_at, scopes, type FROM messages INNER JOIN users ON messages.user_id = users.id WHERE user_id IS '%s'", userID)
messages := getChat(query)
messages, err := getChat(rows)
if err != nil {
log.Errorln(err)
log.Errorln("There is a problem enumerating chat message rows. Please report this:", query)
return nil
}
if len(messages) == 0 {
return nil
@ -345,6 +432,11 @@ func SetMessageVisibilityForUserID(userID string, visible bool) error {
ids = append(ids, message.(events.UserMessageEvent).ID)
}
if err = tx.Commit(); err != nil {
log.Errorln("error while setting message visibility ", err)
return nil
}
// Tell the clients to hide/show these messages.
return SetMessagesVisibility(ids, visible)
}

File diff suppressed because one or more lines are too long

View File

@ -3,11 +3,17 @@ Description=Owncast Service
[Service]
Type=simple
WorkingDirectory=[path_to_owncast_root_directory]
ExecStart=[path_to_owncast_executable]
Restart=on-failure
WorkingDirectory=[path to owncast directory]
ReadWritePaths=[path to owncast directory]
ExecStart=[path to owncast directory]/owncast
Restart=always
RestartSec=5
User=[user to run owncast as]
Group=[group to run owncast as]
NoNewPrivileges=true
SecureBits=noroot
ProtectSystem=strict
ProtectHome=read-only
[Install]
WantedBy=multi-user.target

18
go.mod
View File

@ -4,7 +4,7 @@ go 1.17
require (
github.com/amalfra/etag v1.0.0
github.com/aws/aws-sdk-go v1.44.124
github.com/aws/aws-sdk-go v1.44.145
github.com/go-fed/activity v1.0.1-0.20210803212804-d866ba75dd0f
github.com/go-fed/httpsig v1.1.0
github.com/go-ole/go-ole v1.2.6 // indirect
@ -20,9 +20,9 @@ require (
github.com/schollz/sqlite3dump v1.3.1
github.com/sirupsen/logrus v1.9.0
github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569
github.com/yuin/goldmark v1.5.2
golang.org/x/mod v0.6.0
golang.org/x/time v0.1.0
github.com/yuin/goldmark v1.5.3
golang.org/x/mod v0.7.0
golang.org/x/time v0.2.0
mvdan.cc/xurls v1.1.0
)
@ -35,11 +35,11 @@ require (
github.com/tklauser/numcpus v0.4.0 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/crypto v0.1.0 // indirect
golang.org/x/net v0.1.0
golang.org/x/sys v0.1.0 // indirect
golang.org/x/net v0.2.0
golang.org/x/sys v0.2.0 // indirect
)
require github.com/prometheus/client_golang v1.13.0
require github.com/prometheus/client_golang v1.14.0
require (
github.com/beorn7/perks v1.0.1 // indirect
@ -48,7 +48,7 @@ require (
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
golang.org/x/text v0.4.0 // indirect
@ -57,7 +57,7 @@ require (
require (
github.com/nakabonne/tstorage v0.3.5
github.com/shirou/gopsutil/v3 v3.22.9
github.com/shirou/gopsutil/v3 v3.22.10
)
require github.com/SherClockHolmes/webpush-go v1.2.0

39
go.sum
View File

@ -82,6 +82,18 @@ github.com/aws/aws-sdk-go v1.44.118 h1:FJOqIRTukf7+Ulp047/k7JB6eqMXNnj7eb+coORTh
github.com/aws/aws-sdk-go v1.44.118/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.44.124 h1:Xe1WQRUUekZf6ZFm3SD0vplB/AP/hymVqMiRS9LQRIs=
github.com/aws/aws-sdk-go v1.44.124/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.44.125 h1:yIyCs6HX1BOj6SFTirvBwVM1tTfplKrJOyilIZPtKV8=
github.com/aws/aws-sdk-go v1.44.125/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.44.128 h1:X34pX5t0LIZXjBY11yf9JKMP3c1aZgirh+5PjtaZyJ4=
github.com/aws/aws-sdk-go v1.44.128/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.44.130 h1:a/qwOxmYJF47xTZvTjECSJXnfRbjegb3YxvCXfETtnY=
github.com/aws/aws-sdk-go v1.44.130/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.44.136 h1:J1KJJssa8pjU8jETYUxwRS37KTcxjACfKd9GK8t+5ZU=
github.com/aws/aws-sdk-go v1.44.136/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/aws-sdk-go v1.44.142 h1:KZ1/FDwCSft1DuNllFaBtWpcG0CW2NgQjvOrE1TdlXE=
github.com/aws/aws-sdk-go v1.44.142/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/aws-sdk-go v1.44.145 h1:KMVRrIyjBsNz3xGPuHIRnhIuKlb5h3Ii5e5jbi3cgnc=
github.com/aws/aws-sdk-go v1.44.145/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
@ -292,11 +304,17 @@ github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnY
github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
github.com/prometheus/client_golang v1.13.1 h1:3gMjIY2+/hzmqhtUC/aQNYldJA6DtH3CgQvwS+02K1c=
github.com/prometheus/client_golang v1.13.1/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
@ -327,6 +345,8 @@ github.com/shirou/gopsutil/v3 v3.22.8 h1:a4s3hXogo5mE2PfdfJIonDbstO/P+9JszdfhAHS
github.com/shirou/gopsutil/v3 v3.22.8/go.mod h1:s648gW4IywYzUfE/KjXxUsqrqx/T2xO5VqOXxONeRfI=
github.com/shirou/gopsutil/v3 v3.22.9 h1:yibtJhIVEMcdw+tCTbOPiF1VcsuDeTE4utJ8Dm4c5eA=
github.com/shirou/gopsutil/v3 v3.22.9/go.mod h1:bBYl1kjgEJpWpxeHmLI+dVHWtyAwfcmSBLDsp2TNT8A=
github.com/shirou/gopsutil/v3 v3.22.10 h1:4KMHdfBRYXGF9skjDWiL4RA2N+E8dRdodU/bOZpPoVg=
github.com/shirou/gopsutil/v3 v3.22.10/go.mod h1:QNza6r4YQoydyCfo6rH0blGfKahgibh4dQmV5xdFkQk=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
@ -339,6 +359,7 @@ github.com/spf13/pflag v1.0.4-0.20181223182923-24fa6976df40/go.mod h1:DYY7MBk1bd
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@ -347,6 +368,7 @@ github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMT
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/teris-io/shortid v0.0.0-20201117134242-e59966efd125 h1:3SNcvBmEPE1YlB1JpVZouslJpI3GBNoiqW7+wb0Rz7w=
github.com/teris-io/shortid v0.0.0-20201117134242-e59966efd125/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0=
github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569 h1:xzABM9let0HLLqFypcxvLmlvEciCHL7+Lv+4vwZqecI=
@ -368,6 +390,8 @@ github.com/yuin/goldmark v1.4.14 h1:jwww1XQfhJN7Zm+/a1ZA/3WUiEBEroYFNTiV3dKwM8U=
github.com/yuin/goldmark v1.4.14/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.5.2 h1:ALmeCk/px5FSm1MAcFBAsVKZjDuMVj8Tm7FFIlMJnqU=
github.com/yuin/goldmark v1.5.2/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.5.3 h1:3HUJmBFbQW9fhQOzMgseU134xfi6hU+mjWywx5Ty+/M=
github.com/yuin/goldmark v1.5.3/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
@ -383,6 +407,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
@ -419,8 +444,11 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I=
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -450,6 +478,7 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@ -488,6 +517,8 @@ golang.org/x/net v0.0.0-20221019024206-cb67ada4b0ad h1:Zx6wVVDwwNJFWXNIvDi7o952w
golang.org/x/net v0.0.0-20221019024206-cb67ada4b0ad/go.mod h1:RpDiru2p0u2F0lLpEoqnP2+7xs0ifAuOcJ442g6GU2s=
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -504,6 +535,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180525142821-c11f84a56e43/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -553,6 +585,7 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbuf
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220804214406-8e32c043e418 h1:9vYwv7OjYaky/tlAeD7C4oC9EsPTlaFl1H2jS++V+ME=
@ -561,9 +594,12 @@ golang.org/x/sys v0.0.0-20221010170243-090e33056c14 h1:k5II8e6QD8mITdi+okbbmR/cI
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -587,6 +623,8 @@ golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQL
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.2.0 h1:52I/1L54xyEQAYdtcSuxtiT84KGYTBGXwayxmIpNJhE=
golang.org/x/time v0.2.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@ -627,6 +665,7 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -2,7 +2,7 @@ openapi: 3.0.1
info:
title: Owncast
description: Owncast is a self-hosted live video and web chat server for use with existing popular broadcasting software.
version: '0.0.12'
version: '0.0.13'
contact:
name: Gabe Kangas
email: gabek@real-ity.com

View File

@ -9,11 +9,16 @@
"timezone": "America/Los_Angeles",
"lockFileMaintenance": {
"enabled": true,
"automerge": true
"automerge": true,
"platformAutomerge": true
},
"npm": {
"stabilityDays": 3
},
"dependencyDashboard": true,
"major": {
"dependencyDashboardApproval": true
},
"packageRules": [
{
"description": "Automatically merge minor and patch-level updates",
@ -23,20 +28,31 @@
"digest"
],
"automerge": true,
"major": {
"dependencyDashboardApproval": true
},
"automergeType": "branch"
"automergeType": "branch",
"platformAutomerge": true,
"dependencyDashboardApproval": false
},
{
"matchDepTypes": [
"devDependencies"
"description": "Require approval for every Go language update",
"dependencyDashboardApproval": true,
"matchPackagePatterns": [
"go"
]
},
{
"description": "Ignore the old pre-0.1.0 web packages",
"matchPackageNames": [
"postcss",
"tailwindcss",
"cssnano",
"htm",
"mark.js",
"postcss-cli",
"@videojs/themes",
"@joeattardi/emoji-button",
"preact"
],
"automerge": true,
"major": {
"dependencyDashboardApproval": true
}
"enabled": false
}
],
"platformAutomerge": true
}
]
}

View File

@ -1585,9 +1585,9 @@
}
},
"socket.io-parser": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.2.tgz",
"integrity": "sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg==",
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.3.tgz",
"integrity": "sha512-qOg87q1PMWWTeO01768Yh9ogn7chB9zkKtQnya41Y355S0UmpXgpcrFwAgjYJxu9BdKug5r5e9YtVSeWhKBUZg==",
"requires": {
"component-emitter": "~1.3.0",
"debug": "~3.1.0",
@ -1605,7 +1605,7 @@
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
}
}
},

View File

@ -6,394 +6,395 @@ import { EmojiButton } from '/js/web_modules/@joeattardi/emoji-button.js';
import ContentEditable, { replaceCaret } from './content-editable.js';
import {
generatePlaceholderText,
getCaretPosition,
convertToText,
convertOnPaste,
createEmojiMarkup,
trimNbsp,
emojify,
generatePlaceholderText,
getCaretPosition,
convertToText,
convertOnPaste,
createEmojiMarkup,
trimNbsp,
emojify,
} from '../../utils/chat.js';
import {
getLocalStorage,
setLocalStorage,
classNames,
getLocalStorage,
setLocalStorage,
classNames,
} from '../../utils/helpers.js';
import {
URL_CUSTOM_EMOJIS,
KEY_CHAT_FIRST_MESSAGE_SENT,
CHAT_CHAR_COUNT_BUFFER,
CHAT_OK_KEYCODES,
CHAT_KEY_MODIFIERS,
URL_CUSTOM_EMOJIS,
KEY_CHAT_FIRST_MESSAGE_SENT,
CHAT_CHAR_COUNT_BUFFER,
CHAT_OK_KEYCODES,
CHAT_KEY_MODIFIERS,
} from '../../utils/constants.js';
export default class ChatInput extends Component {
constructor(props, context) {
super(props, context);
this.formMessageInput = createRef();
this.emojiPickerButton = createRef();
constructor(props, context) {
super(props, context);
this.formMessageInput = createRef();
this.emojiPickerButton = createRef();
this.messageCharCount = 0;
this.messageCharCount = 0;
this.prepNewLine = false;
this.modifierKeyPressed = false; // control/meta/shift/alt
this.prepNewLine = false;
this.modifierKeyPressed = false; // control/meta/shift/alt
this.state = {
inputHTML: '',
inputCharsLeft: props.inputMaxBytes,
hasSentFirstChatMessage: getLocalStorage(KEY_CHAT_FIRST_MESSAGE_SENT),
emojiPicker: null,
emojiList: null,
emojiNames: null,
};
this.state = {
inputHTML: '',
inputCharsLeft: props.inputMaxBytes,
hasSentFirstChatMessage: getLocalStorage(KEY_CHAT_FIRST_MESSAGE_SENT),
emojiPicker: null,
emojiList: null,
emojiNames: null,
};
this.handleEmojiButtonClick = this.handleEmojiButtonClick.bind(this);
this.handleEmojiSelected = this.handleEmojiSelected.bind(this);
this.getCustomEmojis = this.getCustomEmojis.bind(this);
this.handleEmojiButtonClick = this.handleEmojiButtonClick.bind(this);
this.handleEmojiSelected = this.handleEmojiSelected.bind(this);
this.getCustomEmojis = this.getCustomEmojis.bind(this);
this.handleMessageInputKeydown = this.handleMessageInputKeydown.bind(this);
this.handleMessageInputKeyup = this.handleMessageInputKeyup.bind(this);
this.handleMessageInputBlur = this.handleMessageInputBlur.bind(this);
this.handleSubmitChatButton = this.handleSubmitChatButton.bind(this);
this.handlePaste = this.handlePaste.bind(this);
this.handleMessageInputKeydown = this.handleMessageInputKeydown.bind(this);
this.handleMessageInputKeyup = this.handleMessageInputKeyup.bind(this);
this.handleMessageInputBlur = this.handleMessageInputBlur.bind(this);
this.handleSubmitChatButton = this.handleSubmitChatButton.bind(this);
this.handlePaste = this.handlePaste.bind(this);
this.handleContentEditableChange =
this.handleContentEditableChange.bind(this);
}
this.handleContentEditableChange =
this.handleContentEditableChange.bind(this);
}
componentDidMount() {
this.getCustomEmojis();
}
componentDidMount() {
this.getCustomEmojis();
}
getCustomEmojis() {
fetch(URL_CUSTOM_EMOJIS)
.then((response) => {
if (!response.ok) {
throw new Error(`Network response was not ok ${response.ok}`);
}
return response.json();
})
.then((json) => {
const emojiList = json;
const emojiNames = emojiList.map((emoji) => emoji.name);
const emojiPicker = new EmojiButton({
zIndex: 100,
theme: 'owncast', // see chat.css
custom: json,
initialCategory: 'custom',
showPreview: false,
autoHide: false,
autoFocusSearch: false,
showAnimation: false,
emojiSize: '24px',
position: 'right-start',
strategy: 'absolute',
});
emojiPicker.on('emoji', (emoji) => {
this.handleEmojiSelected(emoji);
});
emojiPicker.on('hidden', () => {
this.formMessageInput.current.focus();
replaceCaret(this.formMessageInput.current);
});
this.setState({ emojiNames, emojiList, emojiPicker });
})
.catch((error) => {
// this.handleNetworkingError(`Emoji Fetch: ${error}`);
});
}
getCustomEmojis() {
fetch(URL_CUSTOM_EMOJIS)
.then((response) => {
if (!response.ok) {
throw new Error(`Network response was not ok ${response.ok}`);
}
return response.json();
})
.then((json) => {
const emojiList = json;
const emojiNames = emojiList.map((emoji) => emoji.name);
const emojiPicker = new EmojiButton({
zIndex: 100,
theme: 'owncast', // see chat.css
custom: json,
initialCategory: 'custom',
showPreview: false,
autoHide: false,
autoFocusSearch: false,
showAnimation: false,
emojiSize: '24px',
position: 'right-start',
strategy: 'absolute',
});
emojiPicker.on('emoji', (emoji) => {
this.handleEmojiSelected(emoji);
});
emojiPicker.on('hidden', () => {
this.formMessageInput.current.focus();
replaceCaret(this.formMessageInput.current);
});
this.setState({ emojiNames, emojiList, emojiPicker });
})
.catch((error) => {
// this.handleNetworkingError(`Emoji Fetch: ${error}`);
});
}
handleEmojiButtonClick() {
const { emojiPicker } = this.state;
if (emojiPicker) {
emojiPicker.togglePicker(this.emojiPickerButton.current);
}
}
handleEmojiButtonClick() {
const { emojiPicker } = this.state;
if (emojiPicker) {
emojiPicker.togglePicker(this.emojiPickerButton.current);
}
}
handleEmojiSelected(emoji) {
const { inputHTML, inputCharsLeft } = this.state;
// if we're already at char limit, don't do anything
if (inputCharsLeft < 0) {
return;
}
let content = '';
if (emoji.url) {
content = createEmojiMarkup(emoji, false);
} else {
content = emoji.emoji;
}
handleEmojiSelected(emoji) {
const { inputHTML, inputCharsLeft } = this.state;
// if we're already at char limit, don't do anything
if (inputCharsLeft < 0) {
return;
}
let content = '';
if (emoji.url) {
content = createEmojiMarkup(emoji, false);
} else {
content = emoji.emoji;
}
const position = getCaretPosition(this.formMessageInput.current);
const newHTML =
inputHTML.substring(0, position) +
content +
inputHTML.substring(position);
const position = getCaretPosition(this.formMessageInput.current);
const newHTML =
inputHTML.substring(0, position) +
content +
inputHTML.substring(position);
const charsLeft = this.calculateCurrentBytesLeft(newHTML);
this.setState({
inputHTML: newHTML,
inputCharsLeft: charsLeft,
});
// a hacky way add focus back into input field
setTimeout(() => {
const input = this.formMessageInput.current;
input.focus();
replaceCaret(input);
}, 100);
}
const charsLeft = this.calculateCurrentBytesLeft(newHTML);
this.setState({
inputHTML: newHTML,
inputCharsLeft: charsLeft,
});
// a hacky way add focus back into input field
setTimeout(() => {
const input = this.formMessageInput.current;
input.focus();
replaceCaret(input);
}, 100);
}
// autocomplete text from the given "list". "token" marks the start of word lookup.
autoComplete(token, list) {
const { inputHTML } = this.state;
const position = getCaretPosition(this.formMessageInput.current);
const at = inputHTML.lastIndexOf(token, position - 1);
if (at === -1) {
return false;
}
// autocomplete text from the given "list". "token" marks the start of word lookup.
autoComplete(token, list) {
const { inputHTML } = this.state;
const position = getCaretPosition(this.formMessageInput.current);
const at = inputHTML.lastIndexOf(token, position - 1);
if (at === -1) {
return false;
}
let partial = inputHTML.substring(at + 1, position).trim();
let partial = inputHTML.substring(at + 1, position).trim();
if (this.partial === undefined) {
this.partial = [];
}
if (this.partial === undefined) {
this.partial = [];
}
if (partial === this.suggestion) {
partial = this.partial[token];
} else {
this.partial[token] = partial;
}
if (partial === this.suggestion) {
partial = this.partial[token];
} else {
this.partial[token] = partial;
}
const possibilities = list.filter(function (item) {
return item.toLowerCase().startsWith(partial.toLowerCase());
});
const possibilities = list.filter(function (item) {
return item.toLowerCase().startsWith(partial.toLowerCase());
});
if (this.completionIndex === undefined) {
this.completionIndex = [];
}
if (this.completionIndex === undefined) {
this.completionIndex = [];
}
if (
this.completionIndex[token] === undefined ||
++this.completionIndex[token] >= possibilities.length
) {
this.completionIndex[token] = 0;
}
if (
this.completionIndex[token] === undefined ||
++this.completionIndex[token] >= possibilities.length
) {
this.completionIndex[token] = 0;
}
if (possibilities.length > 0) {
this.suggestion = possibilities[this.completionIndex[token]];
if (possibilities.length > 0) {
this.suggestion = possibilities[this.completionIndex[token]];
const newHTML =
inputHTML.substring(0, at + 1) +
this.suggestion +
' ' +
inputHTML.substring(position);
const newHTML =
inputHTML.substring(0, at + 1) +
this.suggestion +
' ' +
inputHTML.substring(position);
this.setState({
inputHTML: newHTML,
inputCharsLeft: this.calculateCurrentBytesLeft(newHTML),
});
}
this.setState({
inputHTML: newHTML,
inputCharsLeft: this.calculateCurrentBytesLeft(newHTML),
});
}
return true;
}
return true;
}
// replace :emoji: with the emoji <img>
injectEmoji() {
const { inputHTML, emojiList } = this.state;
const textValue = convertToText(inputHTML);
const processedHTML = emojify(inputHTML, emojiList);
// replace :emoji: with the emoji <img>
injectEmoji() {
const { inputHTML, emojiList } = this.state;
const textValue = convertToText(inputHTML);
const processedHTML = emojify(inputHTML, emojiList);
if (textValue != convertToText(processedHTML)) {
this.setState({
inputHTML: processedHTML,
});
return true;
}
return false;
}
if (textValue != convertToText(processedHTML)) {
this.setState({
inputHTML: processedHTML,
});
return true;
}
return false;
}
handleMessageInputKeydown(event) {
const key = event && event.key;
handleMessageInputKeydown(event) {
const key = event && event.key;
if (key === 'Enter') {
if (!this.prepNewLine) {
this.sendMessage();
event.preventDefault();
this.prepNewLine = false;
return;
}
}
// allow key presses such as command/shift/meta, etc even when message length is full later.
if (CHAT_KEY_MODIFIERS.includes(key)) {
this.modifierKeyPressed = true;
}
if (key === 'Control' || key === 'Shift') {
this.prepNewLine = true;
}
if (key === 'Tab') {
const { chatUserNames } = this.props;
const { emojiNames } = this.state;
if (this.autoComplete('@', chatUserNames)) {
event.preventDefault();
}
if (this.autoComplete(':', emojiNames)) {
event.preventDefault();
}
}
if (key === 'Enter') {
if (!this.prepNewLine) {
this.sendMessage();
event.preventDefault();
this.prepNewLine = false;
return;
}
}
// allow key presses such as command/shift/meta, etc even when message length is full later.
if (CHAT_KEY_MODIFIERS.includes(key)) {
this.modifierKeyPressed = true;
}
if (key === 'Control' || key === 'Shift') {
this.prepNewLine = true;
}
if (key === 'Tab') {
const { chatUserNames } = this.props;
const { emojiNames } = this.state;
if (this.autoComplete('@', chatUserNames)) {
event.preventDefault();
}
if (this.autoComplete(':', emojiNames)) {
event.preventDefault();
}
}
// if new input pushes the potential chars over, don't do anything
const formField = this.formMessageInput.current;
const tempCharsLeft = this.calculateCurrentBytesLeft(formField.innerHTML);
if (tempCharsLeft <= 0 && !CHAT_OK_KEYCODES.includes(key)) {
if (!this.modifierKeyPressed) {
event.preventDefault(); // prevent typing more
}
return;
}
}
// if new input pushes the potential chars over, don't do anything
const formField = this.formMessageInput.current;
const tempCharsLeft = this.calculateCurrentBytesLeft(formField.innerHTML);
if (tempCharsLeft <= 0 && !CHAT_OK_KEYCODES.includes(key)) {
if (!this.modifierKeyPressed) {
event.preventDefault(); // prevent typing more
}
return;
}
}
handleMessageInputKeyup(event) {
const { key } = event;
if (key === 'Control' || key === 'Shift') {
this.prepNewLine = false;
}
if (CHAT_KEY_MODIFIERS.includes(key)) {
this.modifierKeyPressed = false;
}
handleMessageInputKeyup(event) {
const { key } = event;
if (key === 'Control' || key === 'Shift') {
this.prepNewLine = false;
}
if (CHAT_KEY_MODIFIERS.includes(key)) {
this.modifierKeyPressed = false;
}
if (key === ':' || key === ';') {
this.injectEmoji();
}
}
if (key === ':' || key === ';') {
this.injectEmoji();
}
}
handleMessageInputBlur() {
this.prepNewLine = false;
this.modifierKeyPressed = false;
}
handleMessageInputBlur() {
this.prepNewLine = false;
this.modifierKeyPressed = false;
}
handlePaste(event) {
// don't allow paste if too much text already
if (this.state.inputCharsLeft < 0) {
event.preventDefault();
return;
}
convertOnPaste(event, this.state.emojiList);
this.handleMessageInputKeydown(event);
}
handlePaste(event) {
// don't allow paste if too much text already
if (this.state.inputCharsLeft < 0) {
event.preventDefault();
return;
}
convertOnPaste(event, this.state.emojiList);
this.handleMessageInputKeydown(event);
}
handleSubmitChatButton(event) {
event.preventDefault();
this.sendMessage();
}
handleSubmitChatButton(event) {
event.preventDefault();
this.sendMessage();
}
sendMessage() {
const { handleSendMessage, inputMaxBytes } = this.props;
const { hasSentFirstChatMessage, inputHTML, inputCharsLeft } = this.state;
if (inputCharsLeft < 0) {
return;
}
const message = convertToText(inputHTML);
const newStates = {
inputHTML: '',
inputCharsLeft: inputMaxBytes,
};
sendMessage() {
const { handleSendMessage, inputMaxBytes } = this.props;
const { hasSentFirstChatMessage, inputHTML, inputCharsLeft } = this.state;
if (inputCharsLeft < 0) {
return;
}
const message = convertToText(inputHTML);
const newStates = {
inputHTML: '',
inputCharsLeft: inputMaxBytes,
};
handleSendMessage(message);
handleSendMessage(message);
if (!hasSentFirstChatMessage) {
newStates.hasSentFirstChatMessage = true;
setLocalStorage(KEY_CHAT_FIRST_MESSAGE_SENT, true);
}
if (!hasSentFirstChatMessage) {
newStates.hasSentFirstChatMessage = true;
setLocalStorage(KEY_CHAT_FIRST_MESSAGE_SENT, true);
}
// clear things out.
this.setState(newStates);
}
// clear things out.
this.setState(newStates);
}
handleContentEditableChange(event) {
const value = event.target.value;
this.setState({
inputHTML: value,
inputCharsLeft: this.calculateCurrentBytesLeft(value),
});
}
handleContentEditableChange(event) {
const value = event.target.value;
this.setState({
inputHTML: value,
inputCharsLeft: this.calculateCurrentBytesLeft(value),
});
}
calculateCurrentBytesLeft(inputContent) {
const { inputMaxBytes } = this.props;
const curBytes = new Blob([trimNbsp(inputContent)]).size;
return inputMaxBytes - curBytes;
}
calculateCurrentBytesLeft(inputContent) {
const { inputMaxBytes } = this.props;
const curBytes = new Blob([trimNbsp(inputContent)]).size;
return inputMaxBytes - curBytes;
}
render(props, state) {
const { hasSentFirstChatMessage, inputCharsLeft, inputHTML, emojiPicker } =
state;
const { inputEnabled, inputMaxBytes } = props;
const emojiButtonStyle = {
display: emojiPicker && inputCharsLeft > 0 ? 'block' : 'none',
};
const extraClasses = classNames({
'display-count': inputCharsLeft <= CHAT_CHAR_COUNT_BUFFER,
});
const placeholderText = generatePlaceholderText(
inputEnabled,
hasSentFirstChatMessage
);
return html`
<div
id="message-input-container"
class="relative shadow-md bg-gray-900 border-t border-gray-700 border-solid p-4 z-20 ${extraClasses}"
>
<div
id="message-input-wrap"
class="flex flex-row justify-end appearance-none w-full bg-gray-200 border border-black-500 rounded py-2 px-2 pr-20 my-2 overflow-auto"
>
<${ContentEditable}
id="message-input"
class="appearance-none block w-full bg-transparent text-sm text-gray-700 h-full focus:outline-none"
placeholderText=${placeholderText}
innerRef=${this.formMessageInput}
html=${inputHTML}
disabled=${!inputEnabled}
onChange=${this.handleContentEditableChange}
onKeyDown=${this.handleMessageInputKeydown}
onKeyUp=${this.handleMessageInputKeyup}
onBlur=${this.handleMessageInputBlur}
onPaste=${this.handlePaste}
/>
</div>
<div
id="message-form-actions"
class="absolute flex flex-col justify-end items-end mr-4"
>
<span class="flex flex-row justify-center">
<button
ref=${this.emojiPickerButton}
id="emoji-button"
class="text-3xl leading-3 cursor-pointer text-purple-600"
type="button"
style=${emojiButtonStyle}
onclick=${this.handleEmojiButtonClick}
aria-label="Select an emoji"
disabled=${!inputEnabled}
>
<img src="../../../img/smiley.png" />
</button>
render(props, state) {
const { hasSentFirstChatMessage, inputCharsLeft, inputHTML, emojiPicker } =
state;
const { inputEnabled, inputMaxBytes } = props;
const emojiButtonStyle = {
display: emojiPicker && inputCharsLeft > 0 ? 'block' : 'none',
};
const extraClasses = classNames({
'display-count': inputCharsLeft <= CHAT_CHAR_COUNT_BUFFER,
});
const placeholderText = generatePlaceholderText(
inputEnabled,
hasSentFirstChatMessage
);
return html`
<div
id="message-input-container"
class="relative shadow-md bg-gray-900 border-t border-gray-700 border-solid p-4 z-20 ${extraClasses}"
>
<div
id="message-input-wrap"
class="flex flex-row justify-end appearance-none w-full bg-gray-200 border border-black-500 rounded py-2 px-2 pr-20 my-2 overflow-auto"
>
<${ContentEditable}
id="message-input"
aria-role="textbox"
class="appearance-none block w-full bg-transparent text-sm text-gray-700 h-full focus:outline-none"
aria-placeholder=${placeholderText}
innerRef=${this.formMessageInput}
html=${inputHTML}
disabled=${!inputEnabled}
onChange=${this.handleContentEditableChange}
onKeyDown=${this.handleMessageInputKeydown}
onKeyUp=${this.handleMessageInputKeyup}
onBlur=${this.handleMessageInputBlur}
onPaste=${this.handlePaste}
/>
</div>
<div
id="message-form-actions"
class="absolute flex flex-col justify-end items-end mr-4"
>
<span class="flex flex-row justify-center">
<button
ref=${this.emojiPickerButton}
id="emoji-button"
class="text-3xl leading-3 cursor-pointer text-purple-600"
type="button"
style=${emojiButtonStyle}
onclick=${this.handleEmojiButtonClick}
aria-label="Select an emoji"
disabled=${!inputEnabled}
>
<img src="../../../img/smiley.png" />
</button>
<button
id="send-message-button"
class="text-sm text-white rounded bg-gray-600 hidden p-1 ml-1 -mr-2"
type="button"
onclick=${this.handleSubmitChatButton}
disabled=${inputHTML === '' || inputCharsLeft < 0}
aria-label="Send message"
>
Send
</button>
</span>
<button
id="send-message-button"
class="text-sm text-white rounded bg-gray-600 hidden p-1 ml-1 -mr-2"
type="button"
onclick=${this.handleSubmitChatButton}
disabled=${inputHTML === '' || inputCharsLeft < 0}
aria-label="Send message"
>
Send
</button>
</span>
<span id="message-form-warning" class="text-red-600 text-xs"
>${inputCharsLeft} bytes</span
>
</div>
</div>
`;
}
<span id="message-form-warning" class="text-red-600 text-xs"
>${inputCharsLeft} bytes</span
>
</div>
</div>
`;
}
}

View File

@ -62,7 +62,7 @@
/* If the div is empty then show the placeholder */
#message-input:empty:before {
content: attr(placeholderText);
content: attr(aria-placeholder);
pointer-events: none;
position: absolute; /* Fixes firefox positioning caret on the right */
display: block; /* For Firefox */