|
8 | 8 | from api import views |
9 | 9 |
|
10 | 10 |
|
11 | | -router = DefaultRouter(trailing_slash=False) |
| 11 | +class OptionalSlashRouter(DefaultRouter): |
| 12 | + """Router that accepts both trailing-slash and no-trailing-slash URLs.""" |
| 13 | + |
| 14 | + def __init__(self, *args, **kwargs): |
| 15 | + super().__init__(*args, **kwargs) |
| 16 | + self.trailing_slash = '/?' |
| 17 | + |
| 18 | + |
| 19 | +router = OptionalSlashRouter() |
| 20 | +router.register(r'workspaces', views.WorkspaceViewSet, basename='workspace') |
| 21 | +router.register(r'apps', views.AppViewSet, basename='app') |
| 22 | +router.register(r'keys', views.KeyViewSet, basename='key') |
| 23 | +router.register(r'tokens', views.TokenViewSet, basename='token') |
| 24 | +router.register(r'limits/specs', views.LimitSpecViewSet, basename='limitspec') |
| 25 | +router.register(r'limits/plans', views.LimitPlanViewSet, basename='limitplan') |
| 26 | + |
12 | 27 | extra = getattr(settings, setting_name('TRAILING_SLASH'), True) and '/' or '' |
13 | 28 |
|
14 | 29 | # Add the generated REST URLs and login/logout endpoint |
|
17 | 32 | re_path(r'auth/login/?$', views.AuthLoginView.as_view({"post": "login"})), |
18 | 33 | re_path(r'auth/token/?$', views.AuthTokenView.as_view({"post": "token"})), |
19 | 34 | re_path(r'auth/token/(?P<key>[-_\w]+)/?$', views.AuthTokenView.as_view({"get": "token"})), |
20 | | - # Workspaces management URLs (keep workspaces prefix, no user prefix) |
21 | | - re_path(r'^workspaces/?$', |
22 | | - views.WorkspaceViewSet.as_view({'get': 'list', 'post': 'create'}), |
23 | | - name='workspace_list'), |
24 | | - re_path(r'^workspaces/(?P<name>[-_\w]+)/?$', |
25 | | - views.WorkspaceViewSet.as_view( |
26 | | - {'get': 'retrieve', 'patch': 'partial_update', 'delete': 'destroy'}), |
27 | | - name='workspace_detail'), |
| 35 | + # Workspace sub-resources (members, invitations) |
28 | 36 | re_path(r'^workspaces/(?P<name>[-_\w]+)/members/?$', |
29 | 37 | views.WorkspaceMemberViewSet.as_view({'get': 'list'}), |
30 | 38 | name='workspace_member_list'), |
|
38 | 46 | re_path(r'^workspaces/(?P<name>[-_\w]+)/invitations/(?P<uid>[-_\w]+)/?$', |
39 | 47 | views.WorkspaceInvitationViewSet.as_view({'get': 'retrieve', 'delete': 'destroy'}), |
40 | 48 | name='workspace_invitation_detail'), |
41 | | - # limits |
42 | | - re_path( |
43 | | - r'^limits/specs/?$', |
44 | | - views.LimitSpecViewSet.as_view({'get': 'list'})), |
45 | | - re_path( |
46 | | - r'^limits/plans/?$', |
47 | | - views.LimitPlanViewSet.as_view({'get': 'list'})), |
48 | | - re_path( |
49 | | - r'^limits/plans/(?P<id>[-.\w]+)/?$', |
50 | | - views.LimitPlanViewSet.as_view({'get': 'retrieve'})), |
51 | 49 | # application release components |
52 | 50 | re_path( |
53 | 51 | r"^apps/(?P<id>{})/build/?$".format(settings.APP_URL_REGEX), |
|
112 | 110 | # application services |
113 | 111 | re_path( |
114 | 112 | r"^apps/(?P<id>{})/services/?$".format(settings.APP_URL_REGEX), |
115 | | - views.ServiceViewSet.as_view({'post': 'create_or_update', |
| 113 | + views.ServiceViewSet.as_view({'post': 'upsert', |
116 | 114 | 'get': 'list', 'delete': 'destroy'})), |
117 | 115 | # application settings |
118 | 116 | re_path( |
|
164 | 162 | re_path( |
165 | 163 | r'^apps/(?P<id>{})/certs/?$'.format(settings.APP_URL_REGEX), |
166 | 164 | views.CertificateViewSet.as_view({'get': 'list', 'post': 'create'})), |
167 | | - # application actions |
168 | | - re_path( |
169 | | - r"^apps/(?P<id>{})/run/?$".format(settings.APP_URL_REGEX), |
170 | | - views.AppViewSet.as_view({'post': 'run'})), |
171 | | - # apps base endpoint |
172 | | - re_path( |
173 | | - r"^apps/(?P<id>{})/?$".format(settings.APP_URL_REGEX), |
174 | | - views.AppViewSet.as_view({'get': 'retrieve', 'patch': 'transfer', 'delete': 'destroy'})), |
175 | | - re_path( |
176 | | - r'^apps/?$', |
177 | | - views.AppViewSet.as_view({'get': 'list', 'post': 'create'})), |
178 | | - # key |
179 | | - re_path( |
180 | | - r'^keys/(?P<id>.+)/?$', |
181 | | - views.KeyViewSet.as_view({'get': 'retrieve', 'delete': 'destroy'})), |
182 | | - re_path( |
183 | | - r'^keys/?$', |
184 | | - views.KeyViewSet.as_view({'get': 'list', 'post': 'create'})), |
185 | 165 | # hooks |
186 | 166 | re_path( |
187 | 167 | r'^hooks/keys/(?P<id>{})/(?P<username>[\w.@+-]+)/?$'.format(settings.APP_URL_REGEX), |
|
206 | 186 | re_path( |
207 | 187 | r"^apps/(?P<id>{})/gateways/?$".format(settings.APP_URL_REGEX), |
208 | 188 | views.GatewayViewSet.as_view( |
209 | | - {'post': 'create_or_update', 'get': 'list', 'delete': 'destroy'})), |
| 189 | + {'post': 'upsert', 'get': 'list', 'delete': 'destroy'})), |
210 | 190 | # routes |
211 | 191 | re_path( |
212 | 192 | r"^apps/(?P<id>{})/routes/(?P<name>{})?/?$".format( |
|
224 | 204 | re_path( |
225 | 205 | r"^apps/(?P<id>{})/routes/(?P<name>{})/rules/?$".format( |
226 | 206 | settings.APP_URL_REGEX, settings.NAME_REGEX), |
227 | | - views.RouteViewSet.as_view({'get': 'get', 'put': 'set'})), |
| 207 | + views.RouteRulesViewSet.as_view({'get': 'retrieve', 'put': 'update'})), |
228 | 208 | re_path( |
229 | 209 | r'^apps/(?P<id>{})/metrics/?$'.format(settings.APP_URL_REGEX), |
230 | 210 | views.MetricView.as_view({'get': 'metric'})), |
|
245 | 225 | re_path( |
246 | 226 | r'^prometheus/(?P<workspace>[-\w]+)/(?P<path>.+)/?$', |
247 | 227 | views.PrometheusProxyView.as_view()), |
248 | | - # tokens |
249 | | - re_path(r'^tokens/?$', views.TokenViewSet.as_view({'get': 'list'})), |
250 | | - re_path( |
251 | | - r"^tokens/(?P<pk>[-_\w]+)/?$", |
252 | | - views.TokenViewSet.as_view({'get': 'retrieve', 'delete': 'destroy'})), |
253 | 228 | ] |
254 | 229 |
|
255 | 230 | metric_urlpatterns = [ |
|
0 commit comments