Skip to content

Commit

Permalink
fix: OpenAPI lint (#445)
Browse files Browse the repository at this point in the history
* fix: openapi lint

* chore: fmtfix

* fix: update dart client

* fix api_tests, update registration schema, enable linter for CI

* update dart code

---------

Co-authored-by: Mr-Leshiy <[email protected]>
  • Loading branch information
apskhem and Mr-Leshiy authored Apr 23, 2024
1 parent 7516710 commit 044ca8e
Show file tree
Hide file tree
Showing 6 changed files with 318 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,30 @@ struct Delegation {
power: i64,
}

/// Represents a list of delegations
#[derive(Object)]
struct Delegations {
/// A list of delegations.
#[oai(validator(max_items = "100"))]
delegations: Vec<Delegation>,
}

/// Direct voter type
#[derive(Object)]
struct DirectVoter {
/// Voting key.
#[oai(validator(min_length = "66", max_length = "66", pattern = "0x[0-9a-f]{64}"))]
voting_key: String,
}

/// Voting key type
#[derive(Union)]
#[oai(discriminator_name = "type", one_of = true)]
enum VotingInfo {
/// direct voting key
Direct(String),
Direct(DirectVoter),
/// delegations
Delegated(Vec<Delegation>),
Delegated(Delegations),
}

/// User's [CIP-36](https://cips.cardano.org/cip/CIP-36/) registration info.
Expand Down Expand Up @@ -57,11 +74,13 @@ impl RegistrationInfo {
) -> Self {
let voting_info = match voting_info {
PublicVotingInfo::Direct(voting_key) => {
VotingInfo::Direct(to_hex_with_prefix(voting_key.bytes()))
VotingInfo::Direct(DirectVoter {
voting_key: to_hex_with_prefix(voting_key.bytes()),
})
},
PublicVotingInfo::Delegated(delegations) => {
VotingInfo::Delegated(
delegations
VotingInfo::Delegated(Delegations {
delegations: delegations
.into_iter()
.map(|(voting_key, power)| {
Delegation {
Expand All @@ -70,7 +89,7 @@ impl RegistrationInfo {
}
})
.collect(),
)
})
},
};
Self {
Expand All @@ -94,11 +113,14 @@ impl Example for RegistrationInfo {
.expect("Invalid hex")
.into(),
nonce: 11_623_850,
voting_info: VotingInfo::Delegated(vec![Delegation {
voting_key: "0xb16f03d67e95ddd321df4bee8658901eb183d4cb5623624ff5edd7fe54f8e857"
.to_string(),
power: 1,
}]),
voting_info: VotingInfo::Delegated(Delegations {
delegations: vec![Delegation {
voting_key:
"0xb16f03d67e95ddd321df4bee8658901eb183d4cb5623624ff5edd7fe54f8e857"
.to_string(),
power: 1,
}],
}),
}
}
}
2 changes: 2 additions & 0 deletions catalyst-gateway/tests/.spectral.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ overrides:
# warn: Should be implemented, but is blocked by a technical issue.
# info: Good to be implemented.

# Ref: https://github.com/stoplightio/spectral-owasp-ruleset/blob/2fd49c377794222352ff10dee99ed2a106c35199/src/ruleset.ts#L767
owasp:api7:2019-security-hosts-https-oas3: info
# Rate limit
# Ref: https://github.com/stoplightio/spectral-owasp-ruleset/blob/2fd49c377794222352ff10dee99ed2a106c35199/src/ruleset.ts#L436
owasp:api4:2019-rate-limit: warn
Expand Down
3 changes: 1 addition & 2 deletions catalyst-gateway/tests/Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,8 @@ fuzzer-api:

# test-lint-openapi - OpenAPI linting from an artifact
# testing whether the OpenAPI generated during build stage follows good practice.
# TODO: https://github.com/input-output-hk/catalyst-voices/issues/408
# enable this linting after this issue will be solved
lint-openapi:
test-lint-openapi:
FROM github.com/input-output-hk/catalyst-ci/earthly/spectral:v2.4.0+spectral-base
# Copy the doc artifact.
COPY ../+build/doc ./doc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,18 @@

def check_delegations(provided, expected):
if type(expected) is list:
provided_delegations = provided["delegations"]
for i in range(0, len(expected)):
expected_voting_key = expected[i][0]
expected_power = expected[i][1]
provided_voting_key = provided[i]["voting_key"]
provided_power = provided[i]["power"]
provided_voting_key = provided_delegations[i]["voting_key"]
provided_power = provided_delegations[i]["power"]
assert (
expected_voting_key == provided_voting_key
and expected_power == provided_power
)
else:
assert provided == expected
assert provided["voting_key"] == expected


def test_voter_registration_endpoint():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,95 @@ extension $DelegationExtension on Delegation {
}
}

@JsonSerializable(explicitToJson: true)
class Delegations {
const Delegations({
required this.delegations,
});

factory Delegations.fromJson(Map<String, dynamic> json) =>
_$DelegationsFromJson(json);

static const toJsonFactory = _$DelegationsToJson;
Map<String, dynamic> toJson() => _$DelegationsToJson(this);

@JsonKey(name: 'delegations', defaultValue: <Delegation>[])
final List<Delegation> delegations;
static const fromJsonFactory = _$DelegationsFromJson;

@override
bool operator ==(Object other) {
return identical(this, other) ||
(other is Delegations &&
(identical(other.delegations, delegations) ||
const DeepCollectionEquality()
.equals(other.delegations, delegations)));
}

@override
String toString() => jsonEncode(this);

@override
int get hashCode =>
const DeepCollectionEquality().hash(delegations) ^ runtimeType.hashCode;
}

extension $DelegationsExtension on Delegations {
Delegations copyWith({List<Delegation>? delegations}) {
return Delegations(delegations: delegations ?? this.delegations);
}

Delegations copyWithWrapped({Wrapped<List<Delegation>>? delegations}) {
return Delegations(
delegations:
(delegations != null ? delegations.value : this.delegations));
}
}

@JsonSerializable(explicitToJson: true)
class DirectVoter {
const DirectVoter({
required this.votingKey,
});

factory DirectVoter.fromJson(Map<String, dynamic> json) =>
_$DirectVoterFromJson(json);

static const toJsonFactory = _$DirectVoterToJson;
Map<String, dynamic> toJson() => _$DirectVoterToJson(this);

@JsonKey(name: 'voting_key')
final String votingKey;
static const fromJsonFactory = _$DirectVoterFromJson;

@override
bool operator ==(Object other) {
return identical(this, other) ||
(other is DirectVoter &&
(identical(other.votingKey, votingKey) ||
const DeepCollectionEquality()
.equals(other.votingKey, votingKey)));
}

@override
String toString() => jsonEncode(this);

@override
int get hashCode =>
const DeepCollectionEquality().hash(votingKey) ^ runtimeType.hashCode;
}

extension $DirectVoterExtension on DirectVoter {
DirectVoter copyWith({String? votingKey}) {
return DirectVoter(votingKey: votingKey ?? this.votingKey);
}

DirectVoter copyWithWrapped({Wrapped<String>? votingKey}) {
return DirectVoter(
votingKey: (votingKey != null ? votingKey.value : this.votingKey));
}
}

@JsonSerializable(explicitToJson: true)
class FragmentStatus {
const FragmentStatus();
Expand Down Expand Up @@ -1207,7 +1296,135 @@ extension $VoterRegistrationExtension on VoterRegistration {
}
}

typedef VotingInfo = Map<String, dynamic>;
@JsonSerializable(explicitToJson: true)
class VotingInfo {
const VotingInfo();

factory VotingInfo.fromJson(Map<String, dynamic> json) =>
_$VotingInfoFromJson(json);

static const toJsonFactory = _$VotingInfoToJson;
Map<String, dynamic> toJson() => _$VotingInfoToJson(this);

static const fromJsonFactory = _$VotingInfoFromJson;

@override
String toString() => jsonEncode(this);

@override
int get hashCode => runtimeType.hashCode;
}

@JsonSerializable(explicitToJson: true)
class VotingInfoDelegations {
const VotingInfoDelegations({
required this.type,
required this.delegations,
});

factory VotingInfoDelegations.fromJson(Map<String, dynamic> json) =>
_$VotingInfoDelegationsFromJson(json);

static const toJsonFactory = _$VotingInfoDelegationsToJson;
Map<String, dynamic> toJson() => _$VotingInfoDelegationsToJson(this);

@JsonKey(name: 'type')
final String type;
@JsonKey(name: 'delegations', defaultValue: <Delegation>[])
final List<Delegation> delegations;
static const fromJsonFactory = _$VotingInfoDelegationsFromJson;

@override
bool operator ==(Object other) {
return identical(this, other) ||
(other is VotingInfoDelegations &&
(identical(other.type, type) ||
const DeepCollectionEquality().equals(other.type, type)) &&
(identical(other.delegations, delegations) ||
const DeepCollectionEquality()
.equals(other.delegations, delegations)));
}

@override
String toString() => jsonEncode(this);

@override
int get hashCode =>
const DeepCollectionEquality().hash(type) ^
const DeepCollectionEquality().hash(delegations) ^
runtimeType.hashCode;
}

extension $VotingInfoDelegationsExtension on VotingInfoDelegations {
VotingInfoDelegations copyWith(
{String? type, List<Delegation>? delegations}) {
return VotingInfoDelegations(
type: type ?? this.type, delegations: delegations ?? this.delegations);
}

VotingInfoDelegations copyWithWrapped(
{Wrapped<String>? type, Wrapped<List<Delegation>>? delegations}) {
return VotingInfoDelegations(
type: (type != null ? type.value : this.type),
delegations:
(delegations != null ? delegations.value : this.delegations));
}
}

@JsonSerializable(explicitToJson: true)
class VotingInfoDirectVoter {
const VotingInfoDirectVoter({
required this.type,
required this.votingKey,
});

factory VotingInfoDirectVoter.fromJson(Map<String, dynamic> json) =>
_$VotingInfoDirectVoterFromJson(json);

static const toJsonFactory = _$VotingInfoDirectVoterToJson;
Map<String, dynamic> toJson() => _$VotingInfoDirectVoterToJson(this);

@JsonKey(name: 'type')
final String type;
@JsonKey(name: 'voting_key')
final String votingKey;
static const fromJsonFactory = _$VotingInfoDirectVoterFromJson;

@override
bool operator ==(Object other) {
return identical(this, other) ||
(other is VotingInfoDirectVoter &&
(identical(other.type, type) ||
const DeepCollectionEquality().equals(other.type, type)) &&
(identical(other.votingKey, votingKey) ||
const DeepCollectionEquality()
.equals(other.votingKey, votingKey)));
}

@override
String toString() => jsonEncode(this);

@override
int get hashCode =>
const DeepCollectionEquality().hash(type) ^
const DeepCollectionEquality().hash(votingKey) ^
runtimeType.hashCode;
}

extension $VotingInfoDirectVoterExtension on VotingInfoDirectVoter {
VotingInfoDirectVoter copyWith({String? type, String? votingKey}) {
return VotingInfoDirectVoter(
type: type ?? this.type, votingKey: votingKey ?? this.votingKey);
}

VotingInfoDirectVoter copyWithWrapped(
{Wrapped<String>? type, Wrapped<String>? votingKey}) {
return VotingInfoDirectVoter(
type: (type != null ? type.value : this.type),
votingKey: (votingKey != null ? votingKey.value : this.votingKey));
}
}

String? animalsNullableToJson(enums.Animals? animals) {
return animals?.value;
}
Expand Down
Loading

0 comments on commit 044ca8e

Please sign in to comment.