Self-review
parent
79a3259c86
commit
ac029c389e
|
@ -856,8 +856,8 @@ billing-contact: "phil@example.com"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Phone calls
|
## Phone calls
|
||||||
ntfy supports phone calls via [Twilio](https://www.twilio.com/) as a phone call provider. If phone calls are enabled,
|
ntfy supports phone calls via [Twilio](https://www.twilio.com/) as a call provider. If phone calls are enabled,
|
||||||
users can verify and add a phone number, and then receive phone calls when publish a message with the `X-Call` header.
|
users can verify and add a phone number, and then receive phone calls when publishing a message using the `X-Call` header.
|
||||||
See [publishing page](publish.md#phone-calls) for more details.
|
See [publishing page](publish.md#phone-calls) for more details.
|
||||||
|
|
||||||
To enable Twilio integration, sign up with [Twilio](https://www.twilio.com/), purchase a phone number (Toll free numbers
|
To enable Twilio integration, sign up with [Twilio](https://www.twilio.com/), purchase a phone number (Toll free numbers
|
||||||
|
|
|
@ -2709,7 +2709,7 @@ You may also simply pass `yes` as a value to pick the first of your verified pho
|
||||||
On ntfy.sh, this feature is only supported to [ntfy Pro](https://ntfy.sh/app) plans.
|
On ntfy.sh, this feature is only supported to [ntfy Pro](https://ntfy.sh/app) plans.
|
||||||
|
|
||||||
<figure markdown>
|
<figure markdown>
|
||||||
![e-mail publishing](static/img/web-phone-verify.png)
|
![phone number verification](static/img/web-phone-verify.png)
|
||||||
<figcaption>Phone number verification in the <a href="https://ntfy.sh/account">web app</a></figcaption>
|
<figcaption>Phone number verification in the <a href="https://ntfy.sh/account">web app</a></figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
|
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -33,7 +33,7 @@ require (
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go v0.110.2 // indirect
|
cloud.google.com/go v0.110.2 // indirect
|
||||||
cloud.google.com/go/compute v1.19.2 // indirect
|
cloud.google.com/go/compute v1.19.3 // indirect
|
||||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||||
cloud.google.com/go/iam v1.0.1 // indirect
|
cloud.google.com/go/iam v1.0.1 // indirect
|
||||||
cloud.google.com/go/longrunning v0.4.2 // indirect
|
cloud.google.com/go/longrunning v0.4.2 // indirect
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -4,6 +4,8 @@ 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 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 h1:GbJtPo8OKVHbVep8jvM57KidbYHxeE68LOVqouNLrDY=
|
||||||
cloud.google.com/go/compute v1.19.2/go.mod h1:5f5a+iC1IriXYauaQ0EyQmEAEq9CGRnV5xJSQSlTV08=
|
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=
|
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
|
||||||
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
|
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
|
||||||
cloud.google.com/go/firestore v1.9.0 h1:IBlRyxgGySXu5VuW0RgGFlTtLukSnNkpDiEOMkQkmpA=
|
cloud.google.com/go/firestore v1.9.0 h1:IBlRyxgGySXu5VuW0RgGFlTtLukSnNkpDiEOMkQkmpA=
|
||||||
|
|
|
@ -198,6 +198,30 @@ func TestLog_LevelOverride_ManyOnSameField(t *testing.T) {
|
||||||
require.Equal(t, "", File())
|
require.Equal(t, "", File())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLog_FieldIf(t *testing.T) {
|
||||||
|
t.Cleanup(resetState)
|
||||||
|
|
||||||
|
var out bytes.Buffer
|
||||||
|
SetOutput(&out)
|
||||||
|
SetLevel(DebugLevel)
|
||||||
|
SetFormat(JSONFormat)
|
||||||
|
|
||||||
|
Time(time.Unix(11, 0).UTC()).
|
||||||
|
FieldIf("trace_field", "manager", TraceLevel). // This is not logged
|
||||||
|
Field("tag", "manager").
|
||||||
|
Debug("trace_field is not logged")
|
||||||
|
SetLevel(TraceLevel)
|
||||||
|
Time(time.Unix(12, 0).UTC()).
|
||||||
|
FieldIf("trace_field", "manager", TraceLevel). // Now it is logged
|
||||||
|
Field("tag", "manager").
|
||||||
|
Debug("trace_field is logged")
|
||||||
|
|
||||||
|
expected := `{"time":"1970-01-01T00:00:11Z","level":"DEBUG","message":"trace_field is not logged","tag":"manager"}
|
||||||
|
{"time":"1970-01-01T00:00:12Z","level":"DEBUG","message":"trace_field is logged","tag":"manager","trace_field":"manager"}
|
||||||
|
`
|
||||||
|
require.Equal(t, expected, out.String())
|
||||||
|
}
|
||||||
|
|
||||||
func TestLog_UsingStdLogger_JSON(t *testing.T) {
|
func TestLog_UsingStdLogger_JSON(t *testing.T) {
|
||||||
t.Cleanup(resetState)
|
t.Cleanup(resetState)
|
||||||
|
|
||||||
|
|
|
@ -108,11 +108,12 @@ var (
|
||||||
errHTTPBadRequestBillingSubscriptionExists = &errHTTP{40029, http.StatusBadRequest, "invalid request: billing subscription already exists", "", nil}
|
errHTTPBadRequestBillingSubscriptionExists = &errHTTP{40029, http.StatusBadRequest, "invalid request: billing subscription already exists", "", nil}
|
||||||
errHTTPBadRequestTierInvalid = &errHTTP{40030, http.StatusBadRequest, "invalid request: tier does not exist", "", nil}
|
errHTTPBadRequestTierInvalid = &errHTTP{40030, http.StatusBadRequest, "invalid request: tier does not exist", "", nil}
|
||||||
errHTTPBadRequestUserNotFound = &errHTTP{40031, http.StatusBadRequest, "invalid request: user does not exist", "", nil}
|
errHTTPBadRequestUserNotFound = &errHTTP{40031, http.StatusBadRequest, "invalid request: user does not exist", "", nil}
|
||||||
errHTTPBadRequestPhoneCallsDisabled = &errHTTP{40032, http.StatusBadRequest, "invalid request: calling is disabled", "https://ntfy.sh/docs/publish/#phone-calls", nil}
|
errHTTPBadRequestPhoneCallsDisabled = &errHTTP{40032, http.StatusBadRequest, "invalid request: calling is disabled", "https://ntfy.sh/docs/config/#phone-calls", nil}
|
||||||
errHTTPBadRequestPhoneNumberInvalid = &errHTTP{40033, http.StatusBadRequest, "invalid request: phone number invalid", "https://ntfy.sh/docs/publish/#phone-calls", nil}
|
errHTTPBadRequestPhoneNumberInvalid = &errHTTP{40033, http.StatusBadRequest, "invalid request: phone number invalid", "https://ntfy.sh/docs/publish/#phone-calls", nil}
|
||||||
errHTTPBadRequestPhoneNumberNotVerified = &errHTTP{40034, http.StatusBadRequest, "invalid request: phone number not verified, or no matching verified numbers found", "https://ntfy.sh/docs/publish/#phone-calls", nil}
|
errHTTPBadRequestPhoneNumberNotVerified = &errHTTP{40034, http.StatusBadRequest, "invalid request: phone number not verified, or no matching verified numbers found", "https://ntfy.sh/docs/publish/#phone-calls", nil}
|
||||||
errHTTPBadRequestAnonymousCallsNotAllowed = &errHTTP{40035, http.StatusBadRequest, "invalid request: anonymous phone calls are not allowed", "https://ntfy.sh/docs/publish/#phone-calls", nil}
|
errHTTPBadRequestAnonymousCallsNotAllowed = &errHTTP{40035, http.StatusBadRequest, "invalid request: anonymous phone calls are not allowed", "https://ntfy.sh/docs/publish/#phone-calls", nil}
|
||||||
errHTTPBadRequestPhoneNumberVerifyChannelInvalid = &errHTTP{40036, http.StatusBadRequest, "invalid request: verification channel must be 'sms' or 'call'", "https://ntfy.sh/docs/publish/#phone-calls", nil}
|
errHTTPBadRequestPhoneNumberVerifyChannelInvalid = &errHTTP{40036, http.StatusBadRequest, "invalid request: verification channel must be 'sms' or 'call'", "https://ntfy.sh/docs/publish/#phone-calls", nil}
|
||||||
|
errHTTPBadRequestDelayNoCall = &errHTTP{40037, http.StatusBadRequest, "delayed call notifications are not supported", "", nil}
|
||||||
errHTTPNotFound = &errHTTP{40401, http.StatusNotFound, "page not found", "", nil}
|
errHTTPNotFound = &errHTTP{40401, http.StatusNotFound, "page not found", "", nil}
|
||||||
errHTTPUnauthorized = &errHTTP{40101, http.StatusUnauthorized, "unauthorized", "https://ntfy.sh/docs/publish/#authentication", nil}
|
errHTTPUnauthorized = &errHTTP{40101, http.StatusUnauthorized, "unauthorized", "https://ntfy.sh/docs/publish/#authentication", nil}
|
||||||
errHTTPForbidden = &errHTTP{40301, http.StatusForbidden, "forbidden", "https://ntfy.sh/docs/publish/#authentication", nil}
|
errHTTPForbidden = &errHTTP{40301, http.StatusForbidden, "forbidden", "https://ntfy.sh/docs/publish/#authentication", nil}
|
||||||
|
|
|
@ -937,6 +937,9 @@ func (s *Server) parsePublishParams(r *http.Request, m *message) (cache bool, fi
|
||||||
if email != "" {
|
if email != "" {
|
||||||
return false, false, "", "", false, errHTTPBadRequestDelayNoEmail // we cannot store the email address (yet)
|
return false, false, "", "", false, errHTTPBadRequestDelayNoEmail // we cannot store the email address (yet)
|
||||||
}
|
}
|
||||||
|
if call != "" {
|
||||||
|
return false, false, "", "", false, errHTTPBadRequestDelayNoCall // we cannot store the phone number (yet)
|
||||||
|
}
|
||||||
delay, err := util.ParseFutureTime(delayStr, time.Now())
|
delay, err := util.ParseFutureTime(delayStr, time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, false, "", "", false, errHTTPBadRequestDelayCannotParse
|
return false, false, "", "", false, errHTTPBadRequestDelayCannotParse
|
||||||
|
|
|
@ -581,7 +581,7 @@ func (s *Server) handleAccountPhoneNumberDelete(w http.ResponseWriter, r *http.R
|
||||||
return errHTTPBadRequestPhoneNumberInvalid
|
return errHTTPBadRequestPhoneNumberInvalid
|
||||||
}
|
}
|
||||||
logvr(v, r).Tag(tagAccount).Field("phone_number", req.Number).Debug("Deleting phone number")
|
logvr(v, r).Tag(tagAccount).Field("phone_number", req.Number).Debug("Deleting phone number")
|
||||||
if err := s.userManager.DeletePhoneNumber(u.ID, req.Number); err != nil {
|
if err := s.userManager.RemovePhoneNumber(u.ID, req.Number); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return s.writeJSON(w, newSuccessResponse())
|
return s.writeJSON(w, newSuccessResponse())
|
||||||
|
|
|
@ -1190,7 +1190,20 @@ func TestServer_PublishDelayedEmail_Fail(t *testing.T) {
|
||||||
"E-Mail": "test@example.com",
|
"E-Mail": "test@example.com",
|
||||||
"Delay": "20 min",
|
"Delay": "20 min",
|
||||||
})
|
})
|
||||||
require.Equal(t, 400, response.Code)
|
require.Equal(t, 40003, toHTTPError(t, response.Body.String()).Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServer_PublishDelayedCall_Fail(t *testing.T) {
|
||||||
|
c := newTestConfig(t)
|
||||||
|
c.TwilioAccount = "AC1234567890"
|
||||||
|
c.TwilioAuthToken = "AAEAA1234567890"
|
||||||
|
c.TwilioFromNumber = "+1234567890"
|
||||||
|
s := newTestServer(t, c)
|
||||||
|
response := request(t, s, "PUT", "/mytopic", "fail", map[string]string{
|
||||||
|
"Call": "yes",
|
||||||
|
"Delay": "20 min",
|
||||||
|
})
|
||||||
|
require.Equal(t, 40037, toHTTPError(t, response.Body.String()).Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServer_PublishEmailNoMailer_Fail(t *testing.T) {
|
func TestServer_PublishEmailNoMailer_Fail(t *testing.T) {
|
||||||
|
|
|
@ -43,7 +43,7 @@ func TestServer_Twilio_Call_Add_Verify_Call_Delete_Success(t *testing.T) {
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
require.Equal(t, "/2010-04-01/Accounts/AC1234567890/Calls.json", r.URL.Path)
|
require.Equal(t, "/2010-04-01/Accounts/AC1234567890/Calls.json", r.URL.Path)
|
||||||
require.Equal(t, "Basic QUMxMjM0NTY3ODkwOkFBRUFBMTIzNDU2Nzg5MA==", r.Header.Get("Authorization"))
|
require.Equal(t, "Basic QUMxMjM0NTY3ODkwOkFBRUFBMTIzNDU2Nzg5MA==", r.Header.Get("Authorization"))
|
||||||
require.Equal(t, "From=%2B1234567890&To=%2B12223334444&Twiml=%0A%3CResponse%3E%0A%09%3CPause+length%3D%221%22%2F%3E%0A%09%3CSay+loop%3D%223%22%3E%0A%09%09You+have+a+notification+from+notify+on+topic+mytopic.+Message%3A%0A%09%09%3Cbreak+time%3D%221s%22%2F%3E%0A%09%09hi+there%0A%09%09%3Cbreak+time%3D%221s%22%2F%3E%0A%09%09End+message.%0A%09%09%3Cbreak+time%3D%221s%22%2F%3E%0A%09%09This+message+was+sent+by+user+phil.+It+will+be+repeated+up+to+three+times.%0A%09%09%3Cbreak+time%3D%223s%22%2F%3E%0A%09%3C%2FSay%3E%0A%09%3CSay%3EGoodbye.%3C%2FSay%3E%0A%3C%2FResponse%3E", string(body))
|
require.Equal(t, "From=%2B1234567890&To=%2B12223334444&Twiml=%0A%3CResponse%3E%0A%09%3CPause+length%3D%221%22%2F%3E%0A%09%3CSay+loop%3D%223%22%3E%0A%09%09You+have+a+message+from+notify+on+topic+mytopic.+Message%3A%0A%09%09%3Cbreak+time%3D%221s%22%2F%3E%0A%09%09hi+there%0A%09%09%3Cbreak+time%3D%221s%22%2F%3E%0A%09%09End+of+message.%0A%09%09%3Cbreak+time%3D%221s%22%2F%3E%0A%09%09This+message+was+sent+by+user+phil.+It+will+be+repeated+three+times.%0A%09%09To+unsubscribe+from+calls+like+this%2C+remove+your+phone+number+in+the+notify+web+app.%0A%09%09%3Cbreak+time%3D%223s%22%2F%3E%0A%09%3C%2FSay%3E%0A%09%3CSay%3EGoodbye.%3C%2FSay%3E%0A%3C%2FResponse%3E", string(body))
|
||||||
called.Store(true)
|
called.Store(true)
|
||||||
}))
|
}))
|
||||||
defer twilioCallsServer.Close()
|
defer twilioCallsServer.Close()
|
||||||
|
@ -69,7 +69,7 @@ func TestServer_Twilio_Call_Add_Verify_Call_Delete_Success(t *testing.T) {
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
// Send verification code for phone number
|
// Send verification code for phone number
|
||||||
response := request(t, s, "PUT", "/v1/account/phone/verify", `{"number":"+12223334444"}`, map[string]string{
|
response := request(t, s, "PUT", "/v1/account/phone/verify", `{"number":"+12223334444","channel":"sms"}`, map[string]string{
|
||||||
"authorization": util.BasicAuth("phil", "phil"),
|
"authorization": util.BasicAuth("phil", "phil"),
|
||||||
})
|
})
|
||||||
require.Equal(t, 200, response.Code)
|
require.Equal(t, 200, response.Code)
|
||||||
|
@ -122,7 +122,7 @@ func TestServer_Twilio_Call_Success(t *testing.T) {
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
require.Equal(t, "/2010-04-01/Accounts/AC1234567890/Calls.json", r.URL.Path)
|
require.Equal(t, "/2010-04-01/Accounts/AC1234567890/Calls.json", r.URL.Path)
|
||||||
require.Equal(t, "Basic QUMxMjM0NTY3ODkwOkFBRUFBMTIzNDU2Nzg5MA==", r.Header.Get("Authorization"))
|
require.Equal(t, "Basic QUMxMjM0NTY3ODkwOkFBRUFBMTIzNDU2Nzg5MA==", r.Header.Get("Authorization"))
|
||||||
require.Equal(t, "From=%2B1234567890&To=%2B11122233344&Twiml=%0A%3CResponse%3E%0A%09%3CPause+length%3D%221%22%2F%3E%0A%09%3CSay+loop%3D%223%22%3E%0A%09%09You+have+a+notification+from+notify+on+topic+mytopic.+Message%3A%0A%09%09%3Cbreak+time%3D%221s%22%2F%3E%0A%09%09hi+there%0A%09%09%3Cbreak+time%3D%221s%22%2F%3E%0A%09%09End+message.%0A%09%09%3Cbreak+time%3D%221s%22%2F%3E%0A%09%09This+message+was+sent+by+user+phil.+It+will+be+repeated+up+to+three+times.%0A%09%09%3Cbreak+time%3D%223s%22%2F%3E%0A%09%3C%2FSay%3E%0A%09%3CSay%3EGoodbye.%3C%2FSay%3E%0A%3C%2FResponse%3E", string(body))
|
require.Equal(t, "From=%2B1234567890&To=%2B11122233344&Twiml=%0A%3CResponse%3E%0A%09%3CPause+length%3D%221%22%2F%3E%0A%09%3CSay+loop%3D%223%22%3E%0A%09%09You+have+a+message+from+notify+on+topic+mytopic.+Message%3A%0A%09%09%3Cbreak+time%3D%221s%22%2F%3E%0A%09%09hi+there%0A%09%09%3Cbreak+time%3D%221s%22%2F%3E%0A%09%09End+of+message.%0A%09%09%3Cbreak+time%3D%221s%22%2F%3E%0A%09%09This+message+was+sent+by+user+phil.+It+will+be+repeated+three+times.%0A%09%09To+unsubscribe+from+calls+like+this%2C+remove+your+phone+number+in+the+notify+web+app.%0A%09%09%3Cbreak+time%3D%223s%22%2F%3E%0A%09%3C%2FSay%3E%0A%09%3CSay%3EGoodbye.%3C%2FSay%3E%0A%3C%2FResponse%3E", string(body))
|
||||||
called.Store(true)
|
called.Store(true)
|
||||||
}))
|
}))
|
||||||
defer twilioServer.Close()
|
defer twilioServer.Close()
|
||||||
|
@ -167,7 +167,7 @@ func TestServer_Twilio_Call_Success_With_Yes(t *testing.T) {
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
require.Equal(t, "/2010-04-01/Accounts/AC1234567890/Calls.json", r.URL.Path)
|
require.Equal(t, "/2010-04-01/Accounts/AC1234567890/Calls.json", r.URL.Path)
|
||||||
require.Equal(t, "Basic QUMxMjM0NTY3ODkwOkFBRUFBMTIzNDU2Nzg5MA==", r.Header.Get("Authorization"))
|
require.Equal(t, "Basic QUMxMjM0NTY3ODkwOkFBRUFBMTIzNDU2Nzg5MA==", r.Header.Get("Authorization"))
|
||||||
require.Equal(t, "From=%2B1234567890&To=%2B11122233344&Twiml=%0A%3CResponse%3E%0A%09%3CPause+length%3D%221%22%2F%3E%0A%09%3CSay+loop%3D%223%22%3E%0A%09%09You+have+a+notification+from+notify+on+topic+mytopic.+Message%3A%0A%09%09%3Cbreak+time%3D%221s%22%2F%3E%0A%09%09hi+there%0A%09%09%3Cbreak+time%3D%221s%22%2F%3E%0A%09%09End+message.%0A%09%09%3Cbreak+time%3D%221s%22%2F%3E%0A%09%09This+message+was+sent+by+user+phil.+It+will+be+repeated+up+to+three+times.%0A%09%09%3Cbreak+time%3D%223s%22%2F%3E%0A%09%3C%2FSay%3E%0A%09%3CSay%3EGoodbye.%3C%2FSay%3E%0A%3C%2FResponse%3E", string(body))
|
require.Equal(t, "From=%2B1234567890&To=%2B11122233344&Twiml=%0A%3CResponse%3E%0A%09%3CPause+length%3D%221%22%2F%3E%0A%09%3CSay+loop%3D%223%22%3E%0A%09%09You+have+a+message+from+notify+on+topic+mytopic.+Message%3A%0A%09%09%3Cbreak+time%3D%221s%22%2F%3E%0A%09%09hi+there%0A%09%09%3Cbreak+time%3D%221s%22%2F%3E%0A%09%09End+of+message.%0A%09%09%3Cbreak+time%3D%221s%22%2F%3E%0A%09%09This+message+was+sent+by+user+phil.+It+will+be+repeated+three+times.%0A%09%09To+unsubscribe+from+calls+like+this%2C+remove+your+phone+number+in+the+notify+web+app.%0A%09%09%3Cbreak+time%3D%223s%22%2F%3E%0A%09%3C%2FSay%3E%0A%09%3CSay%3EGoodbye.%3C%2FSay%3E%0A%3C%2FResponse%3E", string(body))
|
||||||
called.Store(true)
|
called.Store(true)
|
||||||
}))
|
}))
|
||||||
defer twilioServer.Close()
|
defer twilioServer.Close()
|
||||||
|
|
|
@ -318,7 +318,7 @@ type apiAccountPhoneNumberVerifyRequest struct {
|
||||||
|
|
||||||
type apiAccountPhoneNumberAddRequest struct {
|
type apiAccountPhoneNumberAddRequest struct {
|
||||||
Number string `json:"number"`
|
Number string `json:"number"`
|
||||||
Code string `json:"code,omitempty"`
|
Code string `json:"code"` // Only set when adding a phone number
|
||||||
}
|
}
|
||||||
|
|
||||||
type apiAccountTier struct {
|
type apiAccountTier struct {
|
||||||
|
|
|
@ -117,7 +117,6 @@ const (
|
||||||
PRIMARY KEY (user_id, phone_number),
|
PRIMARY KEY (user_id, phone_number),
|
||||||
FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE
|
FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
CREATE UNIQUE INDEX idx_user_phone_number ON user_phone (phone_number);
|
|
||||||
CREATE TABLE IF NOT EXISTS schemaVersion (
|
CREATE TABLE IF NOT EXISTS schemaVersion (
|
||||||
id INT PRIMARY KEY,
|
id INT PRIMARY KEY,
|
||||||
version INT NOT NULL
|
version INT NOT NULL
|
||||||
|
@ -420,7 +419,6 @@ const (
|
||||||
PRIMARY KEY (user_id, phone_number),
|
PRIMARY KEY (user_id, phone_number),
|
||||||
FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE
|
FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
CREATE UNIQUE INDEX idx_user_phone_number ON user_phone (phone_number);
|
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -694,8 +692,8 @@ func (a *Manager) AddPhoneNumber(userID string, phoneNumber string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeletePhoneNumber deletes a phone number from the user with the given user ID
|
// RemovePhoneNumber deletes a phone number from the user with the given user ID
|
||||||
func (a *Manager) DeletePhoneNumber(userID string, phoneNumber string) error {
|
func (a *Manager) RemovePhoneNumber(userID string, phoneNumber string) error {
|
||||||
_, err := a.db.Exec(deletePhoneNumberQuery, userID, phoneNumber)
|
_, err := a.db.Exec(deletePhoneNumberQuery, userID, phoneNumber)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -893,6 +893,38 @@ func TestManager_Tier_Change_And_Reset(t *testing.T) {
|
||||||
require.Nil(t, a.ResetTier("phil"))
|
require.Nil(t, a.ResetTier("phil"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUser_PhoneNumberAddListRemove(t *testing.T) {
|
||||||
|
a := newTestManager(t, PermissionDenyAll)
|
||||||
|
|
||||||
|
require.Nil(t, a.AddUser("phil", "phil", RoleUser))
|
||||||
|
phil, err := a.User("phil")
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Nil(t, a.AddPhoneNumber(phil.ID, "+1234567890"))
|
||||||
|
|
||||||
|
phoneNumbers, err := a.PhoneNumbers(phil.ID)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, 1, len(phoneNumbers))
|
||||||
|
require.Equal(t, "+1234567890", phoneNumbers[0])
|
||||||
|
|
||||||
|
require.Nil(t, a.RemovePhoneNumber(phil.ID, "+1234567890"))
|
||||||
|
phoneNumbers, err = a.PhoneNumbers(phil.ID)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, 0, len(phoneNumbers))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUser_PhoneNumberAdd_Multiple_Users_Same_Number(t *testing.T) {
|
||||||
|
a := newTestManager(t, PermissionDenyAll)
|
||||||
|
|
||||||
|
require.Nil(t, a.AddUser("phil", "phil", RoleUser))
|
||||||
|
require.Nil(t, a.AddUser("ben", "ben", RoleUser))
|
||||||
|
phil, err := a.User("phil")
|
||||||
|
require.Nil(t, err)
|
||||||
|
ben, err := a.User("ben")
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Nil(t, a.AddPhoneNumber(phil.ID, "+1234567890"))
|
||||||
|
require.Nil(t, a.AddPhoneNumber(ben.ID, "+1234567890"))
|
||||||
|
}
|
||||||
|
|
||||||
func TestSqliteCache_Migration_From1(t *testing.T) {
|
func TestSqliteCache_Migration_From1(t *testing.T) {
|
||||||
filename := filepath.Join(t.TempDir(), "user.db")
|
filename := filepath.Join(t.TempDir(), "user.db")
|
||||||
db, err := sql.Open("sqlite3", filename)
|
db, err := sql.Open("sqlite3", filename)
|
||||||
|
|
|
@ -3134,14 +3134,14 @@
|
||||||
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A=="
|
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A=="
|
||||||
},
|
},
|
||||||
"node_modules/@mui/base": {
|
"node_modules/@mui/base": {
|
||||||
"version": "5.0.0-beta.0",
|
"version": "5.0.0-beta.1",
|
||||||
"resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.0.tgz",
|
"resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.1.tgz",
|
||||||
"integrity": "sha512-ap+juKvt8R8n3cBqd/pGtZydQ4v2I/hgJKnvJRGjpSh3RvsvnDHO4rXov8MHQlH6VqpOekwgilFLGxMZjNTucA==",
|
"integrity": "sha512-xrkDCeu3JQE+JjJUnJnOrdQJMXwKhbV4AW+FRjMIj5i9cHK3BAuatG/iqbf1M+jklVWLk0KdbgioKwK+03aYbA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.21.0",
|
"@babel/runtime": "^7.21.0",
|
||||||
"@emotion/is-prop-valid": "^1.2.0",
|
"@emotion/is-prop-valid": "^1.2.0",
|
||||||
"@mui/types": "^7.2.4",
|
"@mui/types": "^7.2.4",
|
||||||
"@mui/utils": "^5.12.3",
|
"@mui/utils": "^5.13.1",
|
||||||
"@popperjs/core": "^2.11.7",
|
"@popperjs/core": "^2.11.7",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
|
@ -3166,9 +3166,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@mui/core-downloads-tracker": {
|
"node_modules/@mui/core-downloads-tracker": {
|
||||||
"version": "5.13.0",
|
"version": "5.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.13.1.tgz",
|
||||||
"integrity": "sha512-5nXz2k8Rv2ZjtQY6kXirJVyn2+ODaQuAJmXSJtLDUQDKWp3PFUj6j3bILqR0JGOs9R5ejgwz3crLKsl6GwjwkQ==",
|
"integrity": "sha512-qDHtNDO72NcBQMhaWBt9EZMvNiO+OXjPg5Sdk/6LgRDw6Zr3HdEZ5n2FJ/qtYsaT/okGyCuQavQkcZCOCEVf/g==",
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
"url": "https://opencollective.com/mui"
|
"url": "https://opencollective.com/mui"
|
||||||
|
@ -3200,16 +3200,16 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@mui/material": {
|
"node_modules/@mui/material": {
|
||||||
"version": "5.13.0",
|
"version": "5.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.13.1.tgz",
|
||||||
"integrity": "sha512-ckS+9tCpAzpdJdaTF+btF0b6mF9wbXg/EVKtnoAWYi0UKXoXBAVvEUMNpLGA5xdpCdf+A6fPbVUEHs9TsfU+Yw==",
|
"integrity": "sha512-qSnbJZer8lIuDYFDv19/t3s0AXYY9SxcOdhCnGvetRSfOG4gy3TkiFXNCdW5OLNveTieiMpOuv46eXUmE3ZA6A==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.21.0",
|
"@babel/runtime": "^7.21.0",
|
||||||
"@mui/base": "5.0.0-beta.0",
|
"@mui/base": "5.0.0-beta.1",
|
||||||
"@mui/core-downloads-tracker": "^5.13.0",
|
"@mui/core-downloads-tracker": "^5.13.1",
|
||||||
"@mui/system": "^5.12.3",
|
"@mui/system": "^5.13.1",
|
||||||
"@mui/types": "^7.2.4",
|
"@mui/types": "^7.2.4",
|
||||||
"@mui/utils": "^5.12.3",
|
"@mui/utils": "^5.13.1",
|
||||||
"@types/react-transition-group": "^4.4.6",
|
"@types/react-transition-group": "^4.4.6",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
"csstype": "^3.1.2",
|
"csstype": "^3.1.2",
|
||||||
|
@ -3244,12 +3244,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@mui/private-theming": {
|
"node_modules/@mui/private-theming": {
|
||||||
"version": "5.12.3",
|
"version": "5.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.12.3.tgz",
|
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.13.1.tgz",
|
||||||
"integrity": "sha512-o1e7Z1Bp27n4x2iUHhegV4/Jp6H3T6iBKHJdLivS5GbwsuAE/5l4SnZ+7+K+e5u9TuhwcAKZLkjvqzkDe8zqfA==",
|
"integrity": "sha512-HW4npLUD9BAkVppOUZHeO1FOKUJWAwbpy0VQoGe3McUYTlck1HezGHQCfBQ5S/Nszi7EViqiimECVl9xi+/WjQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.21.0",
|
"@babel/runtime": "^7.21.0",
|
||||||
"@mui/utils": "^5.12.3",
|
"@mui/utils": "^5.13.1",
|
||||||
"prop-types": "^15.8.1"
|
"prop-types": "^15.8.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -3301,15 +3301,15 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@mui/system": {
|
"node_modules/@mui/system": {
|
||||||
"version": "5.12.3",
|
"version": "5.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/@mui/system/-/system-5.12.3.tgz",
|
"resolved": "https://registry.npmjs.org/@mui/system/-/system-5.13.1.tgz",
|
||||||
"integrity": "sha512-JB/6sypHqeJCqwldWeQ1MKkijH829EcZAKKizxbU2MJdxGG5KSwZvTBa5D9qiJUA1hJFYYupjiuy9ZdJt6rV6w==",
|
"integrity": "sha512-BsDUjhiO6ZVAvzKhnWBHLZ5AtPJcdT+62VjnRLyA4isboqDKLg4fmYIZXq51yndg/soDK9RkY5lYZwEDku13Ow==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.21.0",
|
"@babel/runtime": "^7.21.0",
|
||||||
"@mui/private-theming": "^5.12.3",
|
"@mui/private-theming": "^5.13.1",
|
||||||
"@mui/styled-engine": "^5.12.3",
|
"@mui/styled-engine": "^5.12.3",
|
||||||
"@mui/types": "^7.2.4",
|
"@mui/types": "^7.2.4",
|
||||||
"@mui/utils": "^5.12.3",
|
"@mui/utils": "^5.13.1",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
"csstype": "^3.1.2",
|
"csstype": "^3.1.2",
|
||||||
"prop-types": "^15.8.1"
|
"prop-types": "^15.8.1"
|
||||||
|
@ -3353,13 +3353,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@mui/utils": {
|
"node_modules/@mui/utils": {
|
||||||
"version": "5.12.3",
|
"version": "5.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.12.3.tgz",
|
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.13.1.tgz",
|
||||||
"integrity": "sha512-D/Z4Ub3MRl7HiUccid7sQYclTr24TqUAQFFlxHQF8FR177BrCTQ0JJZom7EqYjZCdXhwnSkOj2ph685MSKNtIA==",
|
"integrity": "sha512-6lXdWwmlUbEU2jUI8blw38Kt+3ly7xkmV9ljzY4Q20WhsJMWiNry9CX8M+TaP/HbtuyR8XKsdMgQW7h7MM3n3A==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.21.0",
|
"@babel/runtime": "^7.21.0",
|
||||||
"@types/prop-types": "^15.7.5",
|
"@types/prop-types": "^15.7.5",
|
||||||
"@types/react-is": "^16.7.1 || ^17.0.0",
|
"@types/react-is": "^18.2.0",
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"react-is": "^18.2.0"
|
"react-is": "^18.2.0"
|
||||||
},
|
},
|
||||||
|
@ -4016,9 +4016,9 @@
|
||||||
"integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw=="
|
"integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw=="
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.1.4",
|
"version": "20.1.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.1.7.tgz",
|
||||||
"integrity": "sha512-At4pvmIOki8yuwLtd7BNHl3CiWNbtclUbNtScGx4OHfBd4/oWoJC8KRCIxXwkdndzhxOsPXihrsOoydxBjlE9Q=="
|
"integrity": "sha512-WCuw/o4GSwDGMoonES8rcvwsig77dGCMbZDrZr2x4ZZiNW4P/gcoZXe/0twgtobcTkmg9TuKflxYL/DuwDyJzg=="
|
||||||
},
|
},
|
||||||
"node_modules/@types/parse-json": {
|
"node_modules/@types/parse-json": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
|
@ -4061,21 +4061,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/react-is": {
|
"node_modules/@types/react-is": {
|
||||||
"version": "17.0.4",
|
"version": "18.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-18.2.0.tgz",
|
||||||
"integrity": "sha512-FLzd0K9pnaEvKz4D1vYxK9JmgQPiGk1lu23o1kqGsLeT0iPbRSF7b76+S5T9fD8aRa0B8bY7I/3DebEj+1ysBA==",
|
"integrity": "sha512-1vz2yObaQkLL7YFe/pme2cpvDsCwI1WXIfL+5eLz0MI9gFG24Re16RzUsI8t9XZn9ZWvgLNDrJBmrqXJO7GNQQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/react": "^17"
|
"@types/react": "*"
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/react-is/node_modules/@types/react": {
|
|
||||||
"version": "17.0.59",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.59.tgz",
|
|
||||||
"integrity": "sha512-gSON5zWYIGyoBcycCE75E9+r6dCC2dHdsrVkOEiIYNU5+Q28HcBAuqvDuxHcCbMfHBHdeT5Tva/AFn3rnMKE4g==",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/prop-types": "*",
|
|
||||||
"@types/scheduler": "*",
|
|
||||||
"csstype": "^3.0.2"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/react-transition-group": {
|
"node_modules/@types/react-transition-group": {
|
||||||
|
@ -4175,14 +4165,14 @@
|
||||||
"integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA=="
|
"integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA=="
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "5.59.5",
|
"version": "5.59.6",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.5.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.6.tgz",
|
||||||
"integrity": "sha512-feA9xbVRWJZor+AnLNAr7A8JRWeZqHUf4T9tlP+TN04b05pFVhO5eN7/O93Y/1OUlLMHKbnJisgDURs/qvtqdg==",
|
"integrity": "sha512-sXtOgJNEuRU5RLwPUb1jxtToZbgvq3M6FPpY4QENxoOggK+UpTxUBpj6tD8+Qh2g46Pi9We87E+eHnUw8YcGsw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.4.0",
|
"@eslint-community/regexpp": "^4.4.0",
|
||||||
"@typescript-eslint/scope-manager": "5.59.5",
|
"@typescript-eslint/scope-manager": "5.59.6",
|
||||||
"@typescript-eslint/type-utils": "5.59.5",
|
"@typescript-eslint/type-utils": "5.59.6",
|
||||||
"@typescript-eslint/utils": "5.59.5",
|
"@typescript-eslint/utils": "5.59.6",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"grapheme-splitter": "^1.0.4",
|
"grapheme-splitter": "^1.0.4",
|
||||||
"ignore": "^5.2.0",
|
"ignore": "^5.2.0",
|
||||||
|
@ -4208,11 +4198,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/experimental-utils": {
|
"node_modules/@typescript-eslint/experimental-utils": {
|
||||||
"version": "5.59.5",
|
"version": "5.59.6",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.59.5.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.59.6.tgz",
|
||||||
"integrity": "sha512-ArcSSBifznsKNA/p4h2w3Olt/T8AZf3bNglxD8OnuTsSDJbRpjPPmI8qpr6ijyvk1J/T3GMJHwRIluS/Kuz9kA==",
|
"integrity": "sha512-UIVfEaaHggOuhgqdpFlFQ7IN9UFMCiBR/N7uPBUyUlwNdJzYfAu9m4wbOj0b59oI/HSPW1N63Q7lsvfwTQY13w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/utils": "5.59.5"
|
"@typescript-eslint/utils": "5.59.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||||
|
@ -4226,13 +4216,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "5.59.5",
|
"version": "5.59.6",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.5.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.6.tgz",
|
||||||
"integrity": "sha512-NJXQC4MRnF9N9yWqQE2/KLRSOLvrrlZb48NGVfBa+RuPMN6B7ZcK5jZOvhuygv4D64fRKnZI4L4p8+M+rfeQuw==",
|
"integrity": "sha512-7pCa6al03Pv1yf/dUg/s1pXz/yGMUBAw5EeWqNTFiSueKvRNonze3hma3lhdsOrQcaOXhbk5gKu2Fludiho9VA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "5.59.5",
|
"@typescript-eslint/scope-manager": "5.59.6",
|
||||||
"@typescript-eslint/types": "5.59.5",
|
"@typescript-eslint/types": "5.59.6",
|
||||||
"@typescript-eslint/typescript-estree": "5.59.5",
|
"@typescript-eslint/typescript-estree": "5.59.6",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -4252,12 +4242,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "5.59.5",
|
"version": "5.59.6",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.5.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.6.tgz",
|
||||||
"integrity": "sha512-jVecWwnkX6ZgutF+DovbBJirZcAxgxC0EOHYt/niMROf8p4PwxxG32Qdhj/iIQQIuOflLjNkxoXyArkcIP7C3A==",
|
"integrity": "sha512-gLbY3Le9Dxcb8KdpF0+SJr6EQ+hFGYFl6tVY8VxLPFDfUZC7BHFw+Vq7bM5lE9DwWPfx4vMWWTLGXgpc0mAYyQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "5.59.5",
|
"@typescript-eslint/types": "5.59.6",
|
||||||
"@typescript-eslint/visitor-keys": "5.59.5"
|
"@typescript-eslint/visitor-keys": "5.59.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||||
|
@ -4268,12 +4258,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "5.59.5",
|
"version": "5.59.6",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.5.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.6.tgz",
|
||||||
"integrity": "sha512-4eyhS7oGym67/pSxA2mmNq7X164oqDYNnZCUayBwJZIRVvKpBCMBzFnFxjeoDeShjtO6RQBHBuwybuX3POnDqg==",
|
"integrity": "sha512-A4tms2Mp5yNvLDlySF+kAThV9VTBPCvGf0Rp8nl/eoDX9Okun8byTKoj3fJ52IJitjWOk0fKPNQhXEB++eNozQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/typescript-estree": "5.59.5",
|
"@typescript-eslint/typescript-estree": "5.59.6",
|
||||||
"@typescript-eslint/utils": "5.59.5",
|
"@typescript-eslint/utils": "5.59.6",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"tsutils": "^3.21.0"
|
"tsutils": "^3.21.0"
|
||||||
},
|
},
|
||||||
|
@ -4294,9 +4284,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "5.59.5",
|
"version": "5.59.6",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.5.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.6.tgz",
|
||||||
"integrity": "sha512-xkfRPHbqSH4Ggx4eHRIO/eGL8XL4Ysb4woL8c87YuAo8Md7AUjyWKa9YMwTL519SyDPrfEgKdewjkxNCVeJW7w==",
|
"integrity": "sha512-tH5lBXZI7T2MOUgOWFdVNUILsI02shyQvfzG9EJkoONWugCG77NDDa1EeDGw7oJ5IvsTAAGVV8I3Tk2PNu9QfA==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||||
},
|
},
|
||||||
|
@ -4306,12 +4296,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "5.59.5",
|
"version": "5.59.6",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.5.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.6.tgz",
|
||||||
"integrity": "sha512-+XXdLN2CZLZcD/mO7mQtJMvCkzRfmODbeSKuMY/yXbGkzvA9rJyDY5qDYNoiz2kP/dmyAxXquL2BvLQLJFPQIg==",
|
"integrity": "sha512-vW6JP3lMAs/Tq4KjdI/RiHaaJSO7IUsbkz17it/Rl9Q+WkQ77EOuOnlbaU8kKfVIOJxMhnRiBG+olE7f3M16DA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "5.59.5",
|
"@typescript-eslint/types": "5.59.6",
|
||||||
"@typescript-eslint/visitor-keys": "5.59.5",
|
"@typescript-eslint/visitor-keys": "5.59.6",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"globby": "^11.1.0",
|
"globby": "^11.1.0",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
|
@ -4332,16 +4322,16 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/utils": {
|
"node_modules/@typescript-eslint/utils": {
|
||||||
"version": "5.59.5",
|
"version": "5.59.6",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.5.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.6.tgz",
|
||||||
"integrity": "sha512-sCEHOiw+RbyTii9c3/qN74hYDPNORb8yWCoPLmB7BIflhplJ65u2PBpdRla12e3SSTJ2erRkPjz7ngLHhUegxA==",
|
"integrity": "sha512-vzaaD6EXbTS29cVH0JjXBdzMt6VBlv+hE31XktDRMX1j3462wZCJa7VzO2AxXEXcIl8GQqZPcOPuW/Z1tZVogg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.2.0",
|
"@eslint-community/eslint-utils": "^4.2.0",
|
||||||
"@types/json-schema": "^7.0.9",
|
"@types/json-schema": "^7.0.9",
|
||||||
"@types/semver": "^7.3.12",
|
"@types/semver": "^7.3.12",
|
||||||
"@typescript-eslint/scope-manager": "5.59.5",
|
"@typescript-eslint/scope-manager": "5.59.6",
|
||||||
"@typescript-eslint/types": "5.59.5",
|
"@typescript-eslint/types": "5.59.6",
|
||||||
"@typescript-eslint/typescript-estree": "5.59.5",
|
"@typescript-eslint/typescript-estree": "5.59.6",
|
||||||
"eslint-scope": "^5.1.1",
|
"eslint-scope": "^5.1.1",
|
||||||
"semver": "^7.3.7"
|
"semver": "^7.3.7"
|
||||||
},
|
},
|
||||||
|
@ -4377,11 +4367,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "5.59.5",
|
"version": "5.59.6",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.5.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.6.tgz",
|
||||||
"integrity": "sha512-qL+Oz+dbeBRTeyJTIy0eniD3uvqU7x+y1QceBismZ41hd4aBSRh8UAw4pZP0+XzLuPZmx4raNMq/I+59W2lXKA==",
|
"integrity": "sha512-zEfbFLzB9ETcEJ4HZEEsCR9HHeNku5/Qw1jSS5McYJv5BR+ftYXwFFAH5Al+xkGaZEqowMwl7uoJjQb1YSPF8Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "5.59.5",
|
"@typescript-eslint/types": "5.59.6",
|
||||||
"eslint-visitor-keys": "^3.3.0"
|
"eslint-visitor-keys": "^3.3.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -4956,9 +4946,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/axe-core": {
|
"node_modules/axe-core": {
|
||||||
"version": "4.7.0",
|
"version": "4.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.1.tgz",
|
||||||
"integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==",
|
"integrity": "sha512-sCXXUhA+cljomZ3ZAwb8i1p3oOlkABzPy08ZDAoGcYuvtBPlQ1Ytde129ArXyHWDhfeewq7rlx9F+cUx2SSlkg==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
|
@ -5511,9 +5501,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001487",
|
"version": "1.0.30001488",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001487.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001488.tgz",
|
||||||
"integrity": "sha512-83564Z3yWGqXsh2vaH/mhXfEM0wX+NlBCm1jYHOb97TrTWJEmPTccZgeLTPBUUb0PNVo+oomb7wkimZBIERClA==",
|
"integrity": "sha512-NORIQuuL4xGpIy6iCCQGN4iFjlBXtfKWIenlUuyZJumLRIindLb7wXM+GO8erEhb7vXfcnf4BAg2PrSDN5TNLQ==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
|
@ -6749,9 +6739,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.4.394",
|
"version": "1.4.397",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.394.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.397.tgz",
|
||||||
"integrity": "sha512-0IbC2cfr8w5LxTz+nmn2cJTGafsK9iauV2r5A5scfzyovqLrxuLoxOHE5OBobP3oVIggJT+0JfKnw9sm87c8Hw=="
|
"integrity": "sha512-jwnPxhh350Q/aMatQia31KAIQdhEsYS0fFZ0BQQlN9tfvOEwShu6ZNwI4kL/xBabjcB/nTy6lSt17kNIluJZ8Q=="
|
||||||
},
|
},
|
||||||
"node_modules/emittery": {
|
"node_modules/emittery": {
|
||||||
"version": "0.8.1",
|
"version": "0.8.1",
|
||||||
|
@ -9146,9 +9136,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/is-core-module": {
|
"node_modules/is-core-module": {
|
||||||
"version": "2.12.0",
|
"version": "2.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
|
||||||
"integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==",
|
"integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"has": "^1.0.3"
|
"has": "^1.0.3"
|
||||||
},
|
},
|
||||||
|
@ -13879,9 +13869,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss-selector-parser": {
|
"node_modules/postcss-selector-parser": {
|
||||||
"version": "6.0.12",
|
"version": "6.0.13",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
|
||||||
"integrity": "sha512-NdxGCAZdRrwVI1sy59+Wzrh+pMMHxapGnpfenDVlMEXoOcvt4pGE0JLK9YY2F5dLxcFYA/YbVQKhcGU+FtSYQg==",
|
"integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cssesc": "^3.0.0",
|
"cssesc": "^3.0.0",
|
||||||
"util-deprecate": "^1.0.2"
|
"util-deprecate": "^1.0.2"
|
||||||
|
@ -15976,9 +15966,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/terser": {
|
"node_modules/terser": {
|
||||||
"version": "5.17.3",
|
"version": "5.17.4",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.17.3.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.17.4.tgz",
|
||||||
"integrity": "sha512-AudpAZKmZHkG9jueayypz4duuCFJMMNGRMwaPvQKWfxKedh8Z2x3OCoDqIIi1xx5+iwx1u6Au8XQcc9Lke65Yg==",
|
"integrity": "sha512-jcEKZw6UPrgugz/0Tuk/PVyLAPfMBJf5clnGueo45wTweoV8yh7Q7PEkhkJ5uuUbC7zAxEcG3tqNr1bstkQ8nw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/source-map": "^0.3.2",
|
"@jridgewell/source-map": "^0.3.2",
|
||||||
"acorn": "^8.5.0",
|
"acorn": "^8.5.0",
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
import {
|
import {
|
||||||
accountBillingPortalUrl,
|
accountBillingPortalUrl,
|
||||||
accountBillingSubscriptionUrl,
|
accountBillingSubscriptionUrl,
|
||||||
accountPasswordUrl, accountPhoneUrl, accountPhoneVerifyUrl,
|
accountPasswordUrl,
|
||||||
|
accountPhoneUrl,
|
||||||
|
accountPhoneVerifyUrl,
|
||||||
accountReservationSingleUrl,
|
accountReservationSingleUrl,
|
||||||
accountReservationUrl,
|
accountReservationUrl,
|
||||||
accountSettingsUrl,
|
accountSettingsUrl,
|
||||||
accountSubscriptionSingleUrl,
|
|
||||||
accountSubscriptionUrl,
|
accountSubscriptionUrl,
|
||||||
accountTokenUrl,
|
accountTokenUrl,
|
||||||
accountUrl, maybeWithBearerAuth,
|
accountUrl,
|
||||||
|
maybeWithBearerAuth,
|
||||||
tiersUrl,
|
tiersUrl,
|
||||||
withBasicAuth,
|
withBasicAuth,
|
||||||
withBearerAuth
|
withBearerAuth
|
||||||
|
@ -18,7 +20,7 @@ import subscriptionManager from "./SubscriptionManager";
|
||||||
import i18n from "i18next";
|
import i18n from "i18next";
|
||||||
import prefs from "./Prefs";
|
import prefs from "./Prefs";
|
||||||
import routes from "../components/routes";
|
import routes from "../components/routes";
|
||||||
import {fetchOrThrow, throwAppError, UnauthorizedError} from "./errors";
|
import {fetchOrThrow, UnauthorizedError} from "./errors";
|
||||||
|
|
||||||
const delayMillis = 45000; // 45 seconds
|
const delayMillis = 45000; // 45 seconds
|
||||||
const intervalMillis = 900000; // 15 minutes
|
const intervalMillis = 900000; // 15 minutes
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {useContext, useState} from 'react';
|
import {useContext, useState} from 'react';
|
||||||
import {
|
import {
|
||||||
Alert, ButtonGroup,
|
Alert,
|
||||||
CardActions,
|
CardActions,
|
||||||
CardContent, Chip,
|
CardContent,
|
||||||
FormControl, FormControlLabel, InputLabel,
|
Chip,
|
||||||
|
FormControl,
|
||||||
|
FormControlLabel,
|
||||||
LinearProgress,
|
LinearProgress,
|
||||||
Link,
|
Link,
|
||||||
Portal, Radio, RadioGroup,
|
Portal,
|
||||||
|
Radio,
|
||||||
|
RadioGroup,
|
||||||
Select,
|
Select,
|
||||||
Snackbar,
|
Snackbar,
|
||||||
Stack,
|
Stack,
|
||||||
|
@ -47,14 +51,12 @@ import {AccountContext} from "./App";
|
||||||
import DialogFooter from "./DialogFooter";
|
import DialogFooter from "./DialogFooter";
|
||||||
import {Paragraph} from "./styles";
|
import {Paragraph} from "./styles";
|
||||||
import CloseIcon from "@mui/icons-material/Close";
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
import {Check, ContentCopy, DeleteForever, Public} from "@mui/icons-material";
|
import {ContentCopy, Public} from "@mui/icons-material";
|
||||||
import MenuItem from "@mui/material/MenuItem";
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
import DialogContentText from "@mui/material/DialogContentText";
|
import DialogContentText from "@mui/material/DialogContentText";
|
||||||
import {IncorrectPasswordError, UnauthorizedError} from "../app/errors";
|
import {IncorrectPasswordError, UnauthorizedError} from "../app/errors";
|
||||||
import {ProChip} from "./SubscriptionPopup";
|
import {ProChip} from "./SubscriptionPopup";
|
||||||
import AddIcon from "@mui/icons-material/Add";
|
import AddIcon from "@mui/icons-material/Add";
|
||||||
import ListItemIcon from "@mui/material/ListItemIcon";
|
|
||||||
import ListItemText from "@mui/material/ListItemText";
|
|
||||||
|
|
||||||
const Account = () => {
|
const Account = () => {
|
||||||
if (!session.exists()) {
|
if (!session.exists()) {
|
||||||
|
@ -427,6 +429,7 @@ const AddPhoneNumberDialog = (props) => {
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
if (verificationCodeSent) {
|
if (verificationCodeSent) {
|
||||||
setVerificationCodeSent(false);
|
setVerificationCodeSent(false);
|
||||||
|
setCode("");
|
||||||
} else {
|
} else {
|
||||||
props.onClose();
|
props.onClose();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue