Remove awkward subscription id
This commit is contained in:
parent
9131d3d521
commit
cc309e87e9
12 changed files with 67 additions and 104 deletions
|
@ -76,6 +76,7 @@ var (
|
|||
errHTTPForbidden = &errHTTP{40301, http.StatusForbidden, "forbidden", "https://ntfy.sh/docs/publish/#authentication"}
|
||||
errHTTPConflictUserExists = &errHTTP{40901, http.StatusConflict, "conflict: user already exists", ""}
|
||||
errHTTPConflictTopicReserved = &errHTTP{40902, http.StatusConflict, "conflict: access control entry for topic or topic pattern already exists", ""}
|
||||
errHTTPConflictSubscriptionExists = &errHTTP{40903, http.StatusConflict, "conflict: topic subscription already exists", ""}
|
||||
errHTTPEntityTooLargeAttachment = &errHTTP{41301, http.StatusRequestEntityTooLarge, "attachment too large, or bandwidth limit reached", "https://ntfy.sh/docs/publish/#limitations"}
|
||||
errHTTPEntityTooLargeMatrixRequest = &errHTTP{41302, http.StatusRequestEntityTooLarge, "Matrix request is larger than the max allowed length", ""}
|
||||
errHTTPEntityTooLargeJSONBody = &errHTTP{41303, http.StatusRequestEntityTooLarge, "JSON body too large", ""}
|
||||
|
|
|
@ -39,8 +39,6 @@ import (
|
|||
- tiers
|
||||
- api
|
||||
- tokens
|
||||
- LOW: UI: Flickering upgrade banner when logging in
|
||||
- LOW: get rid of reservation id, replace with DELETE X-Topic: ...
|
||||
|
||||
*/
|
||||
|
||||
|
@ -98,7 +96,6 @@ var (
|
|||
apiAccountBillingSubscriptionCheckoutSuccessTemplate = "/v1/account/billing/subscription/success/{CHECKOUT_SESSION_ID}"
|
||||
apiAccountBillingSubscriptionCheckoutSuccessRegex = regexp.MustCompile(`/v1/account/billing/subscription/success/(.+)$`)
|
||||
apiAccountReservationSingleRegex = regexp.MustCompile(`/v1/account/reservation/([-_A-Za-z0-9]{1,64})$`)
|
||||
apiAccountSubscriptionSingleRegex = regexp.MustCompile(`^/v1/account/subscription/([-_A-Za-z0-9]{16})$`)
|
||||
staticRegex = regexp.MustCompile(`^/static/.+`)
|
||||
docsRegex = regexp.MustCompile(`^/docs(|/.*)$`)
|
||||
fileRegex = regexp.MustCompile(`^/file/([-_A-Za-z0-9]{1,64})(?:\.[A-Za-z0-9]{1,16})?$`)
|
||||
|
@ -404,9 +401,9 @@ func (s *Server) handleInternal(w http.ResponseWriter, r *http.Request, v *visit
|
|||
return s.ensureUser(s.withAccountSync(s.handleAccountSettingsChange))(w, r, v)
|
||||
} else if r.Method == http.MethodPost && r.URL.Path == apiAccountSubscriptionPath {
|
||||
return s.ensureUser(s.withAccountSync(s.handleAccountSubscriptionAdd))(w, r, v)
|
||||
} else if r.Method == http.MethodPatch && apiAccountSubscriptionSingleRegex.MatchString(r.URL.Path) {
|
||||
} else if r.Method == http.MethodPatch && r.URL.Path == apiAccountSubscriptionPath {
|
||||
return s.ensureUser(s.withAccountSync(s.handleAccountSubscriptionChange))(w, r, v)
|
||||
} else if r.Method == http.MethodDelete && apiAccountSubscriptionSingleRegex.MatchString(r.URL.Path) {
|
||||
} else if r.Method == http.MethodDelete && r.URL.Path == apiAccountSubscriptionPath {
|
||||
return s.ensureUser(s.withAccountSync(s.handleAccountSubscriptionDelete))(w, r, v)
|
||||
} else if r.Method == http.MethodPost && r.URL.Path == apiAccountReservationPath {
|
||||
return s.ensureUser(s.withAccountSync(s.handleAccountReservationAdd))(w, r, v)
|
||||
|
|
|
@ -12,8 +12,6 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
subscriptionIDLength = 16
|
||||
subscriptionIDPrefix = "su_"
|
||||
syncTopicAccountSyncEvent = "sync"
|
||||
tokenExpiryDuration = 72 * time.Hour // Extend tokens by this much
|
||||
)
|
||||
|
@ -323,52 +321,36 @@ func (s *Server) handleAccountSubscriptionAdd(w http.ResponseWriter, r *http.Req
|
|||
return err
|
||||
}
|
||||
u := v.User()
|
||||
if u.Prefs == nil {
|
||||
u.Prefs = &user.Prefs{}
|
||||
prefs := u.Prefs
|
||||
if prefs == nil {
|
||||
prefs = &user.Prefs{}
|
||||
}
|
||||
newSubscription.ID = "" // Client cannot set ID
|
||||
for _, subscription := range u.Prefs.Subscriptions {
|
||||
for _, subscription := range prefs.Subscriptions {
|
||||
if newSubscription.BaseURL == subscription.BaseURL && newSubscription.Topic == subscription.Topic {
|
||||
newSubscription = subscription
|
||||
break
|
||||
return errHTTPConflictSubscriptionExists
|
||||
}
|
||||
}
|
||||
if newSubscription.ID == "" {
|
||||
newSubscription.ID = util.RandomStringPrefix(subscriptionIDPrefix, subscriptionIDLength)
|
||||
prefs := u.Prefs
|
||||
prefs.Subscriptions = append(prefs.Subscriptions, newSubscription)
|
||||
logvr(v, r).
|
||||
Tag(tagAccount).
|
||||
Fields(log.Context{
|
||||
"base_url": newSubscription.BaseURL,
|
||||
"topic": newSubscription.Topic,
|
||||
}).
|
||||
Debug("Adding subscription for user %s", u.Name)
|
||||
if err := s.userManager.ChangeSettings(u.ID, prefs); err != nil {
|
||||
return err
|
||||
}
|
||||
prefs.Subscriptions = append(prefs.Subscriptions, newSubscription)
|
||||
logvr(v, r).Tag(tagAccount).With(newSubscription).Debug("Adding subscription for user %s", u.Name)
|
||||
if err := s.userManager.ChangeSettings(u.ID, prefs); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.writeJSON(w, newSubscription)
|
||||
}
|
||||
|
||||
func (s *Server) handleAccountSubscriptionChange(w http.ResponseWriter, r *http.Request, v *visitor) error {
|
||||
matches := apiAccountSubscriptionSingleRegex.FindStringSubmatch(r.URL.Path)
|
||||
if len(matches) != 2 {
|
||||
return errHTTPInternalErrorInvalidPath
|
||||
}
|
||||
subscriptionID := matches[1]
|
||||
updatedSubscription, err := readJSONWithLimit[user.Subscription](r.Body, jsonBodyBytesLimit, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
u := v.User()
|
||||
if u.Prefs == nil || u.Prefs.Subscriptions == nil {
|
||||
prefs := u.Prefs
|
||||
if prefs == nil || prefs.Subscriptions == nil {
|
||||
return errHTTPNotFound
|
||||
}
|
||||
prefs := u.Prefs
|
||||
var subscription *user.Subscription
|
||||
for _, sub := range prefs.Subscriptions {
|
||||
if sub.ID == subscriptionID {
|
||||
if sub.BaseURL == updatedSubscription.BaseURL && sub.Topic == updatedSubscription.Topic {
|
||||
sub.DisplayName = updatedSubscription.DisplayName
|
||||
subscription = sub
|
||||
break
|
||||
|
@ -377,14 +359,7 @@ func (s *Server) handleAccountSubscriptionChange(w http.ResponseWriter, r *http.
|
|||
if subscription == nil {
|
||||
return errHTTPNotFound
|
||||
}
|
||||
logvr(v, r).
|
||||
Tag(tagAccount).
|
||||
Fields(log.Context{
|
||||
"base_url": subscription.BaseURL,
|
||||
"topic": subscription.Topic,
|
||||
"display_name": subscription.DisplayName,
|
||||
}).
|
||||
Debug("Changing subscription for user %s", u.Name)
|
||||
logvr(v, r).Tag(tagAccount).With(subscription).Debug("Changing subscription for user %s", u.Name)
|
||||
if err := s.userManager.ChangeSettings(u.ID, prefs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -392,31 +367,23 @@ func (s *Server) handleAccountSubscriptionChange(w http.ResponseWriter, r *http.
|
|||
}
|
||||
|
||||
func (s *Server) handleAccountSubscriptionDelete(w http.ResponseWriter, r *http.Request, v *visitor) error {
|
||||
matches := apiAccountSubscriptionSingleRegex.FindStringSubmatch(r.URL.Path)
|
||||
if len(matches) != 2 {
|
||||
return errHTTPInternalErrorInvalidPath
|
||||
}
|
||||
subscriptionID := matches[1]
|
||||
// DELETEs cannot have a body, and we don't want it in the path
|
||||
deleteBaseURL := readParam(r, "X-BaseURL", "BaseURL")
|
||||
deleteTopic := readParam(r, "X-Topic", "Topic")
|
||||
u := v.User()
|
||||
if u.Prefs == nil || u.Prefs.Subscriptions == nil {
|
||||
prefs := u.Prefs
|
||||
if prefs == nil || prefs.Subscriptions == nil {
|
||||
return nil
|
||||
}
|
||||
newSubscriptions := make([]*user.Subscription, 0)
|
||||
for _, subscription := range u.Prefs.Subscriptions {
|
||||
if subscription.ID == subscriptionID {
|
||||
logvr(v, r).
|
||||
Tag(tagAccount).
|
||||
Fields(log.Context{
|
||||
"base_url": subscription.BaseURL,
|
||||
"topic": subscription.Topic,
|
||||
}).
|
||||
Debug("Removing subscription for user %s", u.Name)
|
||||
for _, sub := range u.Prefs.Subscriptions {
|
||||
if sub.BaseURL == deleteBaseURL && sub.Topic == deleteTopic {
|
||||
logvr(v, r).Tag(tagAccount).With(sub).Debug("Removing subscription for user %s", u.Name)
|
||||
} else {
|
||||
newSubscriptions = append(newSubscriptions, subscription)
|
||||
newSubscriptions = append(newSubscriptions, sub)
|
||||
}
|
||||
}
|
||||
if len(newSubscriptions) < len(u.Prefs.Subscriptions) {
|
||||
prefs := u.Prefs
|
||||
if len(newSubscriptions) < len(prefs.Subscriptions) {
|
||||
prefs.Subscriptions = newSubscriptions
|
||||
if err := s.userManager.ChangeSettings(u.ID, prefs); err != nil {
|
||||
return err
|
||||
|
|
|
@ -214,13 +214,11 @@ func TestAccount_Subscription_AddUpdateDelete(t *testing.T) {
|
|||
require.Equal(t, 200, rr.Code)
|
||||
account, _ := util.UnmarshalJSON[apiAccountResponse](io.NopCloser(rr.Body))
|
||||
require.Equal(t, 1, len(account.Subscriptions))
|
||||
require.NotEmpty(t, account.Subscriptions[0].ID)
|
||||
require.Equal(t, "http://abc.com", account.Subscriptions[0].BaseURL)
|
||||
require.Equal(t, "def", account.Subscriptions[0].Topic)
|
||||
require.Nil(t, account.Subscriptions[0].DisplayName)
|
||||
|
||||
subscriptionID := account.Subscriptions[0].ID
|
||||
rr = request(t, s, "PATCH", "/v1/account/subscription/"+subscriptionID, `{"display_name": "ding dong"}`, map[string]string{
|
||||
rr = request(t, s, "PATCH", "/v1/account/subscription", `{"base_url": "http://abc.com", "topic": "def", "display_name": "ding dong"}`, map[string]string{
|
||||
"Authorization": util.BasicAuth("phil", "phil"),
|
||||
})
|
||||
require.Equal(t, 200, rr.Code)
|
||||
|
@ -231,13 +229,14 @@ func TestAccount_Subscription_AddUpdateDelete(t *testing.T) {
|
|||
require.Equal(t, 200, rr.Code)
|
||||
account, _ = util.UnmarshalJSON[apiAccountResponse](io.NopCloser(rr.Body))
|
||||
require.Equal(t, 1, len(account.Subscriptions))
|
||||
require.Equal(t, subscriptionID, account.Subscriptions[0].ID)
|
||||
require.Equal(t, "http://abc.com", account.Subscriptions[0].BaseURL)
|
||||
require.Equal(t, "def", account.Subscriptions[0].Topic)
|
||||
require.Equal(t, util.String("ding dong"), account.Subscriptions[0].DisplayName)
|
||||
|
||||
rr = request(t, s, "DELETE", "/v1/account/subscription/"+subscriptionID, "", map[string]string{
|
||||
rr = request(t, s, "DELETE", "/v1/account/subscription", "", map[string]string{
|
||||
"Authorization": util.BasicAuth("phil", "phil"),
|
||||
"X-BaseURL": "http://abc.com",
|
||||
"X-Topic": "def",
|
||||
})
|
||||
require.Equal(t, 200, rr.Code)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue