binwiederhier 2 лет назад
Родитель
Сommit
92c384374a

+ 0 - 2
go.sum

@@ -2,8 +2,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
 cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.110.2 h1:sdFPBr6xG9/wkBbfhmUz/JmZC7X6LavQgcrVINrKiVA=
 cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw=
-cloud.google.com/go/compute v1.19.2 h1:GbJtPo8OKVHbVep8jvM57KidbYHxeE68LOVqouNLrDY=
-cloud.google.com/go/compute v1.19.2/go.mod h1:5f5a+iC1IriXYauaQ0EyQmEAEq9CGRnV5xJSQSlTV08=
 cloud.google.com/go/compute v1.19.3 h1:DcTwsFgGev/wV5+q8o2fzgcHOaac+DKGC91ZlvpsQds=
 cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI=
 cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=

+ 2 - 1
server/server.go

@@ -550,6 +550,7 @@ func (s *Server) handleWebConfig(w http.ResponseWriter, _ *http.Request, _ *visi
 		EnableSignup:       s.config.EnableSignup,
 		EnablePayments:     s.config.StripeSecretKey != "",
 		EnableCalls:        s.config.TwilioAccount != "",
+		EnableEmails:       s.config.SMTPSenderFrom != "",
 		EnableReservations: s.config.EnableReservations,
 		BillingContact:     s.config.BillingContact,
 		DisallowedTopics:   s.config.DisallowedTopics,
@@ -911,7 +912,7 @@ func (s *Server) parsePublishParams(r *http.Request, m *message) (cache bool, fi
 		return false, false, "", "", false, errHTTPBadRequestEmailDisabled
 	}
 	call = readParam(r, "x-call", "call")
-	if call != "" && s.config.TwilioAccount == "" && s.userManager == nil {
+	if call != "" && (s.config.TwilioAccount == "" || s.userManager == nil) {
 		return false, false, "", "", false, errHTTPBadRequestPhoneCallsDisabled
 	} else if call != "" && !isBoolValue(call) && !phoneNumberRegex.MatchString(call) {
 		return false, false, "", "", false, errHTTPBadRequestPhoneNumberInvalid

+ 5 - 0
server/server.yml

@@ -146,6 +146,11 @@
 
 # If enabled, ntfy can perform voice calls via Twilio via the "X-Call" header.
 #
+# - twilio-account is the Twilio account SID, e.g. AC12345beefbeef67890beefbeef122586
+# - twilio-auth-token is the Twilio auth token, e.g. affebeef258625862586258625862586
+# - twilio-from-number is the outgoing phone number you purchased, e.g. +18775132586
+# - twilio-verify-service is the Twilio Verify service SID, e.g. VA12345beefbeef67890beefbeef122586
+#
 # twilio-account:
 # twilio-auth-token:
 # twilio-from-number:

+ 21 - 17
server/server_account.go

@@ -108,17 +108,19 @@ func (s *Server) handleAccountGet(w http.ResponseWriter, r *http.Request, v *vis
 				CancelAt:     u.Billing.StripeSubscriptionCancelAt.Unix(),
 			}
 		}
-		reservations, err := s.userManager.Reservations(u.Name)
-		if err != nil {
-			return err
-		}
-		if len(reservations) > 0 {
-			response.Reservations = make([]*apiAccountReservation, 0)
-			for _, r := range reservations {
-				response.Reservations = append(response.Reservations, &apiAccountReservation{
-					Topic:    r.Topic,
-					Everyone: r.Everyone.String(),
-				})
+		if s.config.EnableReservations {
+			reservations, err := s.userManager.Reservations(u.Name)
+			if err != nil {
+				return err
+			}
+			if len(reservations) > 0 {
+				response.Reservations = make([]*apiAccountReservation, 0)
+				for _, r := range reservations {
+					response.Reservations = append(response.Reservations, &apiAccountReservation{
+						Topic:    r.Topic,
+						Everyone: r.Everyone.String(),
+					})
+				}
 			}
 		}
 		tokens, err := s.userManager.Tokens(u.ID)
@@ -141,12 +143,14 @@ func (s *Server) handleAccountGet(w http.ResponseWriter, r *http.Request, v *vis
 				})
 			}
 		}
-		phoneNumbers, err := s.userManager.PhoneNumbers(u.ID)
-		if err != nil {
-			return err
-		}
-		if len(phoneNumbers) > 0 {
-			response.PhoneNumbers = phoneNumbers
+		if s.config.TwilioAccount != "" {
+			phoneNumbers, err := s.userManager.PhoneNumbers(u.ID)
+			if err != nil {
+				return err
+			}
+			if len(phoneNumbers) > 0 {
+				response.PhoneNumbers = phoneNumbers
+			}
 		}
 	} else {
 		response.Username = user.Everyone

+ 6 - 0
server/server_account_test.go

@@ -151,6 +151,8 @@ func TestAccount_Get_Anonymous(t *testing.T) {
 	require.Equal(t, int64(1004), account.Stats.MessagesRemaining)
 	require.Equal(t, int64(0), account.Stats.Emails)
 	require.Equal(t, int64(24), account.Stats.EmailsRemaining)
+	require.Equal(t, int64(0), account.Stats.Calls)
+	require.Equal(t, int64(0), account.Stats.CallsRemaining)
 
 	rr = request(t, s, "POST", "/mytopic", "", nil)
 	require.Equal(t, 200, rr.Code)
@@ -498,6 +500,8 @@ func TestAccount_Reservation_AddAdminSuccess(t *testing.T) {
 func TestAccount_Reservation_AddRemoveUserWithTierSuccess(t *testing.T) {
 	conf := newTestConfigWithAuthFile(t)
 	conf.EnableSignup = true
+	conf.EnableReservations = true
+	conf.TwilioAccount = "dummy"
 	s := newTestServer(t, conf)
 
 	// Create user
@@ -510,6 +514,7 @@ func TestAccount_Reservation_AddRemoveUserWithTierSuccess(t *testing.T) {
 		MessageLimit:             123,
 		MessageExpiryDuration:    86400 * time.Second,
 		EmailLimit:               32,
+		CallLimit:                10,
 		ReservationLimit:         2,
 		AttachmentFileSizeLimit:  1231231,
 		AttachmentTotalSizeLimit: 123123,
@@ -551,6 +556,7 @@ func TestAccount_Reservation_AddRemoveUserWithTierSuccess(t *testing.T) {
 	require.Equal(t, int64(123), account.Limits.Messages)
 	require.Equal(t, int64(86400), account.Limits.MessagesExpiryDuration)
 	require.Equal(t, int64(32), account.Limits.Emails)
+	require.Equal(t, int64(10), account.Limits.Calls)
 	require.Equal(t, int64(2), account.Limits.Reservations)
 	require.Equal(t, int64(1231231), account.Limits.AttachmentFileSize)
 	require.Equal(t, int64(123123), account.Limits.AttachmentTotalSize)

+ 1 - 1
server/server_test.go

@@ -1194,7 +1194,7 @@ func TestServer_PublishDelayedEmail_Fail(t *testing.T) {
 }
 
 func TestServer_PublishDelayedCall_Fail(t *testing.T) {
-	c := newTestConfig(t)
+	c := newTestConfigWithAuthFile(t)
 	c.TwilioAccount = "AC1234567890"
 	c.TwilioAuthToken = "AAEAA1234567890"
 	c.TwilioFromNumber = "+1234567890"

+ 2 - 2
server/server_twilio_test.go

@@ -228,7 +228,7 @@ func TestServer_Twilio_Call_UnverifiedNumber(t *testing.T) {
 }
 
 func TestServer_Twilio_Call_InvalidNumber(t *testing.T) {
-	c := newTestConfig(t)
+	c := newTestConfigWithAuthFile(t)
 	c.TwilioCallsBaseURL = "https://127.0.0.1"
 	c.TwilioAccount = "AC1234567890"
 	c.TwilioAuthToken = "AAEAA1234567890"
@@ -242,7 +242,7 @@ func TestServer_Twilio_Call_InvalidNumber(t *testing.T) {
 }
 
 func TestServer_Twilio_Call_Anonymous(t *testing.T) {
-	c := newTestConfig(t)
+	c := newTestConfigWithAuthFile(t)
 	c.TwilioCallsBaseURL = "https://127.0.0.1"
 	c.TwilioAccount = "AC1234567890"
 	c.TwilioAuthToken = "AAEAA1234567890"

+ 1 - 0
server/types.go

@@ -394,6 +394,7 @@ type apiConfigResponse struct {
 	EnableSignup       bool     `json:"enable_signup"`
 	EnablePayments     bool     `json:"enable_payments"`
 	EnableCalls        bool     `json:"enable_calls"`
+	EnableEmails       bool     `json:"enable_emails"`
 	EnableReservations bool     `json:"enable_reservations"`
 	BillingContact     string   `json:"billing_contact"`
 	DisallowedTopics   []string `json:"disallowed_topics"`

+ 4 - 4
web/package-lock.json

@@ -16262,16 +16262,16 @@
       }
     },
     "node_modules/typescript": {
-      "version": "5.0.4",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz",
-      "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==",
+      "version": "4.9.5",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
+      "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
       "peer": true,
       "bin": {
         "tsc": "bin/tsc",
         "tsserver": "bin/tsserver"
       },
       "engines": {
-        "node": ">=12.20"
+        "node": ">=4.2.0"
       }
     },
     "node_modules/unbox-primitive": {

+ 2 - 1
web/public/config.js

@@ -6,12 +6,13 @@
 // During web development, you may change values here for rapid testing.
 
 var config = {
-    base_url: "http://127.0.0.1:2586",// FIXME window.location.origin, // Change to test against a different server
+    base_url: window.location.origin, // Change to test against a different server
     app_root: "/app",
     enable_login: true,
     enable_signup: true,
     enable_payments: true,
     enable_reservations: true,
+    enable_emails: true,
     enable_calls: true,
     billing_contact: "",
     disallowed_topics: ["docs", "static", "file", "app", "account", "settings", "signup", "login", "v1"]

+ 18 - 16
web/src/components/Account.js

@@ -571,22 +571,24 @@ const Stats = () => {
                         value={account.role === Role.USER ? normalize(account.stats.messages, account.limits.messages) : 100}
                     />
                 </Pref>
-                <Pref title={
-                    <>
-                        {t("account_usage_emails_title")}
-                        <Tooltip title={t("account_usage_limits_reset_daily")}><span><InfoIcon/></span></Tooltip>
-                    </>
-                }>
-                    <div>
-                        <Typography variant="body2" sx={{float: "left"}}>{account.stats.emails.toLocaleString()}</Typography>
-                        <Typography variant="body2" sx={{float: "right"}}>{account.role === Role.USER ? t("account_usage_of_limit", { limit: account.limits.emails.toLocaleString() }) : t("account_usage_unlimited")}</Typography>
-                    </div>
-                    <LinearProgress
-                        variant="determinate"
-                        value={account.role === Role.USER ? normalize(account.stats.emails, account.limits.emails) : 100}
-                    />
-                </Pref>
-                {(account.role === Role.ADMIN || account.limits.calls > 0) &&
+                {config.enable_emails &&
+                    <Pref title={
+                        <>
+                            {t("account_usage_emails_title")}
+                            <Tooltip title={t("account_usage_limits_reset_daily")}><span><InfoIcon/></span></Tooltip>
+                        </>
+                    }>
+                        <div>
+                            <Typography variant="body2" sx={{float: "left"}}>{account.stats.emails.toLocaleString()}</Typography>
+                            <Typography variant="body2" sx={{float: "right"}}>{account.role === Role.USER ? t("account_usage_of_limit", { limit: account.limits.emails.toLocaleString() }) : t("account_usage_unlimited")}</Typography>
+                        </div>
+                        <LinearProgress
+                            variant="determinate"
+                            value={account.role === Role.USER ? normalize(account.stats.emails, account.limits.emails) : 100}
+                        />
+                    </Pref>
+                }
+                {config.enable_calls && (account.role === Role.ADMIN || account.limits.calls > 0) &&
                     <Pref title={
                         <>
                             {t("account_usage_calls_title")}