-
-
Notifications
You must be signed in to change notification settings - Fork 506
Expand file tree
/
Copy pathStackEndpoints.cs
More file actions
315 lines (295 loc) · 19.1 KB
/
Copy pathStackEndpoints.cs
File metadata and controls
315 lines (295 loc) · 19.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
using System.Text.Json;
using Exceptionless.Core.Authorization;
using Exceptionless.Core.Extensions;
using Exceptionless.Core.Models;
using Exceptionless.Web.Api.Filters;
using Exceptionless.Web.Api.Infrastructure;
using Exceptionless.Web.Api.Messages;
using Exceptionless.Web.Api.Results;
using Exceptionless.Web.Models;
using Foundatio.Mediator;
using HttpIResult = Microsoft.AspNetCore.Http.IResult;
using Microsoft.AspNetCore.Mvc;
using Exceptionless.Web.Utility.OpenApi;
namespace Exceptionless.Web.Api.Endpoints;
public static class StackEndpoints
{
public static IEndpointRouteBuilder MapStackEndpoints(this IEndpointRouteBuilder endpoints)
{
var group = endpoints.MapGroup("api/v2")
.AddEndpointFilter<AutoValidationEndpointFilter>()
.WithTags("Stack");
// GET by id
group.MapGet("stacks/{id:objectid}", async (string id, HttpContext httpContext, IMediator mediator, IMediatorResultMapper<HttpIResult> resultMapper, string? offset = null)
=> (await mediator.InvokeAsync<Result<Stack>>(new GetStackById(id, offset, httpContext))).ToHttpResult(resultMapper))
.WithName("GetStackById")
.RequireAuthorization(AuthorizationRoles.StacksReadPolicy)
.Produces<Stack>()
.ProducesProblem(StatusCodes.Status404NotFound)
.WithSummary("Get by id")
.WithMetadata(new EndpointDocumentation {
ParameterDescriptions = new() {
["id"] = "The identifier of the stack.",
["offset"] = "The time offset in minutes that controls what data is returned based on the `time` filter. This is used for time zone support.",
},
ResponseDescriptions = new() {
["404"] = "The stack could not be found.",
}
});
// Mark fixed
group.MapPost("stacks/{ids:objectids}/mark-fixed", async (string ids, HttpContext httpContext, IMediator mediator, IMediatorResultMapper<HttpIResult> resultMapper, string? version = null)
=> (await mediator.InvokeAsync<Result>(new MarkStacksFixed(ids, version, httpContext))).ToHttpResult(resultMapper))
.RequireAuthorization(AuthorizationRoles.StacksWritePolicy)
.Produces(StatusCodes.Status200OK)
.ProducesProblem(StatusCodes.Status404NotFound)
.WithSummary("Mark fixed")
.WithMetadata(new EndpointDocumentation {
ParameterDescriptions = new() {
["ids"] = "A comma-delimited list of stack identifiers.",
["version"] = "A version number that the stack was fixed in.",
},
ResponseDescriptions = new() {
["200"] = "The stacks were marked as fixed.",
["404"] = "One or more stacks could not be found.",
}
});
// Mark fixed - Zapier legacy v1
endpoints.MapPost("api/v1/stack/markfixed", async (HttpContext httpContext, IMediator mediator, IMediatorResultMapper<HttpIResult> resultMapper, [FromBody] JsonDocument data)
=> (await mediator.InvokeAsync<Result>(new MarkStacksFixedByZapier(data, httpContext))).ToHttpResult(resultMapper))
.RequireAuthorization(AuthorizationRoles.StacksWritePolicy)
.ExcludeFromDescription();
// Mark fixed - Zapier v2 (no id in route)
group.MapPost("stacks/mark-fixed", async (HttpContext httpContext, IMediator mediator, IMediatorResultMapper<HttpIResult> resultMapper, [FromBody] JsonDocument data)
=> (await mediator.InvokeAsync<Result>(new MarkStacksFixedByZapier(data, httpContext))).ToHttpResult(resultMapper))
.RequireAuthorization(AuthorizationRoles.StacksWritePolicy)
.ExcludeFromDescription();
// Snooze
group.MapPost("stacks/{ids:objectids}/mark-snoozed", async (string ids, HttpContext httpContext, IMediator mediator, IMediatorResultMapper<HttpIResult> resultMapper, DateTime? snoozeUntilUtc = null)
=> (await mediator.InvokeAsync<Result>(new SnoozeStacks(ids, snoozeUntilUtc ?? DateTime.MinValue, httpContext))).ToHttpResult(resultMapper))
.RequireAuthorization(AuthorizationRoles.StacksWritePolicy)
.Produces(StatusCodes.Status200OK)
.ProducesProblem(StatusCodes.Status404NotFound)
.WithSummary("Mark the selected stacks as snoozed")
.WithMetadata(new EndpointDocumentation {
ParameterDescriptions = new() {
["ids"] = "A comma-delimited list of stack identifiers.",
["snoozeUntilUtc"] = "A time that the stack should be snoozed until.",
},
ResponseDescriptions = new() {
["200"] = "The stacks were snoozed.",
["404"] = "One or more stacks could not be found.",
}
});
// Add link
group.MapPost("stacks/{id:objectid}/add-link", async (string id, HttpContext httpContext, IMediator mediator, IMediatorResultMapper<HttpIResult> resultMapper, [FromBody] ValueFromBody<string?> url)
=> (await mediator.InvokeAsync<Result>(new AddStackLink(id, url, httpContext))).ToHttpResult(resultMapper))
.RequireAuthorization(AuthorizationRoles.StacksWritePolicy)
.Accepts<ValueFromBody<string?>>("application/json", "application/*+json")
.Produces(StatusCodes.Status200OK)
.ProducesProblem(StatusCodes.Status400BadRequest)
.ProducesProblem(StatusCodes.Status404NotFound)
.WithSummary("Add reference link")
.WithMetadata(new EndpointDocumentation {
RequestBodyDescription = "The reference link.",
ParameterDescriptions = new() {
["id"] = "The identifier of the stack.",
},
ResponseDescriptions = new() {
["400"] = "Invalid reference link.",
["404"] = "The stack could not be found.",
}
});
// Add link - Zapier legacy v1
endpoints.MapPost("api/v1/stack/addlink", async (HttpContext httpContext, IMediator mediator, IMediatorResultMapper<HttpIResult> resultMapper, [FromBody] JsonDocument data)
=> (await mediator.InvokeAsync<Result>(new AddStackLinkByZapier(data, httpContext))).ToHttpResult(resultMapper))
.RequireAuthorization(AuthorizationRoles.StacksWritePolicy)
.ExcludeFromDescription();
// Add link - Zapier v2 (no id in route)
group.MapPost("stacks/add-link", async (HttpContext httpContext, IMediator mediator, IMediatorResultMapper<HttpIResult> resultMapper, [FromBody] JsonDocument data)
=> (await mediator.InvokeAsync<Result>(new AddStackLinkByZapier(data, httpContext))).ToHttpResult(resultMapper))
.RequireAuthorization(AuthorizationRoles.StacksWritePolicy)
.ExcludeFromDescription();
// Remove link
group.MapPost("stacks/{id:objectid}/remove-link", async (string id, HttpContext httpContext, IMediator mediator, IMediatorResultMapper<HttpIResult> resultMapper, [FromBody] ValueFromBody<string> url)
=> (await mediator.InvokeAsync<Result>(new RemoveStackLink(id, url, httpContext))).ToHttpResult(resultMapper))
.RequireAuthorization(AuthorizationRoles.StacksWritePolicy)
.Accepts<ValueFromBody<string>>("application/json", "application/*+json")
.Produces(StatusCodes.Status204NoContent)
.ProducesProblem(StatusCodes.Status400BadRequest)
.ProducesProblem(StatusCodes.Status404NotFound)
.WithSummary("Remove reference link")
.WithMetadata(new EndpointDocumentation {
RequestBodyDescription = "The reference link.",
ParameterDescriptions = new() {
["id"] = "The identifier of the stack.",
},
ResponseDescriptions = new() {
["204"] = "The reference link was removed.",
["400"] = "Invalid reference link.",
["404"] = "The stack could not be found.",
}
});
// Mark critical
group.MapPost("stacks/{ids:objectids}/mark-critical", async (string ids, HttpContext httpContext, IMediator mediator, IMediatorResultMapper<HttpIResult> resultMapper)
=> (await mediator.InvokeAsync<Result>(new MarkStacksCritical(ids, httpContext))).ToHttpResult(resultMapper))
.RequireAuthorization(AuthorizationRoles.StacksWritePolicy)
.Produces(StatusCodes.Status200OK)
.ProducesProblem(StatusCodes.Status404NotFound)
.WithSummary("Mark future occurrences as critical")
.WithMetadata(new EndpointDocumentation {
ParameterDescriptions = new() {
["ids"] = "A comma-delimited list of stack identifiers.",
},
ResponseDescriptions = new() {
["404"] = "One or more stacks could not be found.",
}
});
// Mark not critical
group.MapDelete("stacks/{ids:objectids}/mark-critical", async (string ids, HttpContext httpContext, IMediator mediator, IMediatorResultMapper<HttpIResult> resultMapper)
=> (await mediator.InvokeAsync<Result>(new MarkStacksNotCritical(ids, httpContext))).ToHttpResult(resultMapper))
.RequireAuthorization(AuthorizationRoles.StacksWritePolicy)
.Produces(StatusCodes.Status204NoContent)
.ProducesProblem(StatusCodes.Status404NotFound)
.WithSummary("Mark future occurrences as not critical")
.WithMetadata(new EndpointDocumentation {
ParameterDescriptions = new() {
["ids"] = "A comma-delimited list of stack identifiers.",
},
ResponseDescriptions = new() {
["204"] = "The stacks were marked as not critical.",
["404"] = "One or more stacks could not be found.",
}
});
// Change status
group.MapPost("stacks/{ids:objectids}/change-status", async (string ids, HttpContext httpContext, IMediator mediator, IMediatorResultMapper<HttpIResult> resultMapper, StackStatus? status = null)
=> (await mediator.InvokeAsync<Result>(new ChangeStacksStatus(ids, status ?? StackStatus.Open, httpContext))).ToHttpResult(resultMapper))
.RequireAuthorization(AuthorizationRoles.StacksWritePolicy)
.Produces(StatusCodes.Status200OK)
.ProducesProblem(StatusCodes.Status404NotFound)
.WithSummary("Change stack status")
.WithMetadata(new EndpointDocumentation {
ParameterDescriptions = new() {
["ids"] = "A comma-delimited list of stack identifiers.",
["status"] = "The status that the stack should be changed to.",
},
ResponseDescriptions = new() {
["404"] = "One or more stacks could not be found.",
}
});
// Promote
group.MapPost("stacks/{id:objectid}/promote", async (string id, HttpContext httpContext, IMediator mediator, IMediatorResultMapper<HttpIResult> resultMapper)
=> (await mediator.InvokeAsync<Result>(new PromoteStack(id, httpContext))).ToHttpResult(resultMapper))
.RequireAuthorization(AuthorizationRoles.UserPolicy)
.Produces(StatusCodes.Status200OK)
.ProducesProblem(StatusCodes.Status404NotFound)
.ProducesProblem(StatusCodes.Status426UpgradeRequired)
.Produces(StatusCodes.Status501NotImplemented)
.WithSummary("Promote to external service")
.WithMetadata(new EndpointDocumentation {
ParameterDescriptions = new() {
["id"] = "The identifier of the stack.",
},
ResponseDescriptions = new() {
["404"] = "The stack could not be found.",
["426"] = "Promote to External is a premium feature used to promote an error stack to an external system.",
["501"] = "No promoted web hooks are configured for this project.",
}
});
// Delete
group.MapDelete("stacks/{ids:objectids}", async (string ids, HttpContext httpContext, IMediator mediator, IMediatorResultMapper<HttpIResult> resultMapper)
=> (await mediator.InvokeAsync<Result<WorkInProgressResult>>(new DeleteStacks(ids, httpContext))).ToHttpResult(resultMapper))
.RequireAuthorization(AuthorizationRoles.UserPolicy)
.Produces<WorkInProgressResult>(StatusCodes.Status202Accepted)
.ProducesProblem(StatusCodes.Status400BadRequest)
.ProducesProblem(StatusCodes.Status404NotFound)
.ProducesProblem(StatusCodes.Status500InternalServerError)
.WithSummary("Remove")
.WithMetadata(new EndpointDocumentation {
ParameterDescriptions = new() {
["ids"] = "A comma-delimited list of stack identifiers.",
},
ResponseDescriptions = new() {
["202"] = "Accepted",
["400"] = "One or more validation errors occurred.",
["404"] = "One or more stacks were not found.",
["500"] = "An error occurred while deleting one or more stacks.",
}
});
// Get all
group.MapGet("stacks", async (HttpContext httpContext, IMediator mediator, IMediatorResultMapper<HttpIResult> resultMapper, string? filter = null, string? sort = null, string? time = null, string? offset = null, string? mode = null, int page = 1, int limit = 10)
=> (await mediator.InvokeAsync<Result<PagedResult<object>>>(new GetAllStacks(filter, sort, time, offset, mode, page, limit, httpContext))).ToHttpResult(resultMapper))
.RequireAuthorization(AuthorizationRoles.StacksReadPolicy)
.Produces<IReadOnlyCollection<Stack>>()
.ProducesProblem(StatusCodes.Status400BadRequest)
.ProducesProblem(StatusCodes.Status426UpgradeRequired)
.WithSummary("Get all")
.WithMetadata(new EndpointDocumentation {
ParameterDescriptions = new() {
["filter"] = "A filter that controls what data is returned from the server.",
["sort"] = "Controls the sort order that the data is returned in. In this example -date returns the results descending by date.",
["time"] = "The time filter that limits the data being returned to a specific date range.",
["offset"] = "The time offset in minutes that controls what data is returned based on the time filter. This is used for time zone support.",
["mode"] = "If no mode is set then the whole stack object will be returned. If the mode is set to summary than a lightweight object will be returned.",
["page"] = "The page parameter is used for pagination. This value must be greater than 0.",
["limit"] = "A limit on the number of objects to be returned. Limit can range between 1 and 100 items.",
},
ResponseDescriptions = new() {
["400"] = "Invalid filter.",
["426"] = ApiFilterPolicy.PremiumSearchUpgradeMessage,
}
});
// Get by organization
group.MapGet("organizations/{organizationId:objectid}/stacks", async (string organizationId, HttpContext httpContext, IMediator mediator, IMediatorResultMapper<HttpIResult> resultMapper, string? filter = null, string? sort = null, string? time = null, string? offset = null, string? mode = null, int page = 1, int limit = 10)
=> (await mediator.InvokeAsync<Result<PagedResult<object>>>(new GetStacksByOrganization(organizationId, filter, sort, time, offset, mode, page, limit, httpContext))).ToHttpResult(resultMapper))
.RequireAuthorization(AuthorizationRoles.StacksReadPolicy)
.Produces<IReadOnlyCollection<Stack>>()
.ProducesProblem(StatusCodes.Status400BadRequest)
.ProducesProblem(StatusCodes.Status404NotFound)
.ProducesProblem(StatusCodes.Status426UpgradeRequired)
.WithSummary("Get by organization")
.WithMetadata(new EndpointDocumentation {
ParameterDescriptions = new() {
["organizationId"] = "The identifier of the organization.",
["filter"] = "A filter that controls what data is returned from the server.",
["sort"] = "Controls the sort order that the data is returned in. In this example -date returns the results descending by date.",
["time"] = "The time filter that limits the data being returned to a specific date range.",
["offset"] = "The time offset in minutes that controls what data is returned based on the time filter. This is used for time zone support.",
["mode"] = "If no mode is set then the whole stack object will be returned. If the mode is set to summary than a lightweight object will be returned.",
["page"] = "The page parameter is used for pagination. This value must be greater than 0.",
["limit"] = "A limit on the number of objects to be returned. Limit can range between 1 and 100 items.",
},
ResponseDescriptions = new() {
["400"] = "Invalid filter.",
["404"] = "The organization could not be found.",
["426"] = ApiFilterPolicy.SuspendedOrPremiumSearchUpgradeDescription,
}
});
// Get by project
group.MapGet("projects/{projectId:objectid}/stacks", async (string projectId, HttpContext httpContext, IMediator mediator, IMediatorResultMapper<HttpIResult> resultMapper, string? filter = null, string? sort = null, string? time = null, string? offset = null, string? mode = null, int page = 1, int limit = 10)
=> (await mediator.InvokeAsync<Result<PagedResult<object>>>(new GetStacksByProject(projectId, filter, sort, time, offset, mode, page, limit, httpContext))).ToHttpResult(resultMapper))
.RequireAuthorization(AuthorizationRoles.StacksReadPolicy)
.Produces<IReadOnlyCollection<Stack>>()
.ProducesProblem(StatusCodes.Status400BadRequest)
.ProducesProblem(StatusCodes.Status404NotFound)
.ProducesProblem(StatusCodes.Status426UpgradeRequired)
.WithSummary("Get by project")
.WithMetadata(new EndpointDocumentation {
ParameterDescriptions = new() {
["projectId"] = "The identifier of the project.",
["filter"] = "A filter that controls what data is returned from the server.",
["sort"] = "Controls the sort order that the data is returned in. In this example -date returns the results descending by date.",
["time"] = "The time filter that limits the data being returned to a specific date range.",
["offset"] = "The time offset in minutes that controls what data is returned based on the time filter. This is used for time zone support.",
["mode"] = "If no mode is set then the whole stack object will be returned. If the mode is set to summary than a lightweight object will be returned.",
["page"] = "The page parameter is used for pagination. This value must be greater than 0.",
["limit"] = "A limit on the number of objects to be returned. Limit can range between 1 and 100 items.",
},
ResponseDescriptions = new() {
["400"] = "Invalid filter.",
["404"] = "The organization could not be found.",
["426"] = ApiFilterPolicy.SuspendedOrPremiumSearchUpgradeDescription,
}
});
return endpoints;
}
}