Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 159 additions & 0 deletions Metron Comicbook Database.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,10 @@ paths:
Update the rating of a specific collection item (must belong to authenticated user).
Read-tracking fields (is_read/date_read) are not editable here; use scrobble instead.
Requires authentication.

destroy:
Remove a specific collection item (must belong to authenticated user).
Requires authentication.
parameters:
- in: query
name: book_format
Expand Down Expand Up @@ -667,6 +671,10 @@ paths:
Update the rating of a specific collection item (must belong to authenticated user).
Read-tracking fields (is_read/date_read) are not editable here; use scrobble instead.
Requires authentication.

destroy:
Remove a specific collection item (must belong to authenticated user).
Requires authentication.
parameters:
- in: path
name: id
Expand Down Expand Up @@ -707,6 +715,10 @@ paths:
Update the rating of a specific collection item (must belong to authenticated user).
Read-tracking fields (is_read/date_read) are not editable here; use scrobble instead.
Requires authentication.

destroy:
Remove a specific collection item (must belong to authenticated user).
Requires authentication.
parameters:
- in: path
name: id
Expand Down Expand Up @@ -758,6 +770,10 @@ paths:
Update the rating of a specific collection item (must belong to authenticated user).
Read-tracking fields (is_read/date_read) are not editable here; use scrobble instead.
Requires authentication.

destroy:
Remove a specific collection item (must belong to authenticated user).
Requires authentication.
parameters:
- in: path
name: id
Expand Down Expand Up @@ -789,6 +805,81 @@ paths:
schema:
$ref: '#/components/schemas/CollectionRatingUpdate'
description: ''
delete:
operationId: api_collection_destroy
description: |-
list:
Returns authenticated user's collection items.
Requires authentication.

retrieve:
Returns details of a specific collection item (must belong to authenticated user).
Requires authentication.

partial_update:
Update the rating of a specific collection item (must belong to authenticated user).
Read-tracking fields (is_read/date_read) are not editable here; use scrobble instead.
Requires authentication.

update:
Update the rating of a specific collection item (must belong to authenticated user).
Read-tracking fields (is_read/date_read) are not editable here; use scrobble instead.
Requires authentication.

destroy:
Remove a specific collection item (must belong to authenticated user).
Requires authentication.
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this Collection Item.
required: true
tags:
- api
security:
- basicAuth: []
- cookieAuth: []
- knoxApiToken: []
responses:
'204':
description: No response body
/api/collection/add/:
post:
operationId: api_collection_add_create
description: Add an issue to the authenticated user's collection.
tags:
- api
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CollectionAddItem'
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/CollectionAddItem'
multipart/form-data:
schema:
$ref: '#/components/schemas/CollectionAddItem'
required: true
security:
- basicAuth: []
- cookieAuth: []
- knoxApiToken: []
responses:
'201':
content:
application/json:
schema:
$ref: '#/components/schemas/CollectionRead'
description: ''
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/CollectionRead'
description: ''
/api/collection/missing_issues/{series_id}/:
get:
operationId: api_collection_missing_issues_list
Expand Down Expand Up @@ -3655,6 +3746,16 @@ components:
BlankEnum:
enum:
- ''
BookFormatEnum:
enum:
- PRINT
- DIGITAL
- BOTH
type: string
description: |-
* `PRINT` - Print
* `DIGITAL` - Digital
* `BOTH` - Both
Character:
type: object
properties:
Expand Down Expand Up @@ -3790,6 +3891,54 @@ components:
- resource_url
- teams
- universes
CollectionAddItem:
type: object
description: Serializer for adding an issue to the authenticated user's collection.
properties:
issue_id:
type: integer
quantity:
type: integer
minimum: 1
default: 1
book_format:
allOf:
- $ref: '#/components/schemas/BookFormatEnum'
default: PRINT
grade:
type: string
format: decimal
pattern: ^-?\d{0,2}(?:\.\d{0,1})?$
nullable: true
grading_company:
default: ''
oneOf:
- $ref: '#/components/schemas/GradingCompanyEnum'
- $ref: '#/components/schemas/BlankEnum'
purchase_date:
type: string
format: date
nullable: true
purchase_price:
type: string
format: decimal
pattern: ^-?\d{0,5}(?:\.\d{0,2})?$
nullable: true
purchase_price_currency:
allOf:
- $ref: '#/components/schemas/CurrencyEnum'
default: USD
purchase_store:
type: string
default: ''
storage_location:
type: string
default: ''
notes:
type: string
default: ''
required:
- issue_id
CollectionIssue:
type: object
description: Serializer for issues in collection (without image and cover_hash).
Expand Down Expand Up @@ -4787,6 +4936,16 @@ components:
required:
- id
- name
GradingCompanyEnum:
enum:
- CGC
- CBCS
- PGX
type: string
description: |-
* `CGC` - CGC (Certified Guaranty Company)
* `CBCS` - CBCS (Comic Book Certification Service)
* `PGX` - PGX (Professional Grading Experts)
Imprint:
type: object
properties:
Expand Down
53 changes: 53 additions & 0 deletions src/Metron.Api/Models/Generated/CollectionAddItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// <auto-generated>
// Generated by tools/codegen/generate_models.py from "Metron Comicbook Database.yaml".
// Do not edit by hand -- re-run the script instead.
// </auto-generated>
#nullable enable

using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using Metron.Api.Serialization;

namespace Metron.Api.Models;

/// <summary>
/// Serializer for adding an issue to the authenticated user's collection.
/// </summary>
public sealed class CollectionAddItem
{
[JsonPropertyName("issue_id")]
public int? IssueId { get; set; }

[JsonPropertyName("quantity")]
public int? Quantity { get; set; }

[JsonPropertyName("book_format")]
public BookFormatEnum? BookFormat { get; set; }

[JsonPropertyName("grade")]
[JsonConverter(typeof(DecimalStringConverter))]
public decimal? Grade { get; set; }

[JsonPropertyName("grading_company")]
public GradingCompanyEnum? GradingCompany { get; set; }

[JsonPropertyName("purchase_date")]
public DateOnly? PurchaseDate { get; set; }

[JsonPropertyName("purchase_price")]
[JsonConverter(typeof(DecimalStringConverter))]
public decimal? PurchasePrice { get; set; }

[JsonPropertyName("purchase_price_currency")]
public CurrencyEnum? PurchasePriceCurrency { get; set; }

[JsonPropertyName("purchase_store")]
public string? PurchaseStore { get; set; }

[JsonPropertyName("storage_location")]
public string? StorageLocation { get; set; }

[JsonPropertyName("notes")]
public string? Notes { get; set; }
}
26 changes: 26 additions & 0 deletions src/Metron.Api/Models/Generated/Enums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@ public enum AttributionSourceEnum
OTHER,
}

/// <summary>
/// * `PRINT` - Print
/// * `DIGITAL` - Digital
/// * `BOTH` - Both
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum BookFormatEnum
{
PRINT,
DIGITAL,
BOTH,
}

/// <summary>
/// * `AF` - Afghanistan
/// * `AX` - Åland Islands
Expand Down Expand Up @@ -547,6 +560,19 @@ public enum CurrencyEnum
GBP,
}

/// <summary>
/// * `CGC` - CGC (Certified Guaranty Company)
/// * `CBCS` - CBCS (Comic Book Certification Service)
/// * `PGX` - PGX (Professional Grading Experts)
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum GradingCompanyEnum
{
CGC,
CBCS,
PGX,
}

public enum StatusEnum
{
Cancelled = 1,
Expand Down
8 changes: 8 additions & 0 deletions src/Metron.Api/Resources/CollectionClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ public Task<CollectionRatingUpdate> UpdateAsync(int id, CollectionRatingUpdate r
public Task<CollectionRatingUpdate> PartialUpdateAsync(int id, PatchedCollectionRatingUpdate rating, CancellationToken cancellationToken = default) =>
SendFormAsync<CollectionRatingUpdate>(HttpMethod.Patch, $"collection/{id}/", rating, cancellationToken);

/// <summary>Removes an item from the collection.</summary>
public Task RemoveAsync(int id, CancellationToken cancellationToken = default) =>
DeleteAsync($"collection/{id}/", cancellationToken);

/// <summary>Adds an issue to the collection.</summary>
public Task<CollectionRead> AddAsync(CollectionAddItem item, CancellationToken cancellationToken = default) =>
SendFormAsync<CollectionRead>(HttpMethod.Post, "collection/add/", item, cancellationToken);

/// <summary>Returns a single page of issues from a series that are missing from the collection.</summary>
public Task<PagedResult<MissingIssue>> GetMissingIssuesAsync(int seriesId, CollectionMissingIssuesFilter? filter = null, CancellationToken cancellationToken = default) =>
GetAsync<PagedResult<MissingIssue>>($"collection/missing_issues/{seriesId}/" + QueryStringBuilder.Build(filter), cancellationToken);
Expand Down
39 changes: 39 additions & 0 deletions tests/Metron.Api.Tests/ClientIntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,43 @@ public async Task Arc_CreateAsync_SendsMultipartFormData()
Assert.Equal(HttpMethod.Post, request.Method);
Assert.IsType<MultipartFormDataContent>(request.Content);
}

[Fact]
public async Task Collection_AddAsync_SendsMultipartFormData_AndDeserializesResponse()
{
var fake = new FakeHttpMessageHandler();
fake.Enqueue(FakeHttpMessageHandler.Json(HttpStatusCode.Created, """
{"id": 99, "quantity": 2, "book_format": "PRINT"}
"""));

using var client = CreateClient(fake);
var added = await client.Collection.AddAsync(new Models.CollectionAddItem
{
IssueId = 123,
Quantity = 2,
BookFormat = Models.BookFormatEnum.PRINT,
});

Assert.Equal(99, added.Id);
Assert.Equal(2, added.Quantity);

var request = Assert.Single(fake.Requests);
Assert.Equal(HttpMethod.Post, request.Method);
Assert.IsType<MultipartFormDataContent>(request.Content);
Assert.Equal("https://metron.cloud/api/collection/add/", request.RequestUri!.ToString());
}

[Fact]
public async Task Collection_RemoveAsync_SendsDeleteRequest()
{
var fake = new FakeHttpMessageHandler();
fake.Enqueue(new HttpResponseMessage(HttpStatusCode.NoContent));

using var client = CreateClient(fake);
await client.Collection.RemoveAsync(7);

var request = Assert.Single(fake.Requests);
Assert.Equal(HttpMethod.Delete, request.Method);
Assert.Equal("https://metron.cloud/api/collection/7/", request.RequestUri!.ToString());
}
}
Loading