From 19141954e995fc6ab6c172d87e9c7f27206faf0d Mon Sep 17 00:00:00 2001 From: Zergling_man Date: Sun, 3 Nov 2024 15:35:53 +1100 Subject: [PATCH] I guess I should update this --- README => offline/README | 0 swat-codegen/PKGBUILD | 21 + swat-codegen/codegen.sh | 105 + swat-codegen/documentation.yaml | 1251 +++++++++++ swat-codegen/openapi.yaml | 1931 +++++++++++++++++ .../swat-codegen-1.0.2-1-any.pkg.tar.zst | Bin 0 -> 23040 bytes swat-codegen/swat_armour | 4 + swat-codegen/swat_class | 12 + swat-codegen/swat_gun | 8 + swat-codegen/swat_spec | 9 + swat-codegen/swat_talent | 7 + swat-codegen/swat_trait | 16 + 12 files changed, 3364 insertions(+) rename README => offline/README (100%) create mode 100644 swat-codegen/PKGBUILD create mode 100755 swat-codegen/codegen.sh create mode 100644 swat-codegen/documentation.yaml create mode 100644 swat-codegen/openapi.yaml create mode 100644 swat-codegen/swat-codegen-1.0.2-1-any.pkg.tar.zst create mode 100644 swat-codegen/swat_armour create mode 100644 swat-codegen/swat_class create mode 100644 swat-codegen/swat_gun create mode 100644 swat-codegen/swat_spec create mode 100644 swat-codegen/swat_talent create mode 100644 swat-codegen/swat_trait diff --git a/README b/offline/README similarity index 100% rename from README rename to offline/README diff --git a/swat-codegen/PKGBUILD b/swat-codegen/PKGBUILD new file mode 100644 index 0000000..6aebf4e --- /dev/null +++ b/swat-codegen/PKGBUILD @@ -0,0 +1,21 @@ +# Maintainer: Zergling_man, from fedora.email + +pkgname=swat-codegen +pkgver=1.0.2 +pkgrel=1 +pkgdesc="A simple CLI interface to RCPDv3, the rank code management service for the game SWAT: Aftermath" +arch=('any') +url=http://rakka.au/contact +license=('WTFPL+nigger') +depends=('jq' 'curl' 'coreutils' 'grep') +source=() +sha256sums=('SKIP') #Don't know how to use this on a repo. + +package() { + cd ${pkgdir} + install -d usr/bin opt/swat-codegen + cd ${srcdir}/${pkgname} + chmod a+x codegen.sh + cp swat_* codegen.sh ${pkgdir}/opt/swat-codegen + ln -s /opt/swat-codegen/codegen.sh /${pkgdir}/usr/bin/rcpd +} \ No newline at end of file diff --git a/swat-codegen/codegen.sh b/swat-codegen/codegen.sh new file mode 100755 index 0000000..b474f5f --- /dev/null +++ b/swat-codegen/codegen.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +loc=$(dirname $(readlink -f "$0")) + +# TOKEN MANAGEMENT +function migrate +{ + curl "https://swataftermath.com:8443/account/$1/activate-migrated" --json '{"currentPassword":"'"$3"'","emailAddress":"'"$2"'","newPassword":"'"$3"'"}' + curl "https://swataftermath.com:8443/account/$1/verify-email" --json '{"verificationCode":"'"$(cat)"'"}' + login "$1" "$3" +} + +function login +{ + [ -n "$2" ] || { echo "Please provide a username and password, in that order, when calling this"; exit; } + curl https://swataftermath.com:8443/login --json '{"username":"'"$1"'","password":"'"$2"'"}' > ~/.config/rcpd.cfg +} + +function get_token +{ + cat ~/.config/rcpd.cfg 2>/dev/null || { echo "Please login first" >&2; exit; } +} + +# CORE API CALLS +function get +{ + TOKE=`get_token` + curl -H "Authorization:Bearer $TOKE" https://swataftermath.com:9443/account/$1 +} + +function post +{ + TOKE=`get_token` + curl -H "Authorization:Bearer $TOKE" https://swataftermath.com:9443/account/$1 --json "$2" +} + +function delete_code +{ + TOKE=`get_token` + curl -H "Authorization:Bearer $TOKE" https://swataftermath.com:9443/account/rank-code/$1 -X DELETE +} + +# UTILS +function lookup +{ + w= + matches=`grep -ic "${*:2}" $loc/swat_$1` + if [ "$matches" -ne 1 ]; then + echo "$1 '${*:2}' is ambiguous (got $matches matches), trying whole-word match" >&2 + # Attempt whole-word match and see if we get exactly one result (and then remember it has happened!!!) + w=w + word_matches=`grep -ic$w "${*:2}" $loc/swat_$1` + if [ "$word_matches" -ne 1 ]; then echo "still ambiguous (got $word_matches matches)" >&2; return 1; fi + fi + read $1 garbage <<< "`grep -i$w "${*:2}" $loc/swat_$1`" +} + +# USER-FACING COMMANDS +function builds +{ + if [ -n "$1" ]; then filter='.[] | select(.buildName=="'"$*"'")'; fi + get saved-builds | jq $filter +} + +function save +{ + if [ -n "$2" ]; then name=',"buildName":"'"${*:2}"'"'; fi + post rank-code '{"rankCode":"'$1'"'$name'}' | jq + if [ -z "$2" ]; then delete_code $1; fi # Don't bother storing any build that doesn't have a name. Assume it's just logging the results of a game. +} + +function generate +{ + # mfw I actually have to do work + IFS=/ read -a hero <<< "$*" + length=${#hero[*]} + if [ $length -eq 6 ]; then IFS=/ read class gun armour trait spec talent <<< "$*" + elif [ $length -eq 5 ]; then IFS=/ read class armour trait spec talent <<< "$*" + elif [ $length -eq 4 ]; then IFS=/ read class trait spec talent <<< "$*"; fi # Probably a borg or a wm. + if [ -z "$gun" ]; then + if [ "${class:2}" = "wm" ]; then gun=${class%wm}; class=wm + elif [ "${class:1}" = "mav" ] || [ "${class:2}" = "mav" ]; then gun=${class%mav}; class=mav; fi + fi + res=0 + lookup class "$class" + res=$((res+$?)) + if [ -z "$gun" ]; then gun=$class; fi # Do this after qualifying class so I don't have to nest the full class table in the gun table. + lookup gun "$gun" + res=$((res+$?)) + if [ -z "$armour" ]; then armour=$class; fi + lookup armour "$armour" + res=$((res+$?)) + lookup trait "$trait" + res=$((res+$?)) + lookup spec "$spec" + res=$((res+$?)) + lookup talent "$talent" + res=$((res+$?)) + if [ $res -gt 0 ]; then echo "Please correct above errors and try again"; exit; fi + echo $class $gun $armour $trait $spec $talent + post generate '{"swatClass":"'$class'","gun":"'$gun'","armor":"'$armour'","trait":"'$trait'","specialization":"'$spec'","talent":"'$talent'"}' | jq '.rankCode//.' +} + +# DO SHIT +$@ \ No newline at end of file diff --git a/swat-codegen/documentation.yaml b/swat-codegen/documentation.yaml new file mode 100644 index 0000000..46a73e6 --- /dev/null +++ b/swat-codegen/documentation.yaml @@ -0,0 +1,1251 @@ +{ + "openapi" : "3.1.0", + "info" : { + "title" : "SWAT Account Service API", + "description" : "API for the SWAT Account Service that allows creation, management, and authentication of SWAT accounts. A SWAT account can be used to access SWAT services, such as RCPD 3.0 (rcpd-service) and map marker. Accounts in RCPD 2.0 have been migrated to SWAT accounts with the same username and password.", + "version" : "0.14.0" + }, + "externalDocs" : { + "url" : "/" + }, + "servers" : [ { + "url" : "https://swataftermath.com:8443/" + } ], + "tags" : [ { + "name" : "Account Resource", + "description" : "Resource for managing accounts, such as creating new accounts, and modifying existing accounts." + }, { + "name" : "Authentication Resource", + "description" : "Resource for authenticating and getting a JWT." + }, { + "name" : "Email Verification Resource", + "description" : "Resource for verifying email addresses on accounts." + }, { + "name" : "Open API Resource", + "description" : "Resource for retrieving Open API documentation." + }, { + "name" : "Password Resource", + "description" : "Resource for resetting forgotten passwords." + } ], + "paths" : { + "/openapi/documentation.yaml" : { + "get" : { + "tags" : [ "Open API Resource" ], + "description" : "Get the raw Open API documentation.", + "parameters" : [ ], + "responses" : { + "200" : { + "description" : "The raw Open API documentation.", + "headers" : { }, + "content" : { + "text/yaml" : { + "schema" : { + "type" : "string", + "title" : "String" + } + } + } + } + }, + "deprecated" : false + } + }, + "/account" : { + "post" : { + "tags" : [ "Account Resource" ], + "description" : "Create a new SWAT account. Email address will need to be verified after the account is created, before you can log in.", + "parameters" : [ ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/AccountCreationRequest" + } + } + }, + "required" : true + }, + "responses" : { + "500" : { + "description" : "An error occurred in the system.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "General Exception Response example" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "NullPointerException when deserializing value.", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "201" : { + "description" : "New SWAT account successfully created.", + "headers" : { } + }, + "409" : { + "description" : "User name or email address is already registered.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "Duplicate Username or Email Exception Example" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "Email address [ testemail@test.com ] is already registered in the system.", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "422" : { + "description" : "The request was invalid.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ValidationErrorResponse" + }, + "examples" : { + "Invalid Request Exception Response example" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "request has validation errors", + "serviceName" : "swat-account-service", + "errors" : { + "emailAddress" : [ "must not be blank" ] + } + } + } + } + } + } + } + }, + "deprecated" : false + } + }, + "/account/{username}" : { + "put" : { + "tags" : [ "Account Resource" ], + "description" : "Update your SWAT account. This resource supports partial PUT operations, where all null values are ignored.", + "parameters" : [ { + "name" : "username", + "in" : "path", + "description" : "The username or email address of your account to update.", + "required" : true, + "deprecated" : false, + "explode" : false, + "schema" : { + "type" : "string", + "title" : "String" + }, + "example" : "Skater901" + } ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/AccountUpdateRequest" + } + } + }, + "required" : true + }, + "responses" : { + "500" : { + "description" : "An error occurred in the system.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "General Exception Response example" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "NullPointerException when deserializing value.", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "204" : { + "description" : "The account was updated.", + "headers" : { } + }, + "401" : { + "description" : "Authorization token not provided or is invalid.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "Example Unauthorized Response" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "missing or invalid bearer token", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "403" : { + "description" : "You are attempting to update an account that you do not have access to.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "Example Forbidden Response" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "HTTP 403 Forbidden", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "422" : { + "description" : "The request was invalid.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ValidationErrorResponse" + }, + "examples" : { + "Invalid Request Exception Response example" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "request has validation errors", + "serviceName" : "swat-account-service", + "errors" : { + "newPassword" : [ "must not be blank" ] + } + } + } + } + } + } + } + }, + "deprecated" : false, + "security" : [ { + "SWAT-Token" : [ ] + } ] + } + }, + "/account/{username}/activate-migrated" : { + "post" : { + "tags" : [ "Account Resource" ], + "description" : "Activate a migrated account, by setting an email address and changing the password. This is required for all migrated accounts before they can be used to get tokens.", + "parameters" : [ { + "name" : "username", + "in" : "path", + "description" : "The username of the account to activate.", + "required" : true, + "deprecated" : false, + "explode" : false, + "schema" : { + "type" : "string", + "title" : "String" + }, + "example" : "Skater901" + } ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ActivateMigratedAccountRequest" + } + } + }, + "required" : true + }, + "responses" : { + "500" : { + "description" : "An error occurred in the system.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "General Exception Response example" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "NullPointerException when deserializing value.", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "204" : { + "description" : "Migrated account activated successfully. An email will have been sent to the provided email address with a verification link to verify the email address.", + "headers" : { } + }, + "400" : { + "description" : "Account has already been activated.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "Account Already Activated Exception Response" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "Account has already been activated.", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "401" : { + "description" : "The account does not exist or the password is incorrect.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "Example Unauthorized Response" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "Invalid username or password.", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "409" : { + "description" : "The requested email address is already registered to another SWAT account.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "Email Address Already Registered Exception Response" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "Email address [ myemailaddress@gmail.com ] is already registered.", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "422" : { + "description" : "The request was invalid.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ValidationErrorResponse" + }, + "examples" : { + "Invalid Request Exception Response example" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "request has validation errors", + "serviceName" : "swat-account-service", + "errors" : { + "emailAddress" : [ "must not be blank" ], + "currentPassword" : [ "must not be blank" ], + "newPassword" : [ "must not be blank" ] + } + } + } + } + } + } + } + }, + "deprecated" : false + } + }, + "/login" : { + "post" : { + "tags" : [ "Authentication Resource" ], + "description" : "Get a JWT from a username/password or email address/password combination.", + "parameters" : [ ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/LoginRequest" + } + } + }, + "required" : true + }, + "responses" : { + "200" : { + "description" : "Successfully logged in.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "type" : "string", + "title" : "String" + }, + "examples" : { + "Example JWT Response" : { + "value" : "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkYjA3Nzc2ZS05ZTg2LTRhNGUtOTRkMC03ZDE3NzY2ODZkOWEiLCJqdGkiOiI4NWY4Njg5Yy0wODg5LTRlODUtOWM5Zi05MzY0MDllN2ZlMDciLCJhdWQiOiIiLCJpc3MiOiIiLCJleHAiOjE2OTA1NTczMzZ9.js0KMh7tyqGV4j7zQUs1du4RX16MQczXDCxgGmE_z_QX-551-O53dqX5MgnTufMOFmJ6pevzOwJqnAUcdM8Y2l2qrvUGuWO57vejwdo-tqZFE96AYZHH0cMuxZMNaA3-gtcd11dOvv01RAJWQkPEcj7aEgA2D0-paayhWClSpvMRUC2IkhTKbDvAO_5yAaseKKrSemJjboWrbfUHYvpz9GtvLhXUhWzFLzemu6ZQu2oSiGtuF7VcZfvJYwYdVL_LlxkPAEdiw_-8DYDWhBW4MuXOW8wlpLqtx4U2Ma2-Mn33e1gQll9xsazn85YnWHe_FAU1wQXiVhBb4PaYnr36yg" + } + } + } + } + }, + "401" : { + "description" : "Account doesn't exist or password is wrong.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "Example Unauthorized Response" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "Invalid username or password.", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "422" : { + "description" : "The request was invalid.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ValidationErrorResponse" + }, + "examples" : { + "Invalid Request Exception Response example" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "request has validation errors", + "serviceName" : "swat-account-service", + "errors" : { + "username" : [ "must not be blank" ] + } + } + } + } + } + } + }, + "490" : { + "description" : "The username and password were correct, but the email address for this account has not yet been verified.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "Unverified Email Address Exception Response" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "Email address has not been verified", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "491" : { + "description" : "This is a migrated account from old RCPD. Please activate the account using the /account/{username}/activate-migrated endpoint.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "Not Activated Migrated Account Exception Response" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "Migrated RCPD account, please activate it.", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "492" : { + "description" : "Your password is correct, but must be changed.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "Password Change Required Exception Response" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "Your password must be changed.", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "500" : { + "description" : "An error occurred in the system.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "General Exception Response example" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "NullPointerException when deserializing value.", + "serviceName" : "swat-account-service" + } + } + } + } + } + } + }, + "deprecated" : false + } + }, + "/account/{username}/request-verification-code" : { + "post" : { + "tags" : [ "Email Verification Resource" ], + "description" : "Re-send the verification code for the specified account, creating a new code if the old code has expired.", + "parameters" : [ { + "name" : "username", + "in" : "path", + "description" : "The username or email address of the account you wish to perform the action on.", + "required" : true, + "deprecated" : false, + "explode" : false, + "schema" : { + "type" : "string", + "title" : "String" + }, + "example" : "test@test.com" + } ], + "responses" : { + "500" : { + "description" : "An error occurred in the system.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "General Exception Response example" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "NullPointerException when deserializing value.", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "204" : { + "description" : "An email has been sent with a verification code for the specified email address. Please note, if the email address is not registered, this response will still be returned, in order to prevent malicious actors from discovering registered email addresses.", + "headers" : { } + } + }, + "deprecated" : false + } + }, + "/account/{username}/verify-email" : { + "post" : { + "tags" : [ "Email Verification Resource" ], + "description" : "Verify that your email address is a real email address and you have access to it.", + "parameters" : [ { + "name" : "username", + "in" : "path", + "description" : "The username or email address of the account you wish to perform the action on.", + "required" : true, + "deprecated" : false, + "explode" : false, + "schema" : { + "type" : "string", + "title" : "String" + }, + "example" : "test@test.com" + } ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/VerifyEmailRequest" + } + } + }, + "required" : true + }, + "responses" : { + "500" : { + "description" : "An error occurred in the system.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "General Exception Response example" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "NullPointerException when deserializing value.", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "204" : { + "description" : "Your email address has been verified and you are now able to login and get a token.", + "headers" : { } + }, + "403" : { + "description" : "The provided verification code is not valid for the specified account.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "Example Forbidden Response" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "HTTP 403 Forbidden", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "404" : { + "description" : "The provided verification code does not exist.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "Not Found Exception Response Example" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "email verification code [ {verificationCode} ] not found", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "422" : { + "description" : "The request was invalid.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ValidationErrorResponse" + }, + "examples" : { + "Invalid Request Exception Response example" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "request has validation errors", + "serviceName" : "swat-account-service", + "errors" : { + "verificationCode" : [ "must not be blank" ] + } + } + } + } + } + } + } + }, + "deprecated" : false + } + }, + "/account/{username}/request-password-reset-code" : { + "post" : { + "tags" : [ "Password Resource" ], + "description" : "Request a one-time use code to be emailed to the account's email address that can be used to change the account's password.", + "parameters" : [ { + "name" : "username", + "in" : "path", + "description" : "The username or email address of the account you wish to request a password reset code for.", + "required" : true, + "deprecated" : false, + "explode" : false, + "schema" : { + "type" : "string", + "title" : "String" + }, + "example" : "test@test.com" + } ], + "responses" : { + "500" : { + "description" : "An error occurred in the system.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "General Exception Response example" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "NullPointerException when deserializing value.", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "204" : { + "description" : "An email has been sent with a password reset code for the account specified by the email address. Please note, if the account is not registered, this response will still be returned, in order to prevent malicious actors from discovering registered email addresses.", + "headers" : { } + } + }, + "deprecated" : false + } + }, + "/account/{username}/reset-password" : { + "post" : { + "tags" : [ "Password Resource" ], + "description" : "Use the one-time use code to change the account's password.", + "parameters" : [ { + "name" : "username", + "in" : "path", + "description" : "The username or email address of the account to reset the password on.", + "required" : true, + "deprecated" : false, + "explode" : false, + "schema" : { + "type" : "string", + "title" : "String" + }, + "example" : "test@test.com" + } ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/PasswordResetRequest" + } + } + }, + "required" : true + }, + "responses" : { + "500" : { + "description" : "An error occurred in the system.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "General Exception Response example" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "NullPointerException when deserializing value.", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "204" : { + "description" : "The password has been successfully changed.", + "headers" : { } + }, + "403" : { + "description" : "The provided code is not valid for the specified account.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "Example Forbidden Response" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "HTTP 403 Forbidden", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "404" : { + "description" : "The provided one-time code is not valid.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "Password Reset Code not found response example" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "Password reset code [ 54F5C0BE482828847C650669CE89D57D ] does not exist", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "422" : { + "description" : "The request was invalid.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ValidationErrorResponse" + }, + "examples" : { + "Invalid Request Exception Response example" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "request has validation errors", + "serviceName" : "swat-account-service", + "errors" : { + "code" : [ "must not be blank" ] + } + } + } + } + } + } + } + }, + "deprecated" : false + } + }, + "/account/{username}/change-password" : { + "post" : { + "tags" : [ "Password Resource" ], + "description" : "Change password of the specified account using the existing password to authenticate. Use this endpoint if you are unable to get a token because you are forced to update your password.", + "parameters" : [ { + "name" : "username", + "in" : "path", + "description" : "The username or email address of the account to change the password on.", + "required" : true, + "deprecated" : false, + "explode" : false, + "schema" : { + "type" : "string", + "title" : "String" + }, + "example" : "test@test.com" + } ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ChangePasswordRequest" + } + } + }, + "required" : true + }, + "responses" : { + "500" : { + "description" : "An error occurred in the system.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "General Exception Response example" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "NullPointerException when deserializing value.", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "204" : { + "description" : "The password has been successfully changed.", + "headers" : { } + }, + "401" : { + "description" : "The account and password combination is invalid.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + }, + "examples" : { + "Example Unauthorized Response" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "missing or invalid bearer token", + "serviceName" : "swat-account-service" + } + } + } + } + } + }, + "422" : { + "description" : "The request was invalid.", + "headers" : { }, + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ValidationErrorResponse" + }, + "examples" : { + "Invalid Request Exception Response example" : { + "value" : { + "reference" : "kcog4koca5xhiegavarp", + "message" : "request has validation errors", + "serviceName" : "swat-account-service", + "errors" : { + "newPassword" : [ "must not be blank" ] + } + } + } + } + } + } + } + }, + "deprecated" : false + } + } + }, + "components" : { + "schemas" : { + "AccountCreationRequest" : { + "type" : "object", + "description" : "User name, email address, and password for this account.", + "properties" : { + "emailAddress" : { + "type" : "string", + "description" : "The email address to register this account under. Must be in the standard email format, characters followed by @ followed by characters followed by . followed by characters.", + "example" : "testemail@test.com", + "maxLength" : 100, + "minLength" : 0, + "title" : "String" + }, + "password" : { + "type" : "string", + "description" : "The password for this SWAT account.", + "example" : "password123", + "maxLength" : 100, + "minLength" : 8, + "title" : "String" + }, + "username" : { + "type" : "string", + "description" : "The username for this SWAT account.", + "example" : "Test User", + "maxLength" : 100, + "minLength" : 0, + "title" : "String" + } + }, + "required" : [ "emailAddress", "password", "username" ], + "title" : "AccountCreationRequest" + }, + "ErrorResponse" : { + "type" : "object", + "properties" : { + "message" : { + "type" : "string", + "description" : "A message describing the error that occurred.", + "example" : "An error occurred.", + "maxLength" : 2147483647, + "minLength" : 0, + "title" : "String" + }, + "reference" : { + "type" : "string", + "description" : "A unique reference for your error. Provide this to the admins to help track down your issue.", + "example" : "kcog4koca5xhiegavarp", + "maxLength" : 20, + "minLength" : 20, + "title" : "String" + }, + "serviceName" : { + "type" : "string", + "description" : "The name of this service. Will always be swat-account-service.", + "example" : "swat-account-service", + "maxLength" : 20, + "minLength" : 20, + "title" : "String" + } + }, + "required" : [ "message", "reference", "serviceName" ], + "title" : "ErrorResponse" + }, + "ValidationErrorResponse" : { + "type" : "object", + "properties" : { + "errors" : { + "type" : "object", + "additionalProperties" : { + "type" : "array", + "items" : { + "type" : "string", + "title" : "String" + }, + "title" : "List" + }, + "description" : "Key value pairs, where each key is the name of a property of the request object, and each value is a list of strings, each string indicating a validation error for that property.", + "example" : "{ \"username\": [ \"must not be blank\" ] }", + "maxLength" : 2147483647, + "minLength" : 0, + "title" : "Map>" + }, + "message" : { + "type" : "string", + "description" : "A message describing the error that occurred.", + "example" : "An error occurred.", + "maxLength" : 2147483647, + "minLength" : 0, + "title" : "String" + }, + "reference" : { + "type" : "string", + "description" : "A unique reference for your error. Provide this to the admins to help track down your issue.", + "example" : "kcog4koca5xhiegavarp", + "maxLength" : 20, + "minLength" : 20, + "title" : "String" + }, + "serviceName" : { + "type" : "string", + "description" : "The name of this service. Will always be swat-account-service.", + "example" : "swat-account-service", + "maxLength" : 20, + "minLength" : 20, + "title" : "String" + } + }, + "required" : [ "errors", "message", "reference", "serviceName" ], + "title" : "ValidationErrorResponse" + }, + "AccountUpdateRequest" : { + "type" : "object", + "description" : "The properties of your SWAT account you wish to update.", + "properties" : { + "password" : { + "type" : [ "null", "string" ], + "description" : "The new password for your account.", + "example" : "mynewpassword123", + "maxLength" : 100, + "minLength" : 8, + "title" : "String" + } + }, + "title" : "AccountUpdateRequest" + }, + "ActivateMigratedAccountRequest" : { + "type" : "object", + "description" : "The email address for the account, along with the current password to authenticate, and the new password.", + "properties" : { + "currentPassword" : { + "type" : "string", + "description" : "The current password for your migrated SWAT account you wish to activate.", + "example" : "mypassword123", + "maxLength" : 2147483647, + "minLength" : 0, + "title" : "String" + }, + "emailAddress" : { + "type" : "string", + "description" : "The email address to set for this account. Must be in the standard email format, characters followed by @ followed by characters followed by . followed by characters.", + "example" : "myemailaddress@gmail.com", + "maxLength" : 100, + "minLength" : 0, + "title" : "String" + }, + "newPassword" : { + "type" : "string", + "description" : "The new password for your SWAT account.", + "example" : "mynewpassword", + "maxLength" : 100, + "minLength" : 8, + "title" : "String" + } + }, + "required" : [ "currentPassword", "emailAddress", "newPassword" ], + "title" : "ActivateMigratedAccountRequest" + }, + "LoginRequest" : { + "type" : "object", + "description" : "The username (or email address) and password to login with.", + "properties" : { + "password" : { + "type" : "string", + "description" : "The password for the SWAT account you wish to log in to.", + "example" : "password123", + "maxLength" : 100, + "minLength" : 0, + "title" : "String" + }, + "username" : { + "type" : "string", + "description" : "The username or email address of the SWAT account you wish to log in to.", + "example" : "Test User", + "maxLength" : 100, + "minLength" : 0, + "title" : "String" + } + }, + "required" : [ "password", "username" ], + "title" : "LoginRequest" + }, + "VerifyEmailRequest" : { + "type" : "object", + "description" : "The verification code sent to your email address.", + "properties" : { + "verificationCode" : { + "type" : "string", + "description" : "The verification code sent to your email address.", + "maxLength" : 2147483647, + "minLength" : 0, + "title" : "String" + } + }, + "required" : [ "verificationCode" ], + "title" : "VerifyEmailRequest" + }, + "PasswordResetRequest" : { + "type" : "object", + "description" : "The one-time use code and new password.", + "properties" : { + "code" : { + "type" : "string", + "description" : "The one-time use code sent to you in an email.", + "example" : "54F5C0BE482828847C650669CE89D57D", + "maxLength" : 32, + "minLength" : 32, + "title" : "String" + }, + "password" : { + "type" : "string", + "description" : "The new password to set for the account.", + "example" : "password123", + "maxLength" : 100, + "minLength" : 8, + "title" : "String" + } + }, + "required" : [ "code", "password" ], + "title" : "PasswordResetRequest" + }, + "ChangePasswordRequest" : { + "type" : "object", + "description" : "The current and new passwords.", + "properties" : { + "newPassword" : { + "type" : "string", + "description" : "The new password.", + "example" : "mynewpassword", + "maxLength" : 100, + "minLength" : 8, + "title" : "String" + }, + "password" : { + "type" : "string", + "description" : "The current password for the account.", + "example" : "mypassword", + "maxLength" : 100, + "minLength" : 0, + "title" : "String" + } + }, + "required" : [ "newPassword", "password" ], + "title" : "ChangePasswordRequest" + } + }, + "examples" : { }, + "securitySchemes" : { + "SWAT-Token" : { + "type" : "http", + "description" : "A JWT provided by this service. Must be provided as an Authorization header using the format \"Bearer {JWT}\"", + "in" : "header", + "scheme" : "bearer", + "bearerFormat" : "JWT" + } + } + } +} \ No newline at end of file diff --git a/swat-codegen/openapi.yaml b/swat-codegen/openapi.yaml new file mode 100644 index 0000000..ebff393 --- /dev/null +++ b/swat-codegen/openapi.yaml @@ -0,0 +1,1931 @@ +openapi: 3.0.1 +info: + title: SWAT Aftermath - RCPD Service + description: "Rank code manager service for storing rank codes, generating rank\ + \ codes, earning titles, etc. The back end for RPCD 3.0" + version: 0.24.3 +servers: +- url: https://swataftermath.com:9443/ +tags: +- name: Account Resource + description: Resource for management of RCPD accounts +- name: Accounts Resource + description: Resource for retrieving multiple accounts. +- name: Rank Code Resource + description: Resource for saving and retrieving rank codes and builds. +- name: Unlocks Resource + description: Resource for retrieving the maximum rank unlocked for each SWAT build + element. +- name: Open API Resource + description: Resource that provides the Open API documentation for this service. +paths: + /account/{username}: + get: + tags: + - Account Resource + summary: Get RCPD account. + description: "Get the specified RCPD account if it exists. Auth token is optional\ + \ for this resource. If provided, and you are the owner of the account, you\ + \ will see all information for the account." + operationId: getAccount + parameters: + - name: username + in: path + description: The username of the RCPD account you wish to retrieve. The username + is case sensitive. + required: true + schema: + type: string + example: teller55 + responses: + "500": + description: Something went wrong when processing the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "502": + description: A dependent service or database had an error. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "200": + description: The requested RCPD account. + content: + application/json: + schema: + $ref: "#/components/schemas/AccountResponse" + "401": + description: "Authorization header is not present, or token is invalid or\ + \ expired." + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "503": + description: The security infrastructure cannot currently handle the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "404": + description: The requested resource could not be found. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + security: + - SWAT-Token: [] + put: + tags: + - Account Resource + summary: Update properties of the specified account + description: "Update certain fields of an RCPD account. This is a partial PUT\ + \ operation, where only the fields you want to update must be provided." + operationId: updateAccount + parameters: + - name: username + in: path + description: The username of the RCPD account you wish to update. The username + is case sensitive. + required: true + schema: + type: string + example: teller55 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/AccountUpdateRequest" + responses: + "500": + description: Something went wrong when processing the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "502": + description: A dependent service or database had an error. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "401": + description: "Authorization header is not present, or token is invalid or\ + \ expired." + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "503": + description: The security infrastructure cannot currently handle the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "403": + description: You are not allowed to perform the requested action. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "404": + description: The requested resource could not be found. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: The request body was invalid and could not be processed + content: + application/json: + schema: + $ref: "#/components/schemas/ValidationErrorResponse" + security: + - SWAT-Token: [] + /account: + get: + tags: + - Account Resource + summary: Get default RCPD account. + description: Get the default RCPD account for this user. + operationId: getDefaultAccount + responses: + "500": + description: Something went wrong when processing the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "502": + description: A dependent service or database had an error. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "200": + description: The requested RCPD account. + content: + application/json: + schema: + $ref: "#/components/schemas/AccountResponse" + "401": + description: "Authorization header is not present, or token is invalid or\ + \ expired." + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "503": + description: The security infrastructure cannot currently handle the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "404": + description: The requested resource could not be found. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + security: + - SWAT-Token: [] + post: + tags: + - Account Resource + summary: Create a new RPCD account + description: "Create a new RPCD account with the given username, and owned by\ + \ the user of the provided token." + operationId: newAccount + requestBody: + description: The details of the RPCD account to create. + content: + application/json: + schema: + $ref: "#/components/schemas/AccountCreationRequest" + required: true + responses: + "500": + description: Something went wrong when processing the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "502": + description: A dependent service or database had an error. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "201": + description: The RCPD account has been created. + headers: + Location: + description: The URL of the newly-created RCPD account. + style: simple + schema: + type: uri + example: /account/Teller55 + "400": + description: The request did not include a request body. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "409": + description: The username is already registered. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: The request body was invalid and could not be processed + content: + application/json: + schema: + $ref: "#/components/schemas/ValidationErrorResponse" + "401": + description: "Authorization header is not present, or token is invalid or\ + \ expired." + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "503": + description: The security infrastructure cannot currently handle the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + security: + - SWAT-Token: [] + /account/{username}/set-default: + post: + tags: + - Account Resource + summary: Set default account for user + description: Set the default RCPD account for this user. Must be an account + this user owns. + operationId: setDefaultAccount + parameters: + - name: username + in: path + description: The username of the RCPD account to set as the default account + for this user. The username is case sensitive. + required: true + schema: + type: string + example: teller55 + responses: + "500": + description: Something went wrong when processing the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "502": + description: A dependent service or database had an error. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "204": + description: The account has successfully been set to be the default account. + "401": + description: "Authorization header is not present, or token is invalid or\ + \ expired." + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "503": + description: The security infrastructure cannot currently handle the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "403": + description: You are not allowed to perform the requested action. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "404": + description: The requested resource could not be found. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + security: + - SWAT-Token: [] + /accounts/active-count: + get: + tags: + - Accounts Resource + summary: Get number of active players. + description: Get the number of active RCPD users. Active means somebody who + has logged in or done things on their account recently. + operationId: countActiveAccounts + responses: + "500": + description: Something went wrong when processing the request. + content: + text/plain: + schema: + $ref: "#/components/schemas/ErrorResponse" + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "502": + description: A dependent service or database had an error. + content: + text/plain: + schema: + $ref: "#/components/schemas/ErrorResponse" + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "200": + description: The number of active RCPD users. + content: + text/plain: + example: 47 + /accounts: + get: + tags: + - Accounts Resource + summary: Get users' accounts. + description: Get all the RCPD accounts owned by this user. + operationId: getAccounts + responses: + "500": + description: Something went wrong when processing the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "502": + description: A dependent service or database had an error. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "200": + description: A list of RCPD account summaries. + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/AccountSummaryResponse" + "401": + description: "Authorization header is not present, or token is invalid or\ + \ expired." + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "503": + description: The security infrastructure cannot currently handle the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + security: + - SWAT-Token: [] + /accounts/leaderboard: + get: + tags: + - Accounts Resource + summary: Get the leaderboard + description: "Get accounts on the leaderboard, ordered by account rank and points." + operationId: getLeaderboard + parameters: + - name: limit + in: query + description: The maximum number of accounts to be returned. + schema: + type: integer + format: int32 + default: 30 + responses: + "500": + description: Something went wrong when processing the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "502": + description: A dependent service or database had an error. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "200": + description: The leaderboard accounts. + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/AccountSummaryResponse" + /accounts/search: + get: + tags: + - Accounts Resource + summary: Search for accounts. + description: "Search for any accounts matching the provided username. The results\ + \ will include both partial matches, and sound-alike matches. (IE if you search\ + \ for John, the results will include Jon)" + operationId: searchAccounts + parameters: + - name: searchName + in: query + description: The partial or sound-alike username to search for. + required: true + schema: + type: string + example: teller + responses: + "500": + description: Something went wrong when processing the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "502": + description: A dependent service or database had an error. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "200": + description: A list of RCPD account summaries whose usernames match the + provided search query. + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/AccountSummaryResponse" + "400": + description: Username to search for was not provided. Includes if the provided + query param is blank. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + /account/rank-code/{rankCode}: + delete: + tags: + - Rank Code Resource + summary: Delete saved build for default account. + description: Delete a saved build on the user's default account. + operationId: deleteSavedBuild + parameters: + - name: rankCode + in: path + description: "The SWAT: Aftermath hero build rank code that identifies the\ + \ saved build to be deleted." + required: true + schema: + type: string + example: 1522-4120-7272-0500 + responses: + "500": + description: Something went wrong when processing the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "502": + description: A dependent service or database had an error. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "204": + description: The request was executed successfully. The build is deleted + if it existed. + "400": + description: The provided rank code is invalid. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "404": + description: The requested resource could not be found. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "401": + description: "Authorization header is not present, or token is invalid or\ + \ expired." + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "503": + description: The security infrastructure cannot currently handle the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + security: + - SWAT-Token: [] + /account/{username}/rank-code/{rankCode}: + delete: + tags: + - Rank Code Resource + summary: Delete saved build for specified account. + description: Delete a saved build on the specified account. The user must own + the account. + operationId: deleteSavedBuild_1 + parameters: + - name: username + in: path + description: The RCPD account to delete the saved build from. The username + is case sensitive. + required: true + schema: + type: string + example: teller55 + - name: rankCode + in: path + description: "The SWAT: Aftermath hero build rank code that identifies the\ + \ saved build to be deleted." + required: true + schema: + type: string + example: 1522-4120-7272-0500 + responses: + "500": + description: Something went wrong when processing the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "502": + description: A dependent service or database had an error. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "204": + description: The request was executed successfully. The build is deleted + if it existed. + "400": + description: The provided rank code is invalid. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "403": + description: You are not allowed to perform the requested action. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "404": + description: The requested resource could not be found. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "401": + description: "Authorization header is not present, or token is invalid or\ + \ expired." + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "503": + description: The security infrastructure cannot currently handle the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + security: + - SWAT-Token: [] + /account/generate: + post: + tags: + - Rank Code Resource + summary: Generate a rank code for default account. + description: Generate a SWAT rank code using the default RCPD account for this + user. + operationId: generate + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/BuildRequest" + responses: + "500": + description: Something went wrong when processing the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "502": + description: A dependent service or database had an error. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "200": + description: "The generated rank code, along with the details of the hero\ + \ build, including any medals or titles." + content: + application/json: + schema: + $ref: "#/components/schemas/HeroBuildResponse" + "401": + description: "Authorization header is not present, or token is invalid or\ + \ expired." + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "503": + description: The security infrastructure cannot currently handle the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "404": + description: The requested resource could not be found. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + security: + - SWAT-Token: [] + /account/{username}/generate: + post: + tags: + - Rank Code Resource + summary: Generate a rank code for specified account. + description: Generate a SWAT rank code using the specified RCPD account. The + account must be owned by the user. + operationId: generate_1 + parameters: + - name: username + in: path + description: The RCPD account to get saved builds for. The username is case + sensitive. + required: true + schema: + type: string + example: teller55 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/BuildRequest" + responses: + "500": + description: Something went wrong when processing the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "502": + description: A dependent service or database had an error. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "200": + description: "The generated rank code, along with the details of the hero\ + \ build, including any medals or titles." + content: + application/json: + schema: + $ref: "#/components/schemas/HeroBuildResponse" + "401": + description: "Authorization header is not present, or token is invalid or\ + \ expired." + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "503": + description: The security infrastructure cannot currently handle the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "403": + description: You are not allowed to perform the requested action. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "404": + description: The requested resource could not be found. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + security: + - SWAT-Token: [] + /account/saved-builds: + get: + tags: + - Rank Code Resource + summary: Get saved builds for default account. + description: Get the saved builds for the default RCPD account. + operationId: getSavedBuilds + responses: + "500": + description: Something went wrong when processing the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "502": + description: A dependent service or database had an error. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "200": + description: The saved builds. + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/HeroBuildResponse" + "401": + description: "Authorization header is not present, or token is invalid or\ + \ expired." + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "503": + description: The security infrastructure cannot currently handle the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "404": + description: The requested resource could not be found. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + security: + - SWAT-Token: [] + /account/{username}/saved-builds: + get: + tags: + - Rank Code Resource + summary: Get saved builds for account. + description: "Get the saved builds for the specified RCPD account. If the account\ + \ is not owned by the user, or no token is provided, a public view of the\ + \ saved builds will be returned." + operationId: getSavedBuilds_1 + parameters: + - name: username + in: path + description: The RCPD account to get saved builds for. The username is case + sensitive. + required: true + schema: + type: string + example: teller55 + responses: + "500": + description: Something went wrong when processing the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "502": + description: A dependent service or database had an error. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "200": + description: The saved builds. + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/HeroBuildResponse" + "401": + description: "Authorization header is not present, or token is invalid or\ + \ expired." + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "503": + description: The security infrastructure cannot currently handle the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "404": + description: The requested resource could not be found. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + security: + - SWAT-Token: [] + /account/rank-code: + post: + tags: + - Rank Code Resource + summary: Save a rank code to the default account + description: "Save a rank code, along with an optional name for this build.\ + \ This will be saved to the default account for this user." + operationId: saveRankCode + requestBody: + description: The rank code and optional build name. + content: + application/json: + schema: + $ref: "#/components/schemas/RankCodeRequest" + required: true + responses: + "500": + description: Something went wrong when processing the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "502": + description: A dependent service or database had an error. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "200": + description: "The saved build, plus any other saved builds that have had\ + \ medals or titles updated as a result of the new build being saved. If\ + \ the build that was saved had earned any medals or titles, then all saved\ + \ builds with the same class/trait/specialization combination will be\ + \ updated and returned. This avoids the scenario of earning a medal/title\ + \ on one build, and then earning the same medal/title on another build\ + \ with the same class/trait/specialization combination which shares the\ + \ new medal/title." + content: + application/json: + schema: + minItems: 1 + type: array + items: + $ref: "#/components/schemas/HeroBuildResponse" + "400": + description: The provided rank code is invalid. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "404": + description: The requested resource could not be found. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: The request body was invalid and could not be processed + content: + application/json: + schema: + $ref: "#/components/schemas/ValidationErrorResponse" + "401": + description: "Authorization header is not present, or token is invalid or\ + \ expired." + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "503": + description: The security infrastructure cannot currently handle the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + security: + - SWAT-Token: [] + /account/{username}/rank-code: + post: + tags: + - Rank Code Resource + summary: Save a rank code to the specified account + description: "Save a rank code, along with an optional name for this build,\ + \ to the specified RCPD account." + operationId: saveRankCode_1 + parameters: + - name: username + in: path + description: The RCPD account to save this rank code to. The username is case + sensitive. + required: true + schema: + type: string + example: teller55 + requestBody: + description: The rank code and optional build name. + content: + application/json: + schema: + $ref: "#/components/schemas/RankCodeRequest" + required: true + responses: + "500": + description: Something went wrong when processing the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "502": + description: A dependent service or database had an error. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "200": + description: "The saved build, plus any other saved builds that have had\ + \ medals or titles updated as a result of the new build being saved. If\ + \ the build that was saved had earned any medals or titles, then all saved\ + \ builds with the same class/trait/specialization combination will be\ + \ updated and returned. This avoids the scenario of earning a medal/title\ + \ on one build, and then earning the same medal/title on another build\ + \ with the same class/trait/specialization combination which shares the\ + \ new medal/title." + content: + application/json: + schema: + minItems: 1 + type: array + items: + $ref: "#/components/schemas/HeroBuildResponse" + "400": + description: The provided rank code is invalid. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "403": + description: You are not allowed to perform the requested action. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "404": + description: The requested resource could not be found. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: The request body was invalid and could not be processed + content: + application/json: + schema: + $ref: "#/components/schemas/ValidationErrorResponse" + "401": + description: "Authorization header is not present, or token is invalid or\ + \ expired." + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "503": + description: The security infrastructure cannot currently handle the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + security: + - SWAT-Token: [] + /account/unlocks: + get: + tags: + - Unlocks Resource + summary: Get unlocks for default account. + description: Get the currently unlocked rank for each SWAT build element for + the user's default account. + operationId: getUnlocks + responses: + "500": + description: Something went wrong when processing the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "502": + description: A dependent service or database had an error. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "200": + description: The maximum unlocked rank of each element of a SWAT build. + content: + application/json: + schema: + $ref: "#/components/schemas/UnlocksResponse" + "401": + description: "Authorization header is not present, or token is invalid or\ + \ expired." + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "503": + description: The security infrastructure cannot currently handle the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "404": + description: The requested resource could not be found. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + security: + - SWAT-Token: [] + /account/{username}/unlocks: + get: + tags: + - Unlocks Resource + summary: Get unlocks for specified account. + description: Get the currently unlocked rank for each SWAT build element for + the specified RCPD account. The account must be owned by the user. + operationId: getUnlocks_1 + parameters: + - name: username + in: path + description: The RCPD account to retrieve the unlocks for. The username is + case sensitive. + required: true + schema: + type: string + example: teller55 + responses: + "500": + description: Something went wrong when processing the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "502": + description: A dependent service or database had an error. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "200": + description: The maximum unlocked rank of each element of a SWAT build. + content: + application/json: + schema: + $ref: "#/components/schemas/UnlocksResponse" + "401": + description: "Authorization header is not present, or token is invalid or\ + \ expired." + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "503": + description: The security infrastructure cannot currently handle the request. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "403": + description: You are not allowed to perform the requested action. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "404": + description: The requested resource could not be found. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + security: + - SWAT-Token: [] + /openapi.{type}: + get: + tags: + - Open API Resource + description: Get the Open API documentation in JSON or YAML format. + operationId: getOpenApiSpec + parameters: + - name: type + in: path + description: The extension type of the Open API documentation file. Must be + either yaml or json. + required: true + schema: + pattern: json|yaml + type: string + enum: + - yaml + - json + example: yaml + responses: + "200": + description: The Open API documentation in JSON or YAML format. + content: + application/json: {} + application/yml: {} + /openapi/{file}: + get: + tags: + - Open API Resource + description: "Retrieve a file required for the Swagger UI. It is recommended\ + \ to retrieve the index.html file, and allow the index.html file to retrieve\ + \ the assets it needs." + operationId: getFile + parameters: + - name: file + in: path + description: The file to retrieve. + required: true + schema: + type: string + example: index.html + responses: + "200": + description: The requested file. + content: + image/png: {} + text/css: {} + text/html: {} + text/javascript: {} + text/plain: {} + "404": + description: The requested file was not found. + content: + text/plain: {} + "415": + description: The requested file format is not a format supported by this + resource. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" +components: + schemas: + ErrorResponse: + type: object + properties: + reference: + type: string + description: A unique reference for your error. Provide this to the admins + to help track down your issue. + example: kcog4koca5xhiegavarp + message: + type: string + description: A message describing the error that occurred. + example: An error occurred. + serviceName: + type: string + description: The name of this service. Will always be rcpd-service. + example: rcpd-service + description: "Response indicating an error has occurred, with a unique reference\ + \ and a description of the error." + AccountResponse: + title: Account Response + type: object + properties: + username: + type: string + description: The username of this RCPD account. + example: Teller55 + icon: + type: integer + description: An integer representing the icon (display picture) for the + account. + format: int32 + example: 0 + description: + type: string + description: A public message for the account that will be displayed on + the leaderboard and to people viewing the account. + nullable: true + example: Swat season 2 lets go! + squad: + type: string + description: The group/clan this account belongs to. + nullable: true + example: XLR8 + note: + type: string + description: A private note for this account. Only visible to the account + owner. + nullable: true + example: My super secret plan for winning every EXT game. + rank: + maximum: 11 + minimum: 1 + type: integer + description: The account rank as an integer. + format: int32 + example: 1 + points: + type: integer + description: The amount of points this account has earned through titles. + format: int64 + example: 100 + leaderboardRanking: + type: integer + description: "The rank of this account amongst all RCPD accounts, based\ + \ on the number of points this account has earned. Will be null if the\ + \ account is inactive." + format: int32 + nullable: true + example: 10 + honorGuard: + type: boolean + description: Whether this account has joined the honor guard. + example: true + titles: + $ref: "#/components/schemas/AccountTitlesResponse" + corrupt: + type: boolean + description: "Whether this account has used a code generator to save generated\ + \ rank codes, rather than earning codes solely through playing SWAT: Aftermath." + example: false + lastActive: + type: integer + description: "The last time this account was active (logged in to, saved\ + \ a build, generated a build, etc.) represented as milliseconds from epoch." + format: int64 + example: 1695474479000 + active: + type: boolean + description: Whether this account has been logged into or done anything + recently. + description: A response containing information about an RCPD account. + AccountTitlesResponse: + title: Account Titles Response + type: object + properties: + valiantMartyr: + type: boolean + description: Whether this account has won a Nightmare game. + citySavior: + type: boolean + description: Whether this account has won an Extinction game. + livingLegend: + type: boolean + description: "Whether this account has unlocked all classes, guns, armors,\ + \ traits, and specializations to rank 12." + monsterSlayer: + minimum: 0 + type: integer + description: Requires killing Megazilla on multiple hero builds. + format: int32 + vigilantHero: + minimum: 0 + type: integer + description: Requires completing a Nightmare or Extinction game without + dying on multiple hero builds. + format: int32 + coreElite: + minimum: 0 + type: integer + description: Requires earning an Impressive title on multiple hero builds. + format: int32 + loneRanger: + minimum: 0 + type: integer + description: Requires winning solo Nightmare games with multiple classes. + format: int32 + hardenedVeteran: + maximum: 1 + minimum: 0 + type: integer + description: "Requires winning Nightmare games with different player counts.\ + \ Solo games do not count. You must win with every possible other player\ + \ combination, IE 2 players, 3 players, 4 players, etc." + format: int32 + renownedVeteran: + maximum: 2 + minimum: 0 + type: integer + description: "Requires winning Extinction games with different player counts.\ + \ IE, win with 2 players, win with 3 players, etc. 7/8 combinations are\ + \ required for tier 1, all 8 combinations are required for tier 2." + format: int32 + highlyDecorated: + maximum: 2 + minimum: 0 + type: integer + description: "Requires earning all medals except KEY on one build for multiple\ + \ classes. 10 classes required for tier 1, 12 classes required for tier\ + \ 2." + format: int32 + keyMaster: + maximum: 2 + minimum: 0 + type: integer + description: "Requires earning KEY on multiple classes. 10 classes required\ + \ for tier 1, 12 classes required for tier 2." + format: int32 + swatCenturion: + minimum: 0 + type: integer + description: Requires winning Nightmare with different unique builds. + format: int32 + infiniteLegion: + minimum: 0 + type: integer + description: Requires winning Extinction with different unique builds. + format: int32 + allSniperWins: + maximum: 2 + minimum: 0 + type: integer + description: Requires winning Nightmare and/or Extinction with every unique + Sniper combination. + format: int32 + allMedicWins: + maximum: 2 + minimum: 0 + type: integer + description: Requires winning Nightmare and/or Extinction with every unique + Medic combination. + format: int32 + allTacticianWins: + maximum: 2 + minimum: 0 + type: integer + description: Requires winning Nightmare and/or Extinction with every unique + Tactician combination. + format: int32 + allPsychologistWins: + maximum: 2 + minimum: 0 + type: integer + description: Requires winning Nightmare and/or Extinction with every unique + Psychologist combination. + format: int32 + allMaverickWins: + maximum: 2 + minimum: 0 + type: integer + description: Requires winning Nightmare and/or Extinction with every unique + Maverick combination. + format: int32 + allHeavyOrdnanceWins: + maximum: 2 + minimum: 0 + type: integer + description: Requires winning Nightmare and/or Extinction with every unique + Heavy Ordnance combination. + format: int32 + allDemolitionWins: + maximum: 2 + minimum: 0 + type: integer + description: Requires winning Nightmare and/or Extinction with every unique + Demolitions combination. + format: int32 + allCyborgWins: + maximum: 2 + minimum: 0 + type: integer + description: Requires winning Nightmare and/or Extinction with every unique + Cyborg combination. + format: int32 + allPyrotechnicianWins: + maximum: 2 + minimum: 0 + type: integer + description: Requires winning Nightmare and/or Extinction with every unique + Pyrotechnician combination. + format: int32 + allWatchmanWins: + maximum: 2 + minimum: 0 + type: integer + description: Requires winning Nightmare and/or Extinction with every unique + Watchman combination. + format: int32 + allTechOpsWins: + maximum: 2 + minimum: 0 + type: integer + description: Requires winning Nightmare and/or Extinction with every unique + Tech Ops combination. + format: int32 + allUmbrellaCloneWins: + maximum: 2 + minimum: 0 + type: integer + description: Requires winning Nightmare and/or Extinction with every unique + Umbrella Clone combination. + format: int32 + description: "A response including all the titles this account has earned. For\ + \ the integer properties, a value of 0 means the title is unearned; 1 or higher\ + \ means the title is earned, and indicates the level of that title." + AccountCreationRequest: + required: + - username + type: object + properties: + username: + maxLength: 15 + minLength: 3 + type: string + description: The username of the new RCPD account. This must be the same + as the name used in Warcraft III. + example: Teller55 + description: The username for the new RCPD account. + ValidationErrorResponse: + type: object + properties: + reference: + type: string + description: A unique reference for your error. Provide this to the admins + to help track down your issue. + example: kcog4koca5xhiegavarp + message: + type: string + description: A message describing the error that occurred. + example: An error occurred. + errors: + type: object + additionalProperties: + type: array + description: "The properties for the given request that were invalid,\ + \ along with all the reasons why each property was invalid." + example: + username: + - must not be blank + - size must be between 3 and 15 + items: + type: string + description: "The properties for the given request that were invalid,\ + \ along with all the reasons why each property was invalid." + example: "{\"username\":[\"must not be blank\",\"size must be between\ + \ 3 and 15\"]}" + description: "The properties for the given request that were invalid, along\ + \ with all the reasons why each property was invalid." + example: + username: + - must not be blank + - size must be between 3 and 15 + serviceName: + type: string + description: The name of this service. Will always be rcpd-service. + example: rcpd-service + description: "Response indicating the request was invalid, along with the validation\ + \ errors." + AccountUpdateRequest: + title: Account Update Request + type: object + properties: + icon: + maximum: 11 + minimum: 0 + type: integer + description: The integer that represents the display icon for the account. + format: int32 + example: 0 + description: + maxLength: 255 + minLength: 0 + type: string + description: The description that will be displayed for this account. + example: I am the best SWAT player ever! + squad: + maxLength: 32 + minLength: 0 + type: string + description: The squad/clan this account belongs to. + example: XLR8 + note: + maxLength: 255 + minLength: 0 + type: string + description: A private note for this account that only the account owner + can see. + example: This is my private note for my eyes only. + description: "A request to update various things on an account. All parameters\ + \ are optional. To delete a value, provide an empty string. This will delete\ + \ the value in the database." + AccountSummaryResponse: + type: object + properties: + username: + type: string + description: The username of this RCPD account. + example: Teller55 + icon: + type: integer + description: An integer representing the icon (display picture) for the + account. + format: int32 + example: 0 + description: + type: string + description: A public message for the account that will be displayed on + the leaderboard and to people viewing the account. + nullable: true + example: Swat season 2 lets go! + squad: + type: string + description: The group/clan this account belongs to. + nullable: true + example: XLR8 + rank: + maximum: 11 + minimum: 1 + type: integer + description: The account rank as an integer. + format: int32 + example: 1 + corrupt: + type: boolean + description: "Whether this account has used a code generator to save generated\ + \ rank codes, rather than earning codes solely through playing SWAT: Aftermath." + example: false + active: + type: boolean + description: Whether this account has been logged into or done anything + recently. + lastActive: + type: integer + description: "The last time this account was active (logged in to, saved\ + \ a build, generated a build, etc.) represented as milliseconds from epoch." + format: int64 + example: 1695474479000 + honorGuard: + type: boolean + description: Whether this account has joined the honor guard. + example: true + description: An RCPD account summary. + HeroBuildResponse: + title: Hero Build Response + type: object + properties: + rankCode: + type: string + description: "The SWAT: Aftermath rank code for this build, which can be\ + \ used in a game of SWAT: Aftermath to load this build. Will not be included\ + \ for public view." + nullable: true + example: 6595-0027-2041-6700 + swatClass: + type: string + description: The class of this build. http://redscull.com/swat/readmeafterclasses.html + example: Sniper + enum: + - Sniper + - Medic + - Tactician + - Psychologist + - Maverick + - HeavyOrdnance + - Demolitions + - Cyborg + - Pyrotechnician + - Watchman + - TechOps + - UmbrellaClone + gun: + type: string + description: The gun used by this build. http://redscull.com/swat/readmeafterweapons.html + example: SniperRifle + enum: + - AssaultRifle + - SniperRifle + - Chaingun + - RocketLauncher + - Flamethrower + - LaserRifle + - GatlingLaser + - Pistols + armor: + type: string + description: The armor used by this build. http://redscull.com/swat/readmeafterarmor.html + example: Light + enum: + - Light + - Medium + - Heavy + - Advanced + trait: + type: string + description: The trait used by this build. http://redscull.com/swat/readmeaftertraits.html + example: Dragoon + enum: + - Skilled + - Gifted + - Survivalist + - Dragoon + - Acrobat + - SwiftLearner + - Healer + - FlowerChild + - ChemReliant + - RadResistant + - Gadgeteer + - Prowler + - Energizer + - PackRat + - Engineer + - Reckless + specialization: + type: string + description: The specialization used by this build. http://redscull.com/swat/readmeafterspecs.html + example: Weaponry + enum: + - Weaponry + - PowerArmor + - EnergyCells + - Cybernetics + - Triage + - Chemistry + - Leadership + - Robotics + - Espionage + talent: + type: string + description: The talent used by this build. Only included if the build's + rank is 9 or higher. http://redscull.com/swat/readmeaftertalents.html + nullable: true + example: Tinkering + enum: + - Courage + - Wiring + - Running + - Spotting + - Toughness + - Tinkering + - Hacking + rank: + maximum: 12 + minimum: 1 + type: integer + description: The rank of this build. http://redscull.com/swat/readmeafterrank.html + format: int32 + example: 1 + maxRank: + maximum: 12 + minimum: 3 + type: integer + description: "The maximum rank this build can achieve, determined by the\ + \ highest difficulty this build has beaten. http://redscull.com/swat/readmeafterrank.html" + format: int32 + example: 3 + key: + type: boolean + description: Whether this build has earned the Key to the City medal. http://redscull.com/swat/readmeafterrank.html#medals + moh: + type: boolean + description: Whether this build has earned the Medal of Honor medal. http://redscull.com/swat/readmeafterrank.html#medals + pcc: + type: boolean + description: Whether this build has earned the Police Combat Cross medal. + http://redscull.com/swat/readmeafterrank.html#medals + cob: + type: boolean + description: Whether this build has earned the Commendation Bar medal. http://redscull.com/swat/readmeafterrank.html#medals + lsa: + type: boolean + description: Whether this build has earned the Life Saving Award medal. + http://redscull.com/swat/readmeafterrank.html#medals + rem: + maximum: 3 + minimum: 0 + type: integer + description: "Whether this build has earned the Recognition for Exceptional\ + \ Merit medal, and what level. http://redscull.com/swat/readmeafterrank.html#medals" + format: int32 + example: 0 + honorGuard: + type: boolean + description: Whether this build is an honor guard build. + nightmare: + type: boolean + description: Whether this build has beaten Nightmare difficulty. http://redscull.com/swat/readmeafterobjectives.html + Will not be included for public view. + extinction: + type: boolean + description: Whether this build has beaten Extinction difficulty. http://redscull.com/swat/readmeafterobjectives.html + Will not be included for public view. + megazilla: + type: boolean + description: Whether this build has helped to kill Megazilla. http://redscull.com/swat/readmeafterobjectives.html#megazilla + Will not be included for public view. + deathless: + type: boolean + description: Whether this build has completed Nightmare or Extinction difficulty + without dying. Will not be included for public view. + impressive: + type: boolean + description: Whether this build has participated in a game that earned a + Medal of Honor while already having a Medal of Honor. http://redscull.com/swat/readmeafterrank.html#medals + Will not be included for public view. + solo: + type: boolean + description: Whether this build has beaten a solo Nightmare game. http://redscull.com/swat/readmeafterobjectives.html + Will not be included for public view. + buildName: + type: string + description: An optional name used to identify this build. + nullable: true + example: hacking psy + description: "A response object describing a SWAT hero, including rank code\ + \ and build name." + BuildRequest: + title: Build Request + required: + - armor + - gun + - specialization + - swatClass + - talent + - trait + type: object + properties: + swatClass: + type: string + description: The class of this SWAT hero. + writeOnly: true + example: Psychologist + enum: + - Sniper + - Medic + - Tactician + - Psychologist + - Maverick + - HeavyOrdnance + - Demolitions + - Cyborg + - Pyrotechnician + - Watchman + - TechOps + - UmbrellaClone + gun: + type: string + description: The gun this SWAT hero uses. + writeOnly: true + example: AssaultRifle + enum: + - AssaultRifle + - SniperRifle + - Chaingun + - RocketLauncher + - Flamethrower + - LaserRifle + - GatlingLaser + - Pistols + armor: + type: string + description: The armor this SWAT hero uses. + writeOnly: true + example: Medium + enum: + - Light + - Medium + - Heavy + - Advanced + trait: + type: string + description: The trait of this SWAT hero. + writeOnly: true + example: Healer + enum: + - Skilled + - Gifted + - Survivalist + - Dragoon + - Acrobat + - SwiftLearner + - Healer + - FlowerChild + - ChemReliant + - RadResistant + - Gadgeteer + - Prowler + - Energizer + - PackRat + - Engineer + - Reckless + specialization: + type: string + description: The specialization of this SWAT hero. + writeOnly: true + example: Triage + enum: + - Weaponry + - PowerArmor + - EnergyCells + - Cybernetics + - Triage + - Chemistry + - Leadership + - Robotics + - Espionage + talent: + type: string + description: The talent of this SWAT hero. + writeOnly: true + example: Hacking + enum: + - Courage + - Wiring + - Running + - Spotting + - Toughness + - Tinkering + - Hacking + rank: + maximum: 12 + minimum: 1 + type: integer + description: "The rank of this SWAT hero. Will be capped at the lowest rank\ + \ part of the build. For example, if the requested talent is only available\ + \ at rank 4, the build will be capped to rank 4, even if the requested\ + \ rank is higher. This parameter is optional; if not specified, the build\ + \ will be generated at the highest possible rank." + format: int32 + example: 10 + spoof: + maxLength: 15 + minLength: 3 + type: string + description: "The name to generate this rank code for, different to the\ + \ account's name. If this name is provided, the rank code will be capped\ + \ at rank 11, and not include any medals." + example: teller55 + description: A request containing all the parts for a SWAT hero. + RankCodeRequest: + title: Rank Code Request + required: + - rankCode + type: object + properties: + rankCode: + maxLength: 19 + minLength: 16 + type: string + description: "The SWAT: Aftermath rank code to save. Must be either 16 or\ + \ 19 characters in length." + example: 6595-0027-2041-6700 + buildName: + maxLength: 32 + minLength: 0 + type: string + description: An optional name for this build. + example: Solo HO + description: A rank code and optional build name to save. + UnlocksResponse: + title: Unlocks Response + type: object + properties: + swatClasses: + type: object + additionalProperties: + type: integer + format: int32 + guns: + type: object + additionalProperties: + type: integer + format: int32 + armor: + type: object + additionalProperties: + type: integer + format: int32 + traits: + type: object + additionalProperties: + type: integer + format: int32 + specializations: + type: object + additionalProperties: + type: integer + format: int32 + talents: + type: object + additionalProperties: + type: integer + format: int32 + description: "The maximum rank achieved for every part of a SWAT hero; classes,\ + \ guns, armors, traits, specializations, and talents. The keys for each map\ + \ can be found by viewing the request schema for the /account/generate endpoint." diff --git a/swat-codegen/swat-codegen-1.0.2-1-any.pkg.tar.zst b/swat-codegen/swat-codegen-1.0.2-1-any.pkg.tar.zst new file mode 100644 index 0000000000000000000000000000000000000000..7b2fdf41cba07dc14e6b2f43170e5e52ec1ff078 GIT binary patch literal 23040 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%0At(3y(~7{DRpNGcnn{Mj8T!W+pS)D`~Cx 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%0A-d=VtStIR%8mLj@N`JC=9zyc0(L`E3fDFG(H6=Y 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