1package cloudflare
2
3import (
4	"context"
5	"encoding/json"
6	"fmt"
7	"github.com/pkg/errors"
8	"net/http"
9	"time"
10)
11
12// Magic Transit Static Routes Error messages
13const (
14	errMagicTransitStaticRouteNotModified = "When trying to modify static route, API returned modified: false"
15	errMagicTransitStaticRouteNotDeleted  = "When trying to delete static route, API returned deleted: false"
16)
17
18// MagicTransitStaticRouteScope contains information about a static route's scope
19type MagicTransitStaticRouteScope struct {
20	ColoRegions []string `json:"colo_regions,omitempty"`
21	ColoNames   []string `json:"colo_names,omitempty"`
22}
23
24// MagicTransitStaticRoute contains information about a static route
25type MagicTransitStaticRoute struct {
26	ID          string                       `json:"id,omitempty"`
27	Prefix      string                       `json:"prefix"`
28	CreatedOn   *time.Time                   `json:"created_on,omitempty"`
29	ModifiedOn  *time.Time                   `json:"modified_on,omitempty"`
30	Nexthop     string                       `json:"nexthop"`
31	Priority    int                          `json:"priority,omitempty"`
32	Description string                       `json:"description,omitempty"`
33	Weight      int                          `json:"weight,omitempty"`
34	Scope       MagicTransitStaticRouteScope `json:"scope,omitempty"`
35}
36
37// ListMagicTransitStaticRoutesResponse contains a response including Magic Transit static routes
38type ListMagicTransitStaticRoutesResponse struct {
39	Response
40	Result struct {
41		Routes []MagicTransitStaticRoute `json:"routes"`
42	} `json:"result"`
43}
44
45// GetMagicTransitStaticRouteResponse contains a response including exactly one static route
46type GetMagicTransitStaticRouteResponse struct {
47	Response
48	Result struct {
49		Route MagicTransitStaticRoute `json:"route"`
50	} `json:"result"`
51}
52
53// UpdateMagicTransitStaticRouteResponse contains a static route update response
54type UpdateMagicTransitStaticRouteResponse struct {
55	Response
56	Result struct {
57		Modified      bool                    `json:"modified"`
58		ModifiedRoute MagicTransitStaticRoute `json:"modified_route"`
59	} `json:"result"`
60}
61
62// DeleteMagicTransitStaticRouteResponse contains a static route deletion response
63type DeleteMagicTransitStaticRouteResponse struct {
64	Response
65	Result struct {
66		Deleted      bool                    `json:"deleted"`
67		DeletedRoute MagicTransitStaticRoute `json:"deleted_route"`
68	} `json:"result"`
69}
70
71// CreateMagicTransitStaticRoutesRequest is an array of static routes to create
72type CreateMagicTransitStaticRoutesRequest struct {
73	Routes []MagicTransitStaticRoute `json:"routes"`
74}
75
76// ListMagicTransitStaticRoutes lists all static routes for a given account
77//
78// API reference: https://api.cloudflare.com/#magic-transit-static-routes-list-routes
79func (api *API) ListMagicTransitStaticRoutes(ctx context.Context) ([]MagicTransitStaticRoute, error) {
80	if err := api.checkAccountID(); err != nil {
81		return []MagicTransitStaticRoute{}, err
82	}
83
84	uri := fmt.Sprintf("/accounts/%s/magic/routes", api.AccountID)
85	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
86	if err != nil {
87		return []MagicTransitStaticRoute{}, err
88	}
89
90	result := ListMagicTransitStaticRoutesResponse{}
91	if err := json.Unmarshal(res, &result); err != nil {
92		return []MagicTransitStaticRoute{}, errors.Wrap(err, errUnmarshalError)
93	}
94
95	return result.Result.Routes, nil
96}
97
98// GetMagicTransitStaticRoute returns exactly one static route
99//
100// API reference: https://api.cloudflare.com/#magic-transit-static-routes-route-details
101func (api *API) GetMagicTransitStaticRoute(ctx context.Context, id string) (MagicTransitStaticRoute, error) {
102	if err := api.checkAccountID(); err != nil {
103		return MagicTransitStaticRoute{}, err
104	}
105
106	uri := fmt.Sprintf("/accounts/%s/magic/routes/%s", api.AccountID, id)
107	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
108	if err != nil {
109		return MagicTransitStaticRoute{}, err
110	}
111
112	result := GetMagicTransitStaticRouteResponse{}
113	if err := json.Unmarshal(res, &result); err != nil {
114		return MagicTransitStaticRoute{}, errors.Wrap(err, errUnmarshalError)
115	}
116
117	return result.Result.Route, nil
118}
119
120// CreateMagicTransitStaticRoute creates a new static route
121//
122// API reference: https://api.cloudflare.com/#magic-transit-static-routes-create-routes
123func (api *API) CreateMagicTransitStaticRoute(ctx context.Context, route MagicTransitStaticRoute) ([]MagicTransitStaticRoute, error) {
124	if err := api.checkAccountID(); err != nil {
125		return []MagicTransitStaticRoute{}, err
126	}
127
128	uri := fmt.Sprintf("/accounts/%s/magic/routes", api.AccountID)
129	res, err := api.makeRequestContext(ctx, http.MethodPost, uri, CreateMagicTransitStaticRoutesRequest{
130		Routes: []MagicTransitStaticRoute{
131			route,
132		},
133	})
134
135	if err != nil {
136		return []MagicTransitStaticRoute{}, err
137	}
138
139	result := ListMagicTransitStaticRoutesResponse{}
140	if err := json.Unmarshal(res, &result); err != nil {
141		return []MagicTransitStaticRoute{}, errors.Wrap(err, errUnmarshalError)
142	}
143
144	return result.Result.Routes, nil
145}
146
147// UpdateMagicTransitStaticRoute updates a static route
148//
149// API reference: https://api.cloudflare.com/#magic-transit-static-routes-update-route
150func (api *API) UpdateMagicTransitStaticRoute(ctx context.Context, id string, route MagicTransitStaticRoute) (MagicTransitStaticRoute, error) {
151	if err := api.checkAccountID(); err != nil {
152		return MagicTransitStaticRoute{}, err
153	}
154
155	uri := fmt.Sprintf("/accounts/%s/magic/routes/%s", api.AccountID, id)
156	res, err := api.makeRequestContext(ctx, http.MethodPut, uri, route)
157
158	if err != nil {
159		return MagicTransitStaticRoute{}, err
160	}
161
162	result := UpdateMagicTransitStaticRouteResponse{}
163	if err := json.Unmarshal(res, &result); err != nil {
164		return MagicTransitStaticRoute{}, errors.Wrap(err, errUnmarshalError)
165	}
166
167	if !result.Result.Modified {
168		return MagicTransitStaticRoute{}, errors.New(errMagicTransitStaticRouteNotModified)
169	}
170
171	return result.Result.ModifiedRoute, nil
172}
173
174// DeleteMagicTransitStaticRoute deletes a static route
175//
176// API reference: https://api.cloudflare.com/#magic-transit-static-routes-delete-route
177func (api *API) DeleteMagicTransitStaticRoute(ctx context.Context, id string) (MagicTransitStaticRoute, error) {
178	if err := api.checkAccountID(); err != nil {
179		return MagicTransitStaticRoute{}, err
180	}
181
182	uri := fmt.Sprintf("/accounts/%s/magic/routes/%s", api.AccountID, id)
183	res, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil)
184
185	if err != nil {
186		return MagicTransitStaticRoute{}, err
187	}
188
189	result := DeleteMagicTransitStaticRouteResponse{}
190	if err := json.Unmarshal(res, &result); err != nil {
191		return MagicTransitStaticRoute{}, errors.Wrap(err, errUnmarshalError)
192	}
193
194	if !result.Result.Deleted {
195		return MagicTransitStaticRoute{}, errors.New(errMagicTransitStaticRouteNotDeleted)
196	}
197
198	return result.Result.DeletedRoute, nil
199}
200