Merge remote-tracking branch 'origin/develop' into webv2
This commit is contained in:
commit
0ecaf11a25
@ -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
|
||||
}
|
||||
}
|
||||
|
134
build/javascript/package-lock.json
generated
134
build/javascript/package-lock.json
generated
@ -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": {
|
||||
|
@ -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
@ -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
18
go.mod
@ -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
39
go.sum
@ -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=
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
]
|
||||
}
|
8
test/load/package-lock.json
generated
8
test/load/package-lock.json
generated
@ -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=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -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>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user