mirror of
https://github.com/owncast/owncast.git
synced 2024-11-28 03:01:32 +03:00
Remove twitter notification configuration (#2598)
This commit is contained in:
parent
392da72c8b
commit
59e5cfefd4
15 changed files with 0 additions and 477 deletions
|
@ -58,28 +58,3 @@ func SetBrowserNotificationConfiguration(w http.ResponseWriter, r *http.Request)
|
||||||
|
|
||||||
controllers.WriteSimpleResponse(w, true, "updated browser push config with provided values")
|
controllers.WriteSimpleResponse(w, true, "updated browser push config with provided values")
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTwitterConfiguration will set the browser notification configuration.
|
|
||||||
func SetTwitterConfiguration(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if !requirePOST(w, r) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type request struct {
|
|
||||||
Value models.TwitterConfiguration `json:"value"`
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder := json.NewDecoder(r.Body)
|
|
||||||
var config request
|
|
||||||
if err := decoder.Decode(&config); err != nil {
|
|
||||||
controllers.WriteSimpleResponse(w, false, "unable to update twitter config with provided values")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := data.SetTwitterConfiguration(config.Value); err != nil {
|
|
||||||
controllers.WriteSimpleResponse(w, false, "unable to update twitter config with provided values")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
controllers.WriteSimpleResponse(w, true, "updated twitter config with provided values")
|
|
||||||
}
|
|
||||||
|
|
|
@ -84,7 +84,6 @@ func GetServerConfig(w http.ResponseWriter, r *http.Request) {
|
||||||
Notifications: notificationsConfigResponse{
|
Notifications: notificationsConfigResponse{
|
||||||
Discord: data.GetDiscordConfig(),
|
Discord: data.GetDiscordConfig(),
|
||||||
Browser: data.GetBrowserPushConfig(),
|
Browser: data.GetBrowserPushConfig(),
|
||||||
Twitter: data.GetTwitterConfiguration(),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,5 +159,4 @@ type federationConfigResponse struct {
|
||||||
type notificationsConfigResponse struct {
|
type notificationsConfigResponse struct {
|
||||||
Browser models.BrowserNotificationConfiguration `json:"browser"`
|
Browser models.BrowserNotificationConfiguration `json:"browser"`
|
||||||
Discord models.DiscordConfiguration `json:"discord"`
|
Discord models.DiscordConfiguration `json:"discord"`
|
||||||
Twitter models.TwitterConfiguration `json:"twitter"`
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,6 @@ const (
|
||||||
browserPushConfigurationKey = "browser_push_configuration"
|
browserPushConfigurationKey = "browser_push_configuration"
|
||||||
browserPushPublicKeyKey = "browser_push_public_key"
|
browserPushPublicKeyKey = "browser_push_public_key"
|
||||||
browserPushPrivateKeyKey = "browser_push_private_key"
|
browserPushPrivateKeyKey = "browser_push_private_key"
|
||||||
twitterConfigurationKey = "twitter_configuration"
|
|
||||||
hasConfiguredInitialNotificationsKey = "has_configured_initial_notifications"
|
hasConfiguredInitialNotificationsKey = "has_configured_initial_notifications"
|
||||||
hideViewerCountKey = "hide_viewer_count"
|
hideViewerCountKey = "hide_viewer_count"
|
||||||
customOfflineMessageKey = "custom_offline_message"
|
customOfflineMessageKey = "custom_offline_message"
|
||||||
|
@ -880,27 +879,6 @@ func GetBrowserPushPrivateKey() (string, error) {
|
||||||
return _datastore.GetString(browserPushPrivateKeyKey)
|
return _datastore.GetString(browserPushPrivateKeyKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTwitterConfiguration will set the Twitter configuration.
|
|
||||||
func SetTwitterConfiguration(config models.TwitterConfiguration) error {
|
|
||||||
configEntry := ConfigEntry{Key: twitterConfigurationKey, Value: config}
|
|
||||||
return _datastore.Save(configEntry)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTwitterConfiguration will return the Twitter configuration.
|
|
||||||
func GetTwitterConfiguration() models.TwitterConfiguration {
|
|
||||||
configEntry, err := _datastore.Get(twitterConfigurationKey)
|
|
||||||
if err != nil {
|
|
||||||
return models.TwitterConfiguration{Enabled: false}
|
|
||||||
}
|
|
||||||
|
|
||||||
var config models.TwitterConfiguration
|
|
||||||
if err := configEntry.getObject(&config); err != nil {
|
|
||||||
return models.TwitterConfiguration{Enabled: false}
|
|
||||||
}
|
|
||||||
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetHasPerformedInitialNotificationsConfig sets when performed initial setup.
|
// SetHasPerformedInitialNotificationsConfig sets when performed initial setup.
|
||||||
func SetHasPerformedInitialNotificationsConfig(hasConfigured bool) error {
|
func SetHasPerformedInitialNotificationsConfig(hasConfigured bool) error {
|
||||||
return _datastore.SetBool(hasConfiguredInitialNotificationsKey, true)
|
return _datastore.SetBool(hasConfiguredInitialNotificationsKey, true)
|
||||||
|
|
|
@ -56,7 +56,6 @@ Owncast Dependencies
|
||||||
|
|
||||||
- HTTP routing https://github.com/gorilla/mux
|
- HTTP routing https://github.com/gorilla/mux
|
||||||
- Mastodon API https://github.com/mattn/go-mastodon
|
- Mastodon API https://github.com/mattn/go-mastodon
|
||||||
- Twitter API https://github.com/ChimeraCoder/anaconda
|
|
||||||
- Go ORM https://gorm.io/gorm
|
- Go ORM https://gorm.io/gorm
|
||||||
- ID string generator https://github.com/teris-io/shortid
|
- ID string generator https://github.com/teris-io/shortid
|
||||||
- Slug generator https://github.com/metal3d/go-slugify
|
- Slug generator https://github.com/metal3d/go-slugify
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -77,7 +77,6 @@ require github.com/SherClockHolmes/webpush-go v1.2.0
|
||||||
require (
|
require (
|
||||||
github.com/aymerick/douceur v0.2.0 // indirect
|
github.com/aymerick/douceur v0.2.0 // indirect
|
||||||
github.com/dghubble/oauth1 v0.7.2
|
github.com/dghubble/oauth1 v0.7.2
|
||||||
github.com/g8rswimmer/go-twitter/v2 v2.1.5
|
|
||||||
github.com/go-test/deep v1.0.4 // indirect
|
github.com/go-test/deep v1.0.4 // indirect
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||||
github.com/gorilla/css v1.0.0 // indirect
|
github.com/gorilla/css v1.0.0 // indirect
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -70,8 +70,6 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/g8rswimmer/go-twitter/v2 v2.1.5 h1:Uj9Yuof2UducrP4Xva7irnUJfB9354/VyUXKmc2D5gg=
|
|
||||||
github.com/g8rswimmer/go-twitter/v2 v2.1.5/go.mod h1:/55xWb313KQs25X7oZrNSEwLQNkYHhPsDwFstc45vhc=
|
|
||||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
github.com/gin-gonic/gin v1.7.4 h1:QmUZXrvJ9qZ3GfWvQ+2wnW/1ePrTEJqPKMYEU3lD/DM=
|
github.com/gin-gonic/gin v1.7.4 h1:QmUZXrvJ9qZ3GfWvQ+2wnW/1ePrTEJqPKMYEU3lD/DM=
|
||||||
|
|
|
@ -14,14 +14,3 @@ type BrowserNotificationConfiguration struct {
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
GoLiveMessage string `json:"goLiveMessage,omitempty"`
|
GoLiveMessage string `json:"goLiveMessage,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TwitterConfiguration represents the configuration for Twitter access.
|
|
||||||
type TwitterConfiguration struct {
|
|
||||||
Enabled bool `json:"enabled"`
|
|
||||||
APIKey string `json:"apiKey"` // aka consumer key
|
|
||||||
APISecret string `json:"apiSecret"` // aka consumer secret
|
|
||||||
AccessToken string `json:"accessToken"`
|
|
||||||
AccessTokenSecret string `json:"accessTokenSecret"`
|
|
||||||
BearerToken string `json:"bearerToken"`
|
|
||||||
GoLiveMessage string `json:"goLiveMessage,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,15 +2,12 @@ package notifications
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/owncast/owncast/config"
|
"github.com/owncast/owncast/config"
|
||||||
"github.com/owncast/owncast/core/data"
|
"github.com/owncast/owncast/core/data"
|
||||||
"github.com/owncast/owncast/models"
|
"github.com/owncast/owncast/models"
|
||||||
"github.com/owncast/owncast/notifications/browser"
|
"github.com/owncast/owncast/notifications/browser"
|
||||||
"github.com/owncast/owncast/notifications/discord"
|
"github.com/owncast/owncast/notifications/discord"
|
||||||
"github.com/owncast/owncast/notifications/twitter"
|
|
||||||
"github.com/owncast/owncast/utils"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
@ -20,7 +17,6 @@ type Notifier struct {
|
||||||
datastore *data.Datastore
|
datastore *data.Datastore
|
||||||
browser *browser.Browser
|
browser *browser.Browser
|
||||||
discord *discord.Discord
|
discord *discord.Discord
|
||||||
twitter *twitter.Twitter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup will perform any pre-use setup for the notifier.
|
// Setup will perform any pre-use setup for the notifier.
|
||||||
|
@ -68,9 +64,6 @@ func New(datastore *data.Datastore) (*Notifier, error) {
|
||||||
if err := notifier.setupDiscord(); err != nil {
|
if err := notifier.setupDiscord(); err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
if err := notifier.setupTwitter(); err != nil {
|
|
||||||
log.Errorln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ¬ifier, nil
|
return ¬ifier, nil
|
||||||
}
|
}
|
||||||
|
@ -147,36 +140,6 @@ func (n *Notifier) notifyDiscord() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Notifier) setupTwitter() error {
|
|
||||||
if twitterConfig := data.GetTwitterConfiguration(); twitterConfig.Enabled {
|
|
||||||
if t, err := twitter.New(twitterConfig.APIKey, twitterConfig.APISecret, twitterConfig.AccessToken, twitterConfig.AccessTokenSecret, twitterConfig.BearerToken); err == nil {
|
|
||||||
n.twitter = t
|
|
||||||
} else if err != nil {
|
|
||||||
return errors.Wrap(err, "error creating twitter notifier")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *Notifier) notifyTwitter() {
|
|
||||||
goLiveMessage := data.GetTwitterConfiguration().GoLiveMessage
|
|
||||||
streamTitle := data.GetStreamTitle()
|
|
||||||
if streamTitle != "" {
|
|
||||||
goLiveMessage += "\n" + streamTitle
|
|
||||||
}
|
|
||||||
tagString := ""
|
|
||||||
for _, tag := range utils.ShuffleStringSlice(data.GetServerMetadataTags()) {
|
|
||||||
tagString = fmt.Sprintf("%s #%s", tagString, tag)
|
|
||||||
}
|
|
||||||
tagString = strings.TrimSpace(tagString)
|
|
||||||
|
|
||||||
message := fmt.Sprintf("%s\n%s\n\n%s", goLiveMessage, data.GetServerURL(), tagString)
|
|
||||||
|
|
||||||
if err := n.twitter.Notify(message); err != nil {
|
|
||||||
log.Errorln("error sending twitter message", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify will fire the different notification channels.
|
// Notify will fire the different notification channels.
|
||||||
func (n *Notifier) Notify() {
|
func (n *Notifier) Notify() {
|
||||||
if n.browser != nil {
|
if n.browser != nil {
|
||||||
|
@ -186,8 +149,4 @@ func (n *Notifier) Notify() {
|
||||||
if n.discord != nil {
|
if n.discord != nil {
|
||||||
n.notifyDiscord()
|
n.notifyDiscord()
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.twitter != nil {
|
|
||||||
n.notifyTwitter()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,78 +0,0 @@
|
||||||
package twitter
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/dghubble/oauth1"
|
|
||||||
"github.com/g8rswimmer/go-twitter/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
1. developer.twitter.com. Apply to be a developer if needed.
|
|
||||||
2. Projects and apps -> Your project name
|
|
||||||
3. Settings.
|
|
||||||
4. Scroll down to"User authentication settings" Edit
|
|
||||||
5. Enable OAuth 1.0a with Read/Write permissions.
|
|
||||||
6. Fill out the form with your information. Callback can be anything.
|
|
||||||
7. Go to your project "Keys and tokens"
|
|
||||||
8. Generate API key and secret.
|
|
||||||
9. Generate access token and secret. Verify it says "Read and write permissions."
|
|
||||||
10. Generate bearer token.
|
|
||||||
*/
|
|
||||||
|
|
||||||
type authorize struct {
|
|
||||||
Token string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a authorize) Add(req *http.Request) {
|
|
||||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", a.Token))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Twitter is an instance of the Twitter notifier.
|
|
||||||
type Twitter struct {
|
|
||||||
apiKey string
|
|
||||||
apiSecret string
|
|
||||||
accessToken string
|
|
||||||
accessTokenSecret string
|
|
||||||
bearerToken string
|
|
||||||
}
|
|
||||||
|
|
||||||
// New returns a new instance of the Twitter notifier.
|
|
||||||
func New(apiKey, apiSecret, accessToken, accessTokenSecret, bearerToken string) (*Twitter, error) {
|
|
||||||
if apiKey == "" || apiSecret == "" || accessToken == "" || accessTokenSecret == "" || bearerToken == "" {
|
|
||||||
return nil, errors.New("missing some or all of the required twitter configuration values")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Twitter{
|
|
||||||
apiKey: apiKey,
|
|
||||||
apiSecret: apiSecret,
|
|
||||||
accessToken: accessToken,
|
|
||||||
accessTokenSecret: accessTokenSecret,
|
|
||||||
bearerToken: bearerToken,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify will send a notification to Twitter with the supplied text.
|
|
||||||
func (t *Twitter) Notify(text string) error {
|
|
||||||
config := oauth1.NewConfig(t.apiKey, t.apiSecret)
|
|
||||||
token := oauth1.NewToken(t.accessToken, t.accessTokenSecret)
|
|
||||||
httpClient := config.Client(oauth1.NoContext, token)
|
|
||||||
|
|
||||||
client := &twitter.Client{
|
|
||||||
Authorizer: authorize{
|
|
||||||
Token: t.bearerToken,
|
|
||||||
},
|
|
||||||
Client: httpClient,
|
|
||||||
Host: "https://api.twitter.com",
|
|
||||||
}
|
|
||||||
|
|
||||||
req := twitter.CreateTweetRequest{
|
|
||||||
Text: text,
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := client.CreateTweet(context.Background(), req)
|
|
||||||
return err
|
|
||||||
}
|
|
|
@ -366,7 +366,6 @@ func Start() error {
|
||||||
// Configure outbound notification channels.
|
// Configure outbound notification channels.
|
||||||
http.HandleFunc("/api/admin/config/notifications/discord", middleware.RequireAdminAuth(admin.SetDiscordNotificationConfiguration))
|
http.HandleFunc("/api/admin/config/notifications/discord", middleware.RequireAdminAuth(admin.SetDiscordNotificationConfiguration))
|
||||||
http.HandleFunc("/api/admin/config/notifications/browser", middleware.RequireAdminAuth(admin.SetBrowserNotificationConfiguration))
|
http.HandleFunc("/api/admin/config/notifications/browser", middleware.RequireAdminAuth(admin.SetBrowserNotificationConfiguration))
|
||||||
http.HandleFunc("/api/admin/config/notifications/twitter", middleware.RequireAdminAuth(admin.SetTwitterConfiguration))
|
|
||||||
|
|
||||||
// Auth
|
// Auth
|
||||||
|
|
||||||
|
|
|
@ -1,220 +0,0 @@
|
||||||
import { Button, Typography } from 'antd';
|
|
||||||
import React, { useState, useContext, useEffect } from 'react';
|
|
||||||
import { ServerStatusContext } from '../../../utils/server-status-context';
|
|
||||||
import { TextField, TEXTFIELD_TYPE_PASSWORD } from '../TextField';
|
|
||||||
import { FormStatusIndicator } from '../FormStatusIndicator';
|
|
||||||
import {
|
|
||||||
postConfigUpdateToAPI,
|
|
||||||
RESET_TIMEOUT,
|
|
||||||
TWITTER_CONFIG_FIELDS,
|
|
||||||
} from '../../../utils/config-constants';
|
|
||||||
import { ToggleSwitch } from '../ToggleSwitch';
|
|
||||||
import {
|
|
||||||
createInputStatus,
|
|
||||||
StatusState,
|
|
||||||
STATUS_ERROR,
|
|
||||||
STATUS_SUCCESS,
|
|
||||||
} from '../../../utils/input-statuses';
|
|
||||||
import { UpdateArgs } from '../../../types/config-section';
|
|
||||||
import { TEXTFIELD_TYPE_TEXT } from '../TextFieldWithSubmit';
|
|
||||||
|
|
||||||
const { Title } = Typography;
|
|
||||||
|
|
||||||
export const ConfigNotify = () => {
|
|
||||||
const serverStatusData = useContext(ServerStatusContext);
|
|
||||||
const { serverConfig, setFieldInConfigState } = serverStatusData || {};
|
|
||||||
const { notifications } = serverConfig || {};
|
|
||||||
const { twitter } = notifications || {};
|
|
||||||
|
|
||||||
const [formDataValues, setFormDataValues] = useState<any>({});
|
|
||||||
const [submitStatus, setSubmitStatus] = useState<StatusState>(null);
|
|
||||||
|
|
||||||
const [enableSaveButton, setEnableSaveButton] = useState<boolean>(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const {
|
|
||||||
enabled,
|
|
||||||
apiKey,
|
|
||||||
apiSecret,
|
|
||||||
accessToken,
|
|
||||||
accessTokenSecret,
|
|
||||||
bearerToken,
|
|
||||||
goLiveMessage,
|
|
||||||
} = twitter || {};
|
|
||||||
setFormDataValues({
|
|
||||||
enabled,
|
|
||||||
apiKey,
|
|
||||||
apiSecret,
|
|
||||||
accessToken,
|
|
||||||
accessTokenSecret,
|
|
||||||
bearerToken,
|
|
||||||
goLiveMessage,
|
|
||||||
});
|
|
||||||
}, [twitter]);
|
|
||||||
|
|
||||||
const canSave = (): boolean => {
|
|
||||||
const { apiKey, apiSecret, accessToken, accessTokenSecret, bearerToken, goLiveMessage } =
|
|
||||||
formDataValues;
|
|
||||||
|
|
||||||
return (
|
|
||||||
!!apiKey &&
|
|
||||||
!!apiSecret &&
|
|
||||||
!!accessToken &&
|
|
||||||
!!accessTokenSecret &&
|
|
||||||
!!bearerToken &&
|
|
||||||
!!goLiveMessage
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setEnableSaveButton(canSave());
|
|
||||||
}, [formDataValues]);
|
|
||||||
|
|
||||||
// update individual values in state
|
|
||||||
const handleFieldChange = ({ fieldName, value }: UpdateArgs) => {
|
|
||||||
setFormDataValues({
|
|
||||||
...formDataValues,
|
|
||||||
[fieldName]: value,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// toggle switch.
|
|
||||||
const handleSwitchChange = (switchEnabled: boolean) => {
|
|
||||||
const previouslySaved = formDataValues.enabled;
|
|
||||||
|
|
||||||
handleFieldChange({ fieldName: 'enabled', value: switchEnabled });
|
|
||||||
|
|
||||||
return switchEnabled !== previouslySaved;
|
|
||||||
};
|
|
||||||
|
|
||||||
let resetTimer = null;
|
|
||||||
const resetStates = () => {
|
|
||||||
setSubmitStatus(null);
|
|
||||||
resetTimer = null;
|
|
||||||
clearTimeout(resetTimer);
|
|
||||||
setEnableSaveButton(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const save = async () => {
|
|
||||||
const postValue = formDataValues;
|
|
||||||
|
|
||||||
await postConfigUpdateToAPI({
|
|
||||||
apiPath: '/notifications/twitter',
|
|
||||||
data: { value: postValue },
|
|
||||||
onSuccess: () => {
|
|
||||||
setFieldInConfigState({
|
|
||||||
fieldName: 'twitter',
|
|
||||||
value: postValue,
|
|
||||||
path: 'notifications',
|
|
||||||
});
|
|
||||||
setSubmitStatus(createInputStatus(STATUS_SUCCESS, 'Updated.'));
|
|
||||||
resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
|
|
||||||
},
|
|
||||||
onError: (message: string) => {
|
|
||||||
setSubmitStatus(createInputStatus(STATUS_ERROR, message));
|
|
||||||
resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Title>Twitter</Title>
|
|
||||||
<p className="description reduced-margins">
|
|
||||||
Let your Twitter followers know each time you go live.
|
|
||||||
</p>
|
|
||||||
<div style={{ display: formDataValues.enabled ? 'block' : 'none' }}>
|
|
||||||
<p className="description reduced-margins">
|
|
||||||
<a href="https://owncast.online/docs/notifications" target="_blank" rel="noreferrer">
|
|
||||||
Read how to configure your Twitter account
|
|
||||||
</a>{' '}
|
|
||||||
to support posting from Owncast.
|
|
||||||
</p>
|
|
||||||
<p className="description reduced-margins">
|
|
||||||
<a
|
|
||||||
href="https://developer.twitter.com/en/portal/dashboard"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
And then get your Twitter developer credentials
|
|
||||||
</a>{' '}
|
|
||||||
to fill in below.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ToggleSwitch
|
|
||||||
apiPath=""
|
|
||||||
fieldName="enabled"
|
|
||||||
label="Enable Twitter"
|
|
||||||
onChange={handleSwitchChange}
|
|
||||||
checked={formDataValues.enabled}
|
|
||||||
/>
|
|
||||||
<div style={{ display: formDataValues.enabled ? 'block' : 'none' }}>
|
|
||||||
<TextField
|
|
||||||
{...TWITTER_CONFIG_FIELDS.apiKey}
|
|
||||||
required
|
|
||||||
value={formDataValues.apiKey}
|
|
||||||
onChange={handleFieldChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div style={{ display: formDataValues.enabled ? 'block' : 'none' }}>
|
|
||||||
<TextField
|
|
||||||
{...TWITTER_CONFIG_FIELDS.apiSecret}
|
|
||||||
type={TEXTFIELD_TYPE_PASSWORD}
|
|
||||||
required
|
|
||||||
value={formDataValues.apiSecret}
|
|
||||||
onChange={handleFieldChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div style={{ display: formDataValues.enabled ? 'block' : 'none' }}>
|
|
||||||
<TextField
|
|
||||||
{...TWITTER_CONFIG_FIELDS.accessToken}
|
|
||||||
required
|
|
||||||
value={formDataValues.accessToken}
|
|
||||||
onChange={handleFieldChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div style={{ display: formDataValues.enabled ? 'block' : 'none' }}>
|
|
||||||
<TextField
|
|
||||||
{...TWITTER_CONFIG_FIELDS.accessTokenSecret}
|
|
||||||
type={TEXTFIELD_TYPE_PASSWORD}
|
|
||||||
required
|
|
||||||
value={formDataValues.accessTokenSecret}
|
|
||||||
onChange={handleFieldChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div style={{ display: formDataValues.enabled ? 'block' : 'none' }}>
|
|
||||||
<TextField
|
|
||||||
{...TWITTER_CONFIG_FIELDS.bearerToken}
|
|
||||||
required
|
|
||||||
value={formDataValues.bearerToken}
|
|
||||||
onChange={handleFieldChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div style={{ display: formDataValues.enabled ? 'block' : 'none' }}>
|
|
||||||
<TextField
|
|
||||||
{...TWITTER_CONFIG_FIELDS.goLiveMessage}
|
|
||||||
type={TEXTFIELD_TYPE_TEXT}
|
|
||||||
required
|
|
||||||
value={formDataValues.goLiveMessage}
|
|
||||||
onChange={handleFieldChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
onClick={save}
|
|
||||||
style={{
|
|
||||||
display: enableSaveButton ? 'inline-block' : 'none',
|
|
||||||
position: 'relative',
|
|
||||||
marginLeft: 'auto',
|
|
||||||
right: '0',
|
|
||||||
marginTop: '20px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Save
|
|
||||||
</Button>
|
|
||||||
<FormStatusIndicator status={submitStatus} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
export default ConfigNotify;
|
|
|
@ -4,7 +4,6 @@ import Link from 'next/link';
|
||||||
|
|
||||||
import Discord from '../../components/admin/notification/discord';
|
import Discord from '../../components/admin/notification/discord';
|
||||||
import Browser from '../../components/admin/notification/browser';
|
import Browser from '../../components/admin/notification/browser';
|
||||||
import Twitter from '../../components/admin/notification/twitter';
|
|
||||||
import Federation from '../../components/admin/notification/federation';
|
import Federation from '../../components/admin/notification/federation';
|
||||||
import {
|
import {
|
||||||
TextFieldWithSubmit,
|
TextFieldWithSubmit,
|
||||||
|
@ -99,13 +98,6 @@ export default function ConfigNotify() {
|
||||||
>
|
>
|
||||||
<Browser />
|
<Browser />
|
||||||
</Col>
|
</Col>
|
||||||
<Col
|
|
||||||
span={10}
|
|
||||||
className={`form-module ${enabled ? '' : 'disabled'}`}
|
|
||||||
style={{ margin: '5px', display: 'flex', flexDirection: 'column' }}
|
|
||||||
>
|
|
||||||
<Twitter />
|
|
||||||
</Col>
|
|
||||||
|
|
||||||
<Col
|
<Col
|
||||||
span={10}
|
span={10}
|
||||||
|
|
|
@ -115,20 +115,9 @@ export interface DiscordNotification {
|
||||||
goLiveMessage: string;
|
goLiveMessage: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TwitterNotification {
|
|
||||||
enabled: boolean;
|
|
||||||
apiKey: string;
|
|
||||||
apiSecret: string;
|
|
||||||
accessToken: string;
|
|
||||||
accessTokenSecret: string;
|
|
||||||
bearerToken: string;
|
|
||||||
goLiveMessage: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NotificationsConfig {
|
export interface NotificationsConfig {
|
||||||
browser: BrowserNotification;
|
browser: BrowserNotification;
|
||||||
discord: DiscordNotification;
|
discord: DiscordNotification;
|
||||||
twitter: TwitterNotification;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Health {
|
export interface Health {
|
||||||
|
|
|
@ -557,48 +557,3 @@ export const BROWSER_PUSH_CONFIG_FIELDS = {
|
||||||
placeholder: `I've gone live! Come watch!`,
|
placeholder: `I've gone live! Come watch!`,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TWITTER_CONFIG_FIELDS = {
|
|
||||||
apiKey: {
|
|
||||||
fieldName: 'apiKey',
|
|
||||||
label: 'API Key',
|
|
||||||
maxLength: 200,
|
|
||||||
tip: '',
|
|
||||||
placeholder: `gaUQhRC2lqfrEFfElBXJgOctU`,
|
|
||||||
},
|
|
||||||
apiSecret: {
|
|
||||||
fieldName: 'apiSecret',
|
|
||||||
label: 'API Secret',
|
|
||||||
maxLength: 200,
|
|
||||||
tip: '',
|
|
||||||
placeholder: `IIz4jFZMWbUKdFOEGUprFjRwIslG56d1SPQlolJYjXwJ2y2qKS`,
|
|
||||||
},
|
|
||||||
accessToken: {
|
|
||||||
fieldName: 'accessToken',
|
|
||||||
label: 'Access Token',
|
|
||||||
maxLength: 200,
|
|
||||||
tip: '',
|
|
||||||
placeholder: `952540400-EEiwe9fkuSvWjnNC82YFa9kgpqbyAP3J7FjE2dkka`,
|
|
||||||
},
|
|
||||||
accessTokenSecret: {
|
|
||||||
fieldName: 'accessTokenSecret',
|
|
||||||
label: 'Access Token Secret',
|
|
||||||
maxLength: 200,
|
|
||||||
tip: '',
|
|
||||||
placeholder: `xO0AZWNGfZxpNsYPg3zNEKhAsPPGvNZFlzQArA2khI9Kg`,
|
|
||||||
},
|
|
||||||
bearerToken: {
|
|
||||||
fieldName: 'bearerToken',
|
|
||||||
label: 'Bearer Token',
|
|
||||||
maxLength: 200,
|
|
||||||
tip: '',
|
|
||||||
placeholder: `AAAAAAAAAAAAAAFqpXwEAAnnepHkjA8XD5ftx5jUadYIRtPtaq7AAAAwpXPpDWKDcdhiWr0tVDjsgW%2B4awGOM9VQ%3XPoMFuWcHsE42TK`,
|
|
||||||
},
|
|
||||||
goLiveMessage: {
|
|
||||||
fieldName: 'goLiveMessage',
|
|
||||||
label: 'Go Live Text',
|
|
||||||
maxLength: 200,
|
|
||||||
tip: 'The text to send when you go live.',
|
|
||||||
placeholder: `I've gone live! Come watch!`,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
|
@ -60,15 +60,6 @@ export const initialServerConfigState: ConfigDetails = {
|
||||||
notifications: {
|
notifications: {
|
||||||
browser: { enabled: false, goLiveMessage: '' },
|
browser: { enabled: false, goLiveMessage: '' },
|
||||||
discord: { enabled: false, webhook: '', goLiveMessage: '' },
|
discord: { enabled: false, webhook: '', goLiveMessage: '' },
|
||||||
twitter: {
|
|
||||||
enabled: false,
|
|
||||||
goLiveMessage: '',
|
|
||||||
apiKey: '',
|
|
||||||
apiSecret: '',
|
|
||||||
accessToken: '',
|
|
||||||
accessTokenSecret: '',
|
|
||||||
bearerToken: '',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
externalActions: [],
|
externalActions: [],
|
||||||
supportedCodecs: [],
|
supportedCodecs: [],
|
||||||
|
|
Loading…
Reference in a new issue