diff --git a/.devcontainer/create.sh b/.devcontainer/create.sh new file mode 100644 index 00000000..4fc5314a --- /dev/null +++ b/.devcontainer/create.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -ex + +# Install protoc (used by go:generate) and add it to path +# Not done in Dockerfile because it seems to lock out writing to some files go needs to write to? +# https://github.com/ericslandry/grpc/blob/dcc9b228a2189933b0666eeea23852a12225092b/.devcontainer/post-create.sh +version=25.4 +PB_REL="https://github.com/protocolbuffers/protobuf/releases" +curl -LO $PB_REL/download/v$version/protoc-$version-linux-x86_64.zip +unzip protoc-$version-linux-x86_64.zip -d $HOME/.local/ +export PATH="$PATH:$HOME/.local/bin" +go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.34.2 +go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.3.0 +export PATH="$PATH:$(go env GOPATH)/bin" + +# Install libwebp (otherwise go:generate tries and fails to build it itself or something) +# https://developers.google.com/speed/webp/docs/precompiled +libwebp_version=1.4.0 +libwebp_file="libwebp-$libwebp_version-linux-x86-64.tar.gz" +curl -LO "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/$libwebp_file" +mkdir -p $HOME/libwebp +tar xzvf $libwebp_file -C $HOME/libwebp +export PATH="$PATH:$HOME/libwebp/bin" + +# Add as a safe git directory +git config --global --add safe.directory "/workspaces/smr_api" diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index aa5ee03a..3ddb8006 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,40 +1,47 @@ { - "name": "Go", + "name": "smr-api", "dockerComposeFile": "docker-compose.yml", "service": "app", - "workspaceFolder": "/workspace", + "workspaceFolder": "/workspaces/smr_api", + "onCreateCommand": "./.devcontainer/create.sh", "updateContentCommand": "go mod download && go generate -tags tools -x ./...", + // Add the IDs of extensions you want installed when the container is created. - "extensions": [ - "golang.Go", - "mtxr.sqltools", - "mtxr.sqltools-driver-pg" - ], - "settings": { - "go.toolsManagement.checkForUpdates": "local", - "go.useLanguageServer": true, - "go.gopath": "/go", - "go.goroot": "/usr/local/go", - "sqltools.connections": [ - { - "name": "Container database", - "driver": "PostgreSQL", - "previewLimit": 50, - "server": "localhost", - "port": 5432, - "database": "postgres", - "username": "postgres", - "password": "REPLACE_ME" + "customizations": { + "vscode": { + "extensions": [ + "golang.Go", + "mtxr.sqltools", + "mtxr.sqltools-driver-pg", + "streetsidesoftware.code-spell-checker" + ], + "settings": { + "go.toolsManagement.checkForUpdates": "local", + "go.useLanguageServer": true, + "go.gopath": "/go", + "go.goroot": "/usr/local/go", + "sqltools.connections": [ + { + "name": "Container database", + "driver": "PostgreSQL", + "previewLimit": 50, + "server": "localhost", + "port": 5432, + "database": "postgres", + "username": "postgres", + "password": "REPLACE_ME" + } + ] } - ] + } }, "forwardPorts": [ 5432, 6379, 9000, 9001, - 5020, + 5020 ], // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. "remoteUser": "vscode" -} +} \ No newline at end of file diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index ed54b3d0..987b1e40 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -9,7 +9,7 @@ services: VARIANT: "1-bullseye" NODE_VERSION: "none" volumes: - - ..:/workspace:cached + - ..:/workspaces/smr_api:cached cap_add: - SYS_PTRACE network_mode: service:postgres diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..80f246ba --- /dev/null +++ b/.gitattributes @@ -0,0 +1,9 @@ +# Auto detect text files and perform LF normalization +# This keeps unix/windows machines from wanting to change every file +# from the other because of the line ending (\r vs \r\n) +* text=auto +*.sh text eol=lf +*.env* text eol=lf + +# Atlas migration hashes are different if file get windows line endings +*.sql text eol=lf diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c92fe0ea..e843dd6e 100755 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -58,8 +58,11 @@ jobs: env: GITHUB_TOKEN: ${{ github.token }} + - name: List file tasks and their permissions + run: cd ./.mise/tasks/ && ls -l + - name: Setup - run: mise run setup + run: mise run setup -ci - name: Test run: mise run test_coverage_junit @@ -105,7 +108,7 @@ jobs: GITHUB_TOKEN: ${{ github.token }} - name: Setup - run: mise run setup + run: mise run setup -ci - name: Download and seed database run: | diff --git a/.github/workflows/generated.yml b/.github/workflows/generated.yml index bc3bd3ba..1ec46157 100644 --- a/.github/workflows/generated.yml +++ b/.github/workflows/generated.yml @@ -23,8 +23,14 @@ jobs: - name: Tidy run: go mod tidy - - name: Ensure no changes - run: git diff --exit-code + - name: Ensure freshly generated hashes match committed ones + # Ignore mise.lock because it seems like mise can't generate checksums for platforms that you aren't on -> always diff + run: | + if ! git diff --exit-code ':!mise.lock'; then + echo "Error: Generating migration hashes again produced output that doesn't match those committed to the repo." + echo "Run 'mise run migrate_hash' and commit the changes." + exit 1 + fi go: runs-on: ubuntu-latest @@ -41,5 +47,11 @@ jobs: - name: Tidy run: go mod tidy - - name: Ensure no changes - run: git diff --exit-code + - name: Ensure freshly generated code matches committed code + # Ignore mise.lock because it seems like mise can't generate checksums for platforms that you aren't on -> always diff + run: | + if ! git diff --exit-code ':!mise.lock'; then + echo "Error: Regenerating the generated code produced output that doesn't match the code committed to the repo." + echo "Run 'mise run generate' and commit the changes." + exit 1 + fi diff --git a/.mise/tasks/mark_chmod_execute.ps1 b/.mise/tasks/mark_chmod_execute.ps1 new file mode 100644 index 00000000..4ac9450c --- /dev/null +++ b/.mise/tasks/mark_chmod_execute.ps1 @@ -0,0 +1,9 @@ +#MISE description="For developers on Windows, mark all .sh file-based Mise tasks as executable so Linux devs and the CI can use them" + +$shFiles = Get-ChildItem -Path "./.mise/tasks" -Filter "*.sh" -File + +foreach ($file in $shFiles) { + Write-Host "Setting Linux execute permission on $($file.Name)" + # https://git-scm.com/docs/git-update-index#Documentation/git-update-index.txt---chmod-x + git update-index --add --chmod=+x $file.FullName +} diff --git a/.mise/tasks/migrate_diff.sh b/.mise/tasks/migrate_diff_linux.sh similarity index 83% rename from .mise/tasks/migrate_diff.sh rename to .mise/tasks/migrate_diff_linux.sh index aa1eb034..8bbdf830 100755 --- a/.mise/tasks/migrate_diff.sh +++ b/.mise/tasks/migrate_diff_linux.sh @@ -1,7 +1,10 @@ #!/usr/bin/env bash +#MISE hide=true echo -n 'Migration Name: ' read -r migration_name +echo -n "Atlas is running..." + atlas migrate diff "$migration_name" --dir "file://migrations/sql?format=golang-migrate" --to "ent://db/schema" --dev-url "docker://postgres/16/test?search_path=public" diff --git a/.mise/tasks/migrate_diff_windows.ps1 b/.mise/tasks/migrate_diff_windows.ps1 new file mode 100644 index 00000000..60ab97fc --- /dev/null +++ b/.mise/tasks/migrate_diff_windows.ps1 @@ -0,0 +1,9 @@ +#MISE hide=true + +Write-Host -NoNewline 'Migration Name: ' +$migration_name = Read-Host +Write-Host "Atlas is running..." +atlas migrate diff "$migration_name" --dir "file://migrations/sql?format=golang-migrate" --to "ent://db/schema" --dev-url "docker://postgres/16/test?search_path=public" +if (-not $?) { + Write-Error "If the above failed due to a checksum error, don't run the command it suggests, instead run ``mise run migrate_hash`` " +} diff --git a/.mise/tasks/migrate_new.sh b/.mise/tasks/migrate_new_linux.sh similarity index 90% rename from .mise/tasks/migrate_new.sh rename to .mise/tasks/migrate_new_linux.sh index 28021747..e3e6e088 100755 --- a/.mise/tasks/migrate_new.sh +++ b/.mise/tasks/migrate_new_linux.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +#MISE hide=true echo -n 'Migration Name: ' diff --git a/.mise/tasks/migrate_new_windows.ps1 b/.mise/tasks/migrate_new_windows.ps1 new file mode 100644 index 00000000..4a611726 --- /dev/null +++ b/.mise/tasks/migrate_new_windows.ps1 @@ -0,0 +1,10 @@ +#MISE hide=true + +Write-Host -NoNewline 'Migration Name: ' +$migration_name = Read-Host +atlas migrate new "$migration_name" --dir "file://migrations/sql?format=golang-migrate" +if (-not $?) { + Write-Error "If the above failed due to a checksum error, don't run the command it suggests, instead run ``mise run migrate_hash`` " +} else { + Write-Host "Created new migration '$migration_name', check the migrations/sql/ directory for the new files" +} diff --git a/.mise/tasks/setup_linux.sh b/.mise/tasks/setup_linux.sh new file mode 100755 index 00000000..6e465e21 --- /dev/null +++ b/.mise/tasks/setup_linux.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +#USAGE flag "-ci" "Use plain progress output suitable for CI environments" +#MISE hide=true + +ci=false +while [[ $# -gt 0 ]]; do + case "$1" in + -ci) + ci=true + ;; + *) + ;; + esac + shift +done + +progress=$([ "$ci" = true ] && echo "plain" || echo "auto") + +docker compose --progress "$progress" --file docker-compose-dev.yml up --detach --wait && echo "Waiting for 5 seconds" && sleep 5 +echo "Setting up MinIO..." +mc alias set local http://localhost:9000 minio minio123 +mc admin user svcacct remove local/ REPLACE_ME_KEY --dp || echo It is okay for this REMOVE command to fail if the account is not found +mc admin user svcacct add local minio --access-key REPLACE_ME_KEY --secret-key REPLACE_ME_SECRET +mc anonymous set public local/smr +echo "Setup complete" diff --git a/.mise/tasks/setup_windows.ps1 b/.mise/tasks/setup_windows.ps1 new file mode 100644 index 00000000..a84bf020 --- /dev/null +++ b/.mise/tasks/setup_windows.ps1 @@ -0,0 +1,16 @@ +#USAGE flag "-ci" "Use plain progress output suitable for CI environments" +#MISE hide=true + +param( + [switch]$ci +) + +$progress = if ($ci) { "plain" } else { "auto" } + +docker compose --progress $progress --file docker-compose-dev.yml up --detach --wait && timeout /t 5 +Write-Host "Setting up MinIO... (If it gets stuck here, try restarting WSL via `wsl --shutdown`)" +mc alias set local http://localhost:9000 minio minio123 +mc admin user svcacct remove local/ REPLACE_ME_KEY --dp || Write-Output "It is okay for this REMOVE command to fail if the account is not found" +mc admin user svcacct add local minio --access-key REPLACE_ME_KEY --secret-key REPLACE_ME_SECRET +mc anonymous set public local/smr +Write-Host "Setup complete" diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 6b7defa2..00000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Launch smr-api", - "type": "go", - "request": "launch", - "mode": "auto", - "program": "${workspaceFolder}/cmd/api", - "cwd": "${workspaceFolder}" - } - ] -} diff --git a/README.md b/README.md index a175907c..777292bc 100755 --- a/README.md +++ b/README.md @@ -8,9 +8,15 @@ The Satisfactory Mod Repository backend API - a Go-based service providing REST - [mise](https://mise.jdx.dev/) for tool management - [Docker (and Docker Compose)](https://docs.docker.com/desktop/) +- If on Windows, the [latest PowerShell (>= 7)](https://learn.microsoft.com/en-us/powershell/scripting/install/install-powershell-on-windows). Check current version by running `pwsh -v` in a PowerShell window. ([reason why](https://github.com/jdx/mise/discussions/4151)) ### Setup +> Note: A [devcontainer](https://code.visualstudio.com/docs/devcontainers/containers) exists in this repository, +> but it has not been tested since we switched to using Mise for tool management. +> **You should follow the normal installation instructions below instead of using the devcontainer.** +> We offer no guarantee that it works correctly, but you are welcome to try it out and submit fixes if needed. + 1. Install Tools ```bash @@ -18,8 +24,9 @@ The Satisfactory Mod Repository backend API - a Go-based service providing REST mise install ``` - If you are on Windows, due to a bug in mise, you will also need to do the following: + If you are on Windows, due to a bug in [mise and aqua](https://github.com/aquaproj/aqua-registry/pull/42498/), you will also need to do the following: + ```ps1 > mise where aqua:minio/mc @@ -27,7 +34,19 @@ The Satisfactory Mod Repository backend API - a Go-based service providing REST # Rename the `mc` file to give it an extension: `mc.exe` ``` -2. Start Development Services +2. (First Time Setup Only) Set up the Configuration File + + First, start the containers so you can generate some of the required configuration tokens: + + ```bash + # If this command fails, ensure you have Docker running and configured correctly + mise run setup + ``` + + Next, create a copy of `config.sample.json` as `config.json` and fill in the required fields. + See the [Configuration](#configuration) section for details. + +3. Start Development Services ```bash # If this command fails, ensure you have Docker running and configured correctly @@ -38,20 +57,24 @@ The Satisfactory Mod Repository backend API - a Go-based service providing REST mise run api ``` + If the first line of the output contains `config initialized using defaults and environment only!` then ensure your config file is formatted correctly and does not include `//` comments. + If running `api` produces errors about the database failing to apply migrations, you may have switched branches without cleaning up after database changes you were working on. The easiest way to get back from this state is to delete the `postgres` Docker container and delete all not-in-use volumes so it creates a fresh one. -3. Set up the Configuration File - - Create a copy of `config.sample.json` as `config.json` and fill in the required fields. - See the [Configuration](#configuration) section for details. - ## Development Commands ```bash +# Get information about all available mise tasks +mise tasks + +# Environment management +mise run setup # Start PostgreSQL, Redis, MinIO, etc. containers +mise run teardown # Stop services + # Code generation (run after schema changes) mise run generate @@ -65,18 +88,21 @@ mise run coverage # Linting mise run lint -# Environment management -mise run setup # Start PostgreSQL, Redis, MinIO -mise run teardown # Stop services +# Linux (bash): activate an interactive bash shell with Mise tools loaded +eval "$(mise activate bash)" # Windows: activate an interactive PowerShell with Mise tools loaded. Requires Powershell >= 7 mise activate pwsh | Out-String | Invoke-Expression + +# Database migrations. See `mise tasks` for more info. +mise run migrate_diff ``` ### Local Testing To run specific tests: +- Make sure you have started the containers first via `mise run setup` - In VSCode, the [Go Companion](https://marketplace.visualstudio.com/items?itemName=ethan-reesor.exp-vscode-go) suggested extension adds Go test support to VSCode's testing integration. Note you may need to reload VSCode (`Developer: Reload Window`) after adding or removing tests. - From the command line, use `go test -v run TestNameHere` @@ -88,12 +114,30 @@ It is expected for the command to output `[no test files]` for packages with no The development docker compose also includes a pgadmin container for testing database related stuff exposed at . -The credentials are specified in `docker-compose-dev.yml`. +The credentials are specified in [`docker-compose-dev.yml`](docker-compose-dev.yml). Once logged in, add a server. -The "Host name/address" should be `postgres`, username should be `postgres`, password should be `POSTGRES_PASSWORD` from `docker-compose.yml`. +The "Host name/address" should be `postgres`, username should be `postgres`, password should be `POSTGRES_PASSWORD` from [`docker-compose.yml`](docker-compose.yml). -You can view tables via `Servers >(name)> Databases > postgres > Schemas > public > Tables`. +You can view tables via `Servers > (name) > Databases > postgres > Schemas > public > Tables`. + +#### Site User Roles + +To locally test features of the site that require a user role, you can change your role via direct database queries. +Doing this requires manually creating a `user_groups` entry for you user. + +1. Create an account on your local via the [frontend running with the `development` env](https://github.com/satisfactorymodding/smr-frontend/blob/staging/CONTRIBUTING.md#decide-which-environment-you-want-to-run) +2. Look at [`permissions.go`](/auth/permissions.go) to find the group ID for the group you want to become. Admin is `1`. +3. Run a query in pgadmin to determine your user ID: `SELECT * FROM users;` +4. Run a query to create a user_groups entry for yourself. Example for admin: + + ```sql + INSERT INTO public.user_groups( + user_id, group_id, created_at, updated_at, deleted_at, id) + VALUES ('YOUR_USER_ID_HERE', '1', NOW(), NOW(), null, NOW()); + ``` + +5. Refresh the frontend webpage - you should be an admin now. ## Architecture @@ -101,6 +145,7 @@ You can view tables via `Servers >(name)> Databases > postgres > Schemas > publi - **Framework**: Echo v4 with middleware - **Database**: PostgreSQL with Ent ORM + - [Atlas versioned migrations](https://atlasgo.io/versioned/intro) - **GraphQL**: gqlgen with custom resolvers - **Authentication**: Multi-provider OAuth + PASETO tokens - **Storage**: S3-compatible (MinIO for dev) @@ -115,22 +160,26 @@ You can view tables via `Servers >(name)> Databases > postgres > Schemas > publi - Generated code in `generated/` - Database schemas in `db/schema/` -## Configuration - -Create `config.json`, or use environment variables with `REPO_` prefix. -A sample is provided: `config.sample.json`. - **Required services:** 1. **PostgreSQL** - Database (dev: port 5432) 2. **Redis** - Cache/sessions (dev: port 6379) 3. **MinIO** - Object storage (dev: ports 9000/9001) -4. **OAuth providers** - GitHub, Google, Facebook. For testing purposes, [setting up just GitHub](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app) is the easiest. -5. **PASETO keys** - Generate these with `go run cmd/paseto/main.go` -6. **VirusTotal API key** - For mod scanning. Optional for testing. +4. **VirusTotal** - External API for mod scanning. Optional for testing and local development. + +## Configuration **Development services** are started automatically with `mise run setup`. MinIO configuration is included in the setup task. +Create `config.json`, or use environment variables with `REPO_` prefix. +A sample is provided: `config.sample.json`. + +**For local development, you should change:** + +1. **OAuth providers** - For testing purposes, [setting up just GitHub](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app) is the easiest. +2. **PASETO keys** - Generate these with `mise run make_paseto_keys` +3. **VirusTotal API key** - If you want to test the mod scanning features (optional). + See `config/config.go` for full configuration structure. ## Development Workflow @@ -140,25 +189,35 @@ See `config/config.go` for full configuration structure. - Database schemas (`db/schema/*.go`) - Swagger annotations -2. **Database Changes**: Use Atlas migrations +2. **Database Changes**: Use Atlas migrations (entgo has integration with it via golang-migrate) - SQL migrations in `migrations/sql/` + - Use mise tasks to create migration files (`mise tasks` for more details) + - Migration names should be in `snake_case` - Code migrations in `migrations/code/` + - Created manually + - Get applied after all SQL migrations (see [migrations.go](migrations/migrations.go) for details) 3. **Testing**: Tests require development services running ```bash mise run setup # Start services - mise run test # Run tests + + mise run localtest # Run tests + # OR + mise run test # Run tests (verbose) ``` ## Contributing **Before submitting:** +Commit messages should follow the [Conventional Commits format](https://www.conventionalcommits.org/en/v1.0.0/). + ```bash -mise run lint # Check code quality -mise run test # Run test suite -mise run generate # Regenerate if needed +mise run lint # Check code quality +mise run format # Some linting issues can be auto-fixed +mise run localtest # Run test suite +mise run generate # Regenerate if needed ``` **Development patterns:** diff --git a/config.sample.json b/config.sample.json index d1dd4799..b415bda6 100644 --- a/config.sample.json +++ b/config.sample.json @@ -52,7 +52,7 @@ }, "frontend": { - "url": "http://localhost:4200" + "url": "http://localhost:3000" }, "feature_flags": { diff --git a/cspell.json b/cspell.json new file mode 100644 index 00000000..3826e432 --- /dev/null +++ b/cspell.json @@ -0,0 +1,43 @@ +{ + "version": "0.2", + "language": "en", + "dictionaries": [ + "softwareTerms", + "go" + ], + "words": [ + "devbox", + "dgraph", + "entcache", + "entgo", + "fenv", + "fgprof", + "ficsit", + "golangci", + "goverter", + "gqlgen", + "INNF", + "INNOEF", + "iocopy", + "libwebp", + "Mircea", + "mtxr", + "nixos", + "nolint", + "otelgqlgen", + "Paseto", + "pasteo", + "pgadmin", + "protoc", + "ristretto", + "slox", + "svcacct", + "testza", + "Webp" + ], + // cSpell:disable (don't complain about the words we listed here) + "flagWords": [ + "hte", + "comunity" + ] +} diff --git a/db/schema/mod.go b/db/schema/mod.go index 9e4ef29a..36984f2b 100644 --- a/db/schema/mod.go +++ b/db/schema/mod.go @@ -40,7 +40,8 @@ func (Mod) Fields() []ent.Field { field.String("mod_reference").MaxLen(32), field.Bool("hidden").Default(false), field.JSON("compatibility", &util.CompatibilityInfo{}).Optional(), - field.Bool("toggle_network_use").Default(false), + field.String("network_use_disclosure").Optional().Nillable(), // Optional + Nillable allows distinguishing between: unset, nil, "", "disclosure description" + field.JSON("ai_use_disclosure", &util.AIUseDisclosureInfo{}).Optional(), field.Bool("toggle_explicit_content").Default(false), } } diff --git a/docker-compose.yml b/docker-compose.yml index 138e5d41..7e9c029f 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -50,7 +50,8 @@ services: - "3001:3000" tempo: - image: grafana/tempo:latest + # pinned to fix crash on startup: failed parsing config <...> field compactor not found in type app.Config + image: grafana/tempo:r236-1b7deb9 command: [ "-config.file=/etc/tempo.yaml" ] volumes: - ./tempo.yaml:/etc/tempo.yaml diff --git a/generated/README.md b/generated/README.md index 6d67e059..ef6f5018 100644 --- a/generated/README.md +++ b/generated/README.md @@ -1,7 +1,7 @@ -Do not touch any files in this directory. (except for [custom_models.go](custom_models.go)) +Do not touch any files in this directory except for [custom_models.go](custom_models.go). It is generated by running the following command in the root directory: ```shell -go generate -tags tools -x ./... -``` \ No newline at end of file +mise run generate +``` diff --git a/generated/conv/mod.go b/generated/conv/mod.go index 60c9cb2c..f391b0d0 100755 --- a/generated/conv/mod.go +++ b/generated/conv/mod.go @@ -46,7 +46,11 @@ func (c *ModImpl) Convert(source *ent.Mod) *generated.Mod { } } generatedMod.Compatibility = c.pUtilCompatibilityInfoToPGeneratedCompatibilityInfo((*source).Compatibility) - generatedMod.ToggleNetworkUse = (*source).ToggleNetworkUse + if (*source).NetworkUseDisclosure != nil { + xstring := *(*source).NetworkUseDisclosure + generatedMod.NetworkUseDisclosure = &xstring + } + generatedMod.AiUseDisclosure = c.pUtilAIUseDisclosureInfoToPGeneratedAIUseDisclosureInfo((*source).AiUseDisclosure) generatedMod.ToggleExplicitContent = (*source).ToggleExplicitContent pGeneratedMod = &generatedMod } @@ -73,12 +77,24 @@ func (c *ModImpl) pEntTagToPGeneratedTag(source *ent.Tag) *generated.Tag { } return pGeneratedTag } +func (c *ModImpl) pUtilAIUseDisclosureInfoToPGeneratedAIUseDisclosureInfo(source *util.AIUseDisclosureInfo) *generated.AIUseDisclosureInfo { + var pGeneratedAIUseDisclosureInfo *generated.AIUseDisclosureInfo + if source != nil { + var generatedAIUseDisclosureInfo generated.AIUseDisclosureInfo + generatedAIUseDisclosureInfo.DisclosureType = generated.AIUseDisclosureType((*source).DisclosureType) + pString := (*source).Message + generatedAIUseDisclosureInfo.Message = &pString + pGeneratedAIUseDisclosureInfo = &generatedAIUseDisclosureInfo + } + return pGeneratedAIUseDisclosureInfo +} func (c *ModImpl) pUtilCompatibilityInfoToPGeneratedCompatibilityInfo(source *util.CompatibilityInfo) *generated.CompatibilityInfo { var pGeneratedCompatibilityInfo *generated.CompatibilityInfo if source != nil { var generatedCompatibilityInfo generated.CompatibilityInfo generatedCompatibilityInfo.Ea = c.utilCompatibilityToPGeneratedCompatibility((*source).Ea) generatedCompatibilityInfo.Exp = c.utilCompatibilityToPGeneratedCompatibility((*source).Exp) + generatedCompatibilityInfo.Controller = c.utilCompatibilityToPGeneratedControllerCompatibility((*source).Controller) pGeneratedCompatibilityInfo = &generatedCompatibilityInfo } return pGeneratedCompatibilityInfo @@ -94,3 +110,10 @@ func (c *ModImpl) utilCompatibilityToPGeneratedCompatibility(source util.Compati generatedCompatibility.Note = &pString return &generatedCompatibility } +func (c *ModImpl) utilCompatibilityToPGeneratedControllerCompatibility(source util.Compatibility) *generated.ControllerCompatibility { + var generatedControllerCompatibility generated.ControllerCompatibility + generatedControllerCompatibility.State = generated.ControllerCompatibilityState(source.State) + pString := source.Note + generatedControllerCompatibility.Note = &pString + return &generatedControllerCompatibility +} diff --git a/generated/custom_models.go b/generated/custom_models.go index 6cd89605..99de3274 100755 --- a/generated/custom_models.go +++ b/generated/custom_models.go @@ -16,16 +16,17 @@ type NewMod struct { } type UpdateMod struct { - Name *string `json:"name" validate:"omitempty,min=3,max=32"` - ShortDescription *string `json:"short_description" validate:"omitempty,min=16,max=128"` - FullDescription *string `json:"full_description"` - Logo *graphql.Upload `json:"logo"` - SourceURL *string `json:"source_url"` - ModReference *string `json:"mod_reference"` - Hidden *bool `json:"hidden"` - Compatibility *CompatibilityInfoInput `json:"compatibility"` - Authors []UpdateUserMod `json:"authors"` - TagIDs []string `json:"tagIDs" validate:"dive,min=3,max=24"` - ToggleNetworkUse *bool `json:"toggle_network_use"` - ToggleExplicitContent *bool `json:"toggle_explicit_content"` + Name *string `json:"name" validate:"omitempty,min=3,max=32"` + ShortDescription *string `json:"short_description" validate:"omitempty,min=16,max=128"` + FullDescription *string `json:"full_description"` + Logo *graphql.Upload `json:"logo"` + SourceURL *string `json:"source_url"` + ModReference *string `json:"mod_reference"` + Hidden *bool `json:"hidden"` + Compatibility *CompatibilityInfoInput `json:"compatibility"` + Authors []UpdateUserMod `json:"authors"` + TagIDs []string `json:"tagIDs" validate:"dive,min=3,max=24"` + NetworkUseDisclosure graphql.Omittable[*string] `json:"network_use_disclosure"` + ToggleExplicitContent *bool `json:"toggle_explicit_content"` + AiUseDisclosure graphql.Omittable[*AIUseDisclosureInput] `json:"ai_use_disclosure"` } diff --git a/generated/ent/internal/schema.go b/generated/ent/internal/schema.go index 232ecbe6..e9efe602 100644 --- a/generated/ent/internal/schema.go +++ b/generated/ent/internal/schema.go @@ -6,4 +6,4 @@ // Package internal holds a loadable version of the latest schema. package internal -const Schema = "{\"Schema\":\"github.com/satisfactorymodding/smr-api/db/schema\",\"Package\":\"github.com/satisfactorymodding/smr-api/generated/ent\",\"Schemas\":[{\"name\":\"Announcement\",\"config\":{\"Table\":\"\"},\"fields\":[{\"name\":\"id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}},{\"name\":\"message\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"importance\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"deleted_at\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}]},{\"name\":\"Guide\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_id\",\"ref_name\":\"guides\",\"unique\":true,\"inverse\":true},{\"name\":\"tags\",\"type\":\"Tag\",\"through\":{\"N\":\"guide_tags\",\"T\":\"GuideTag\"}}],\"fields\":[{\"name\":\"id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}},{\"name\":\"user_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":32,\"validators\":1,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"short_description\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":128,\"validators\":1,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"guide\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"views\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":2,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"deleted_at\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}]},{\"name\":\"GuideTag\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"guide\",\"type\":\"Guide\",\"field\":\"guide_id\",\"unique\":true,\"required\":true},{\"name\":\"tag\",\"type\":\"Tag\",\"field\":\"tag_id\",\"unique\":true,\"required\":true}],\"fields\":[{\"name\":\"guide_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"tag_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}}],\"annotations\":{\"Fields\":{\"ID\":[\"guide_id\",\"tag_id\"],\"StructTag\":null}}},{\"name\":\"Mod\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"versions\",\"type\":\"Version\"},{\"name\":\"authors\",\"type\":\"User\",\"ref_name\":\"mods\",\"through\":{\"N\":\"user_mods\",\"T\":\"UserMod\"},\"inverse\":true},{\"name\":\"tags\",\"type\":\"Tag\",\"through\":{\"N\":\"mod_tags\",\"T\":\"ModTag\"}},{\"name\":\"dependents\",\"type\":\"Version\",\"ref_name\":\"dependencies\",\"through\":{\"N\":\"version_dependencies\",\"T\":\"VersionDependency\"},\"inverse\":true}],\"fields\":[{\"name\":\"id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":32,\"validators\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"short_description\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":128,\"validators\":1,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"full_description\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"logo\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"logo_thumbhash\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"source_url\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"creator_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"approved\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"views\",\"type\":{\"Type\":17,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":7,\"position\":{\"Index\":8,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"hotness\",\"type\":{\"Type\":17,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":7,\"position\":{\"Index\":9,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"popularity\",\"type\":{\"Type\":17,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":7,\"position\":{\"Index\":10,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"downloads\",\"type\":{\"Type\":17,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":7,\"position\":{\"Index\":11,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"denied\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":12,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"last_version_date\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":13,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"mod_reference\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":32,\"validators\":1,\"position\":{\"Index\":14,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"hidden\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":15,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"compatibility\",\"type\":{\"Type\":3,\"Ident\":\"*util.CompatibilityInfo\",\"PkgPath\":\"github.com/satisfactorymodding/smr-api/util\",\"PkgName\":\"util\",\"Nillable\":true,\"RType\":{\"Name\":\"CompatibilityInfo\",\"Ident\":\"util.CompatibilityInfo\",\"Kind\":22,\"PkgPath\":\"github.com/satisfactorymodding/smr-api/util\",\"Methods\":{}}},\"optional\":true,\"position\":{\"Index\":16,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"toggle_network_use\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":17,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"toggle_explicit_content\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":18,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"deleted_at\"]},{\"fields\":[\"last_version_date\"]},{\"unique\":true,\"fields\":[\"mod_reference\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}]},{\"name\":\"ModTag\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"mod\",\"type\":\"Mod\",\"field\":\"mod_id\",\"unique\":true,\"required\":true},{\"name\":\"tag\",\"type\":\"Tag\",\"field\":\"tag_id\",\"unique\":true,\"required\":true}],\"fields\":[{\"name\":\"mod_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"tag_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}}],\"annotations\":{\"Fields\":{\"ID\":[\"mod_id\",\"tag_id\"],\"StructTag\":null}}},{\"name\":\"SatisfactoryVersion\",\"config\":{\"Table\":\"\"},\"fields\":[{\"name\":\"id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"version\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"unique\":true,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"engine_version\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":16,\"default\":true,\"default_value\":\"4.26\",\"default_kind\":24,\"validators\":1,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}}]},{\"name\":\"Tag\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"mods\",\"type\":\"Mod\",\"ref_name\":\"tags\",\"through\":{\"N\":\"mod_tags\",\"T\":\"ModTag\"},\"inverse\":true},{\"name\":\"guides\",\"type\":\"Guide\",\"ref_name\":\"tags\",\"through\":{\"N\":\"guide_tags\",\"T\":\"GuideTag\"},\"inverse\":true}],\"fields\":[{\"name\":\"id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":24,\"unique\":true,\"validators\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"description\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":512,\"optional\":true,\"validators\":1,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"deleted_at\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}]},{\"name\":\"User\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"guides\",\"type\":\"Guide\"},{\"name\":\"sessions\",\"type\":\"UserSession\",\"storage_key\":{\"Table\":\"\",\"Symbols\":null,\"Columns\":[\"user_id\"]}},{\"name\":\"mods\",\"type\":\"Mod\",\"through\":{\"N\":\"user_mods\",\"T\":\"UserMod\"}},{\"name\":\"groups\",\"type\":\"UserGroup\"}],\"fields\":[{\"name\":\"id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}},{\"name\":\"email\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":256,\"validators\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"username\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":32,\"validators\":1,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"avatar\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"avatar_thumbhash\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"joined_from\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"banned\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"rank\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":1,\"default_kind\":2,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"github_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":16,\"optional\":true,\"validators\":1,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"google_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":32,\"optional\":true,\"validators\":1,\"position\":{\"Index\":8,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"facebook_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":128,\"optional\":true,\"validators\":1,\"position\":{\"Index\":9,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"deleted_at\"]},{\"unique\":true,\"fields\":[\"email\"]},{\"unique\":true,\"fields\":[\"github_id\"]},{\"unique\":true,\"fields\":[\"google_id\"]},{\"unique\":true,\"fields\":[\"facebook_id\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}]},{\"name\":\"UserGroup\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_id\",\"ref_name\":\"groups\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}},{\"name\":\"user_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":14,\"validators\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"group_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":14,\"validators\":1,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"deleted_at\"]},{\"unique\":true,\"fields\":[\"user_id\",\"group_id\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}]},{\"name\":\"UserMod\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_id\",\"unique\":true,\"required\":true},{\"name\":\"mod\",\"type\":\"Mod\",\"field\":\"mod_id\",\"unique\":true,\"required\":true}],\"fields\":[{\"name\":\"user_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"mod_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"role\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}}],\"annotations\":{\"Fields\":{\"ID\":[\"user_id\",\"mod_id\"],\"StructTag\":null}}},{\"name\":\"UserSession\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"ref_name\":\"sessions\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}},{\"name\":\"token\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":512,\"validators\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"user_agent\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"deleted_at\"]},{\"unique\":true,\"fields\":[\"token\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}]},{\"name\":\"Version\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"mod\",\"type\":\"Mod\",\"field\":\"mod_id\",\"ref_name\":\"versions\",\"unique\":true,\"inverse\":true,\"required\":true},{\"name\":\"dependencies\",\"type\":\"Mod\",\"through\":{\"N\":\"version_dependencies\",\"T\":\"VersionDependency\"}},{\"name\":\"targets\",\"type\":\"VersionTarget\"},{\"name\":\"virustotal_results\",\"type\":\"VirustotalResult\"}],\"fields\":[{\"name\":\"id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}},{\"name\":\"mod_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"version\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":16,\"validators\":1,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"game_version\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"required_on_remote\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":true,\"default_kind\":1,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"changelog\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"downloads\",\"type\":{\"Type\":17,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":7,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"key\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"stability\",\"type\":{\"Type\":6,\"Ident\":\"util.Stability\",\"PkgPath\":\"github.com/satisfactorymodding/smr-api/util\",\"PkgName\":\"util\",\"Nillable\":false,\"RType\":{\"Name\":\"Stability\",\"Ident\":\"util.Stability\",\"Kind\":24,\"PkgPath\":\"github.com/satisfactorymodding/smr-api/util\",\"Methods\":{\"Values\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"enums\":[{\"N\":\"release\",\"V\":\"release\"},{\"N\":\"beta\",\"V\":\"beta\"},{\"N\":\"alpha\",\"V\":\"alpha\"}],\"default\":true,\"default_value\":\"release\",\"default_kind\":24,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"approved\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":8,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"hotness\",\"type\":{\"Type\":17,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":7,\"position\":{\"Index\":9,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"denied\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":10,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"metadata\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":11,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"mod_reference\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":32,\"validators\":1,\"position\":{\"Index\":12,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"version_major\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":13,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"version_minor\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":14,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"version_patch\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":15,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"size\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":16,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"hash\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":64,\"optional\":true,\"validators\":2,\"position\":{\"Index\":17,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"deleted_at\"]},{\"fields\":[\"approved\"]},{\"fields\":[\"denied\"]},{\"fields\":[\"mod_id\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}]},{\"name\":\"VersionDependency\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"version\",\"type\":\"Version\",\"field\":\"version_id\",\"unique\":true,\"required\":true},{\"name\":\"mod\",\"type\":\"Mod\",\"field\":\"mod_id\",\"unique\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"version_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"mod_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"condition\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":64,\"validators\":1,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"optional\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"deleted_at\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}],\"annotations\":{\"Fields\":{\"ID\":[\"version_id\",\"mod_id\"],\"StructTag\":null}}},{\"name\":\"VersionTarget\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"version\",\"type\":\"Version\",\"field\":\"version_id\",\"ref_name\":\"targets\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"version_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"target_name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"key\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"hash\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"size\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"unique\":true,\"fields\":[\"version_id\",\"target_name\"]}]},{\"name\":\"VirustotalResult\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"version\",\"type\":\"Version\",\"field\":\"version_id\",\"ref_name\":\"virustotal_results\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"safe\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"hash\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":64,\"validators\":2,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"file_name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"validators\":1,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"version_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":14,\"validators\":2,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"safe\"]},{\"unique\":true,\"fields\":[\"hash\",\"version_id\"]},{\"fields\":[\"file_name\"]}]}],\"Features\":[\"sql/modifier\",\"intercept\",\"schema/snapshot\",\"sql/execquery\",\"sql/upsert\"]}" +const Schema = "{\"Schema\":\"github.com/satisfactorymodding/smr-api/db/schema\",\"Package\":\"github.com/satisfactorymodding/smr-api/generated/ent\",\"Schemas\":[{\"name\":\"Announcement\",\"config\":{\"Table\":\"\"},\"fields\":[{\"name\":\"id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}},{\"name\":\"message\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"importance\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"deleted_at\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}]},{\"name\":\"Guide\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_id\",\"ref_name\":\"guides\",\"unique\":true,\"inverse\":true},{\"name\":\"tags\",\"type\":\"Tag\",\"through\":{\"N\":\"guide_tags\",\"T\":\"GuideTag\"}}],\"fields\":[{\"name\":\"id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}},{\"name\":\"user_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":32,\"validators\":1,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"short_description\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":128,\"validators\":1,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"guide\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"views\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":2,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"deleted_at\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}]},{\"name\":\"GuideTag\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"guide\",\"type\":\"Guide\",\"field\":\"guide_id\",\"unique\":true,\"required\":true},{\"name\":\"tag\",\"type\":\"Tag\",\"field\":\"tag_id\",\"unique\":true,\"required\":true}],\"fields\":[{\"name\":\"guide_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"tag_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}}],\"annotations\":{\"Fields\":{\"ID\":[\"guide_id\",\"tag_id\"],\"StructTag\":null}}},{\"name\":\"Mod\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"versions\",\"type\":\"Version\"},{\"name\":\"authors\",\"type\":\"User\",\"ref_name\":\"mods\",\"through\":{\"N\":\"user_mods\",\"T\":\"UserMod\"},\"inverse\":true},{\"name\":\"tags\",\"type\":\"Tag\",\"through\":{\"N\":\"mod_tags\",\"T\":\"ModTag\"}},{\"name\":\"dependents\",\"type\":\"Version\",\"ref_name\":\"dependencies\",\"through\":{\"N\":\"version_dependencies\",\"T\":\"VersionDependency\"},\"inverse\":true}],\"fields\":[{\"name\":\"id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":32,\"validators\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"short_description\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":128,\"validators\":1,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"full_description\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"logo\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"logo_thumbhash\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"source_url\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"creator_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"approved\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"views\",\"type\":{\"Type\":17,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":7,\"position\":{\"Index\":8,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"hotness\",\"type\":{\"Type\":17,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":7,\"position\":{\"Index\":9,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"popularity\",\"type\":{\"Type\":17,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":7,\"position\":{\"Index\":10,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"downloads\",\"type\":{\"Type\":17,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":7,\"position\":{\"Index\":11,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"denied\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":12,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"last_version_date\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":13,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"mod_reference\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":32,\"validators\":1,\"position\":{\"Index\":14,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"hidden\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":15,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"compatibility\",\"type\":{\"Type\":3,\"Ident\":\"*util.CompatibilityInfo\",\"PkgPath\":\"github.com/satisfactorymodding/smr-api/util\",\"PkgName\":\"util\",\"Nillable\":true,\"RType\":{\"Name\":\"CompatibilityInfo\",\"Ident\":\"util.CompatibilityInfo\",\"Kind\":22,\"PkgPath\":\"github.com/satisfactorymodding/smr-api/util\",\"Methods\":{}}},\"optional\":true,\"position\":{\"Index\":16,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"network_use_disclosure\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":17,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"ai_use_disclosure\",\"type\":{\"Type\":3,\"Ident\":\"*util.AIUseDisclosureInfo\",\"PkgPath\":\"github.com/satisfactorymodding/smr-api/util\",\"PkgName\":\"util\",\"Nillable\":true,\"RType\":{\"Name\":\"AIUseDisclosureInfo\",\"Ident\":\"util.AIUseDisclosureInfo\",\"Kind\":22,\"PkgPath\":\"github.com/satisfactorymodding/smr-api/util\",\"Methods\":{}}},\"optional\":true,\"position\":{\"Index\":18,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"toggle_explicit_content\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":19,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"deleted_at\"]},{\"fields\":[\"last_version_date\"]},{\"unique\":true,\"fields\":[\"mod_reference\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}]},{\"name\":\"ModTag\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"mod\",\"type\":\"Mod\",\"field\":\"mod_id\",\"unique\":true,\"required\":true},{\"name\":\"tag\",\"type\":\"Tag\",\"field\":\"tag_id\",\"unique\":true,\"required\":true}],\"fields\":[{\"name\":\"mod_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"tag_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}}],\"annotations\":{\"Fields\":{\"ID\":[\"mod_id\",\"tag_id\"],\"StructTag\":null}}},{\"name\":\"SatisfactoryVersion\",\"config\":{\"Table\":\"\"},\"fields\":[{\"name\":\"id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"version\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"unique\":true,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"engine_version\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":16,\"default\":true,\"default_value\":\"4.26\",\"default_kind\":24,\"validators\":1,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}}]},{\"name\":\"Tag\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"mods\",\"type\":\"Mod\",\"ref_name\":\"tags\",\"through\":{\"N\":\"mod_tags\",\"T\":\"ModTag\"},\"inverse\":true},{\"name\":\"guides\",\"type\":\"Guide\",\"ref_name\":\"tags\",\"through\":{\"N\":\"guide_tags\",\"T\":\"GuideTag\"},\"inverse\":true}],\"fields\":[{\"name\":\"id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":24,\"unique\":true,\"validators\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"description\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":512,\"optional\":true,\"validators\":1,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"deleted_at\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}]},{\"name\":\"User\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"guides\",\"type\":\"Guide\"},{\"name\":\"sessions\",\"type\":\"UserSession\",\"storage_key\":{\"Table\":\"\",\"Symbols\":null,\"Columns\":[\"user_id\"]}},{\"name\":\"mods\",\"type\":\"Mod\",\"through\":{\"N\":\"user_mods\",\"T\":\"UserMod\"}},{\"name\":\"groups\",\"type\":\"UserGroup\"}],\"fields\":[{\"name\":\"id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}},{\"name\":\"email\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":256,\"validators\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"username\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":32,\"validators\":1,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"avatar\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"avatar_thumbhash\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"joined_from\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"banned\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"rank\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":1,\"default_kind\":2,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"github_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":16,\"optional\":true,\"validators\":1,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"google_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":32,\"optional\":true,\"validators\":1,\"position\":{\"Index\":8,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"facebook_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":128,\"optional\":true,\"validators\":1,\"position\":{\"Index\":9,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"deleted_at\"]},{\"unique\":true,\"fields\":[\"email\"]},{\"unique\":true,\"fields\":[\"github_id\"]},{\"unique\":true,\"fields\":[\"google_id\"]},{\"unique\":true,\"fields\":[\"facebook_id\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}]},{\"name\":\"UserGroup\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_id\",\"ref_name\":\"groups\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}},{\"name\":\"user_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":14,\"validators\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"group_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":14,\"validators\":1,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"deleted_at\"]},{\"unique\":true,\"fields\":[\"user_id\",\"group_id\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}]},{\"name\":\"UserMod\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_id\",\"unique\":true,\"required\":true},{\"name\":\"mod\",\"type\":\"Mod\",\"field\":\"mod_id\",\"unique\":true,\"required\":true}],\"fields\":[{\"name\":\"user_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"mod_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"role\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}}],\"annotations\":{\"Fields\":{\"ID\":[\"user_id\",\"mod_id\"],\"StructTag\":null}}},{\"name\":\"UserSession\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"ref_name\":\"sessions\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}},{\"name\":\"token\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":512,\"validators\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"user_agent\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"deleted_at\"]},{\"unique\":true,\"fields\":[\"token\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}]},{\"name\":\"Version\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"mod\",\"type\":\"Mod\",\"field\":\"mod_id\",\"ref_name\":\"versions\",\"unique\":true,\"inverse\":true,\"required\":true},{\"name\":\"dependencies\",\"type\":\"Mod\",\"through\":{\"N\":\"version_dependencies\",\"T\":\"VersionDependency\"}},{\"name\":\"targets\",\"type\":\"VersionTarget\"},{\"name\":\"virustotal_results\",\"type\":\"VirustotalResult\"}],\"fields\":[{\"name\":\"id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}},{\"name\":\"mod_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"version\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":16,\"validators\":1,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"game_version\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"required_on_remote\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":true,\"default_kind\":1,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"changelog\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"downloads\",\"type\":{\"Type\":17,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":7,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"key\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"stability\",\"type\":{\"Type\":6,\"Ident\":\"util.Stability\",\"PkgPath\":\"github.com/satisfactorymodding/smr-api/util\",\"PkgName\":\"util\",\"Nillable\":false,\"RType\":{\"Name\":\"Stability\",\"Ident\":\"util.Stability\",\"Kind\":24,\"PkgPath\":\"github.com/satisfactorymodding/smr-api/util\",\"Methods\":{\"Values\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"enums\":[{\"N\":\"release\",\"V\":\"release\"},{\"N\":\"beta\",\"V\":\"beta\"},{\"N\":\"alpha\",\"V\":\"alpha\"}],\"default\":true,\"default_value\":\"release\",\"default_kind\":24,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"approved\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":8,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"hotness\",\"type\":{\"Type\":17,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":7,\"position\":{\"Index\":9,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"denied\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":10,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"metadata\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":11,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"mod_reference\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":32,\"validators\":1,\"position\":{\"Index\":12,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"version_major\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":13,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"version_minor\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":14,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"version_patch\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":15,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"size\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":16,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"hash\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":64,\"optional\":true,\"validators\":2,\"position\":{\"Index\":17,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"deleted_at\"]},{\"fields\":[\"approved\"]},{\"fields\":[\"denied\"]},{\"fields\":[\"mod_id\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":2}]},{\"name\":\"VersionDependency\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"version\",\"type\":\"Version\",\"field\":\"version_id\",\"unique\":true,\"required\":true},{\"name\":\"mod\",\"type\":\"Mod\",\"field\":\"mod_id\",\"unique\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"version_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"mod_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"condition\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":64,\"validators\":1,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"optional\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"deleted_at\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}],\"annotations\":{\"Fields\":{\"ID\":[\"version_id\",\"mod_id\"],\"StructTag\":null}}},{\"name\":\"VersionTarget\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"version\",\"type\":\"Version\",\"field\":\"version_id\",\"ref_name\":\"targets\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"version_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"target_name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"key\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"hash\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"size\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"unique\":true,\"fields\":[\"version_id\",\"target_name\"]}]},{\"name\":\"VirustotalResult\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"version\",\"type\":\"Version\",\"field\":\"version_id\",\"ref_name\":\"virustotal_results\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"safe\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"hash\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":64,\"validators\":2,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"file_name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"validators\":1,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"version_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":14,\"validators\":2,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"safe\"]},{\"unique\":true,\"fields\":[\"hash\",\"version_id\"]},{\"fields\":[\"file_name\"]}]}],\"Features\":[\"sql/modifier\",\"intercept\",\"schema/snapshot\",\"sql/execquery\",\"sql/upsert\"]}" diff --git a/generated/ent/migrate/schema.go b/generated/ent/migrate/schema.go index f84c046d..1f28f29a 100644 --- a/generated/ent/migrate/schema.go +++ b/generated/ent/migrate/schema.go @@ -111,7 +111,8 @@ var ( {Name: "mod_reference", Type: field.TypeString, Size: 32}, {Name: "hidden", Type: field.TypeBool, Default: false}, {Name: "compatibility", Type: field.TypeJSON, Nullable: true}, - {Name: "toggle_network_use", Type: field.TypeBool, Default: false}, + {Name: "network_use_disclosure", Type: field.TypeString, Nullable: true}, + {Name: "ai_use_disclosure", Type: field.TypeJSON, Nullable: true}, {Name: "toggle_explicit_content", Type: field.TypeBool, Default: false}, } // ModsTable holds the schema information for the "mods" table. diff --git a/generated/ent/mod.go b/generated/ent/mod.go index 79ae3375..907a1951 100644 --- a/generated/ent/mod.go +++ b/generated/ent/mod.go @@ -59,8 +59,10 @@ type Mod struct { Hidden bool `json:"hidden,omitempty"` // Compatibility holds the value of the "compatibility" field. Compatibility *util.CompatibilityInfo `json:"compatibility,omitempty"` - // ToggleNetworkUse holds the value of the "toggle_network_use" field. - ToggleNetworkUse bool `json:"toggle_network_use,omitempty"` + // NetworkUseDisclosure holds the value of the "network_use_disclosure" field. + NetworkUseDisclosure *string `json:"network_use_disclosure,omitempty"` + // AiUseDisclosure holds the value of the "ai_use_disclosure" field. + AiUseDisclosure *util.AIUseDisclosureInfo `json:"ai_use_disclosure,omitempty"` // ToggleExplicitContent holds the value of the "toggle_explicit_content" field. ToggleExplicitContent bool `json:"toggle_explicit_content,omitempty"` // Edges holds the relations/edges for other nodes in the graph. @@ -158,13 +160,13 @@ func (*Mod) scanValues(columns []string) ([]any, error) { values := make([]any, len(columns)) for i := range columns { switch columns[i] { - case mod.FieldCompatibility: + case mod.FieldCompatibility, mod.FieldAiUseDisclosure: values[i] = new([]byte) - case mod.FieldApproved, mod.FieldDenied, mod.FieldHidden, mod.FieldToggleNetworkUse, mod.FieldToggleExplicitContent: + case mod.FieldApproved, mod.FieldDenied, mod.FieldHidden, mod.FieldToggleExplicitContent: values[i] = new(sql.NullBool) case mod.FieldViews, mod.FieldHotness, mod.FieldPopularity, mod.FieldDownloads: values[i] = new(sql.NullInt64) - case mod.FieldID, mod.FieldName, mod.FieldShortDescription, mod.FieldFullDescription, mod.FieldLogo, mod.FieldLogoThumbhash, mod.FieldSourceURL, mod.FieldCreatorID, mod.FieldModReference: + case mod.FieldID, mod.FieldName, mod.FieldShortDescription, mod.FieldFullDescription, mod.FieldLogo, mod.FieldLogoThumbhash, mod.FieldSourceURL, mod.FieldCreatorID, mod.FieldModReference, mod.FieldNetworkUseDisclosure: values[i] = new(sql.NullString) case mod.FieldCreatedAt, mod.FieldUpdatedAt, mod.FieldDeletedAt, mod.FieldLastVersionDate: values[i] = new(sql.NullTime) @@ -311,11 +313,20 @@ func (m *Mod) assignValues(columns []string, values []any) error { return fmt.Errorf("unmarshal field compatibility: %w", err) } } - case mod.FieldToggleNetworkUse: - if value, ok := values[i].(*sql.NullBool); !ok { - return fmt.Errorf("unexpected type %T for field toggle_network_use", values[i]) + case mod.FieldNetworkUseDisclosure: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field network_use_disclosure", values[i]) } else if value.Valid { - m.ToggleNetworkUse = value.Bool + m.NetworkUseDisclosure = new(string) + *m.NetworkUseDisclosure = value.String + } + case mod.FieldAiUseDisclosure: + if value, ok := values[i].(*[]byte); !ok { + return fmt.Errorf("unexpected type %T for field ai_use_disclosure", values[i]) + } else if value != nil && len(*value) > 0 { + if err := json.Unmarshal(*value, &m.AiUseDisclosure); err != nil { + return fmt.Errorf("unmarshal field ai_use_disclosure: %w", err) + } } case mod.FieldToggleExplicitContent: if value, ok := values[i].(*sql.NullBool); !ok { @@ -454,8 +465,13 @@ func (m *Mod) String() string { builder.WriteString("compatibility=") builder.WriteString(fmt.Sprintf("%v", m.Compatibility)) builder.WriteString(", ") - builder.WriteString("toggle_network_use=") - builder.WriteString(fmt.Sprintf("%v", m.ToggleNetworkUse)) + if v := m.NetworkUseDisclosure; v != nil { + builder.WriteString("network_use_disclosure=") + builder.WriteString(*v) + } + builder.WriteString(", ") + builder.WriteString("ai_use_disclosure=") + builder.WriteString(fmt.Sprintf("%v", m.AiUseDisclosure)) builder.WriteString(", ") builder.WriteString("toggle_explicit_content=") builder.WriteString(fmt.Sprintf("%v", m.ToggleExplicitContent)) diff --git a/generated/ent/mod/mod.go b/generated/ent/mod/mod.go index 7d6572df..8914edaf 100644 --- a/generated/ent/mod/mod.go +++ b/generated/ent/mod/mod.go @@ -55,8 +55,10 @@ const ( FieldHidden = "hidden" // FieldCompatibility holds the string denoting the compatibility field in the database. FieldCompatibility = "compatibility" - // FieldToggleNetworkUse holds the string denoting the toggle_network_use field in the database. - FieldToggleNetworkUse = "toggle_network_use" + // FieldNetworkUseDisclosure holds the string denoting the network_use_disclosure field in the database. + FieldNetworkUseDisclosure = "network_use_disclosure" + // FieldAiUseDisclosure holds the string denoting the ai_use_disclosure field in the database. + FieldAiUseDisclosure = "ai_use_disclosure" // FieldToggleExplicitContent holds the string denoting the toggle_explicit_content field in the database. FieldToggleExplicitContent = "toggle_explicit_content" // EdgeVersions holds the string denoting the versions edge name in mutations. @@ -143,7 +145,8 @@ var Columns = []string{ FieldModReference, FieldHidden, FieldCompatibility, - FieldToggleNetworkUse, + FieldNetworkUseDisclosure, + FieldAiUseDisclosure, FieldToggleExplicitContent, } @@ -203,8 +206,6 @@ var ( ModReferenceValidator func(string) error // DefaultHidden holds the default value on creation for the "hidden" field. DefaultHidden bool - // DefaultToggleNetworkUse holds the default value on creation for the "toggle_network_use" field. - DefaultToggleNetworkUse bool // DefaultToggleExplicitContent holds the default value on creation for the "toggle_explicit_content" field. DefaultToggleExplicitContent bool // DefaultID holds the default value on creation for the "id" field. @@ -314,9 +315,9 @@ func ByHidden(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldHidden, opts...).ToFunc() } -// ByToggleNetworkUse orders the results by the toggle_network_use field. -func ByToggleNetworkUse(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldToggleNetworkUse, opts...).ToFunc() +// ByNetworkUseDisclosure orders the results by the network_use_disclosure field. +func ByNetworkUseDisclosure(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldNetworkUseDisclosure, opts...).ToFunc() } // ByToggleExplicitContent orders the results by the toggle_explicit_content field. diff --git a/generated/ent/mod/where.go b/generated/ent/mod/where.go index e5bd0dfa..7dcd271c 100644 --- a/generated/ent/mod/where.go +++ b/generated/ent/mod/where.go @@ -160,9 +160,9 @@ func Hidden(v bool) predicate.Mod { return predicate.Mod(sql.FieldEQ(FieldHidden, v)) } -// ToggleNetworkUse applies equality check predicate on the "toggle_network_use" field. It's identical to ToggleNetworkUseEQ. -func ToggleNetworkUse(v bool) predicate.Mod { - return predicate.Mod(sql.FieldEQ(FieldToggleNetworkUse, v)) +// NetworkUseDisclosure applies equality check predicate on the "network_use_disclosure" field. It's identical to NetworkUseDisclosureEQ. +func NetworkUseDisclosure(v string) predicate.Mod { + return predicate.Mod(sql.FieldEQ(FieldNetworkUseDisclosure, v)) } // ToggleExplicitContent applies equality check predicate on the "toggle_explicit_content" field. It's identical to ToggleExplicitContentEQ. @@ -1100,14 +1100,89 @@ func CompatibilityNotNil() predicate.Mod { return predicate.Mod(sql.FieldNotNull(FieldCompatibility)) } -// ToggleNetworkUseEQ applies the EQ predicate on the "toggle_network_use" field. -func ToggleNetworkUseEQ(v bool) predicate.Mod { - return predicate.Mod(sql.FieldEQ(FieldToggleNetworkUse, v)) +// NetworkUseDisclosureEQ applies the EQ predicate on the "network_use_disclosure" field. +func NetworkUseDisclosureEQ(v string) predicate.Mod { + return predicate.Mod(sql.FieldEQ(FieldNetworkUseDisclosure, v)) } -// ToggleNetworkUseNEQ applies the NEQ predicate on the "toggle_network_use" field. -func ToggleNetworkUseNEQ(v bool) predicate.Mod { - return predicate.Mod(sql.FieldNEQ(FieldToggleNetworkUse, v)) +// NetworkUseDisclosureNEQ applies the NEQ predicate on the "network_use_disclosure" field. +func NetworkUseDisclosureNEQ(v string) predicate.Mod { + return predicate.Mod(sql.FieldNEQ(FieldNetworkUseDisclosure, v)) +} + +// NetworkUseDisclosureIn applies the In predicate on the "network_use_disclosure" field. +func NetworkUseDisclosureIn(vs ...string) predicate.Mod { + return predicate.Mod(sql.FieldIn(FieldNetworkUseDisclosure, vs...)) +} + +// NetworkUseDisclosureNotIn applies the NotIn predicate on the "network_use_disclosure" field. +func NetworkUseDisclosureNotIn(vs ...string) predicate.Mod { + return predicate.Mod(sql.FieldNotIn(FieldNetworkUseDisclosure, vs...)) +} + +// NetworkUseDisclosureGT applies the GT predicate on the "network_use_disclosure" field. +func NetworkUseDisclosureGT(v string) predicate.Mod { + return predicate.Mod(sql.FieldGT(FieldNetworkUseDisclosure, v)) +} + +// NetworkUseDisclosureGTE applies the GTE predicate on the "network_use_disclosure" field. +func NetworkUseDisclosureGTE(v string) predicate.Mod { + return predicate.Mod(sql.FieldGTE(FieldNetworkUseDisclosure, v)) +} + +// NetworkUseDisclosureLT applies the LT predicate on the "network_use_disclosure" field. +func NetworkUseDisclosureLT(v string) predicate.Mod { + return predicate.Mod(sql.FieldLT(FieldNetworkUseDisclosure, v)) +} + +// NetworkUseDisclosureLTE applies the LTE predicate on the "network_use_disclosure" field. +func NetworkUseDisclosureLTE(v string) predicate.Mod { + return predicate.Mod(sql.FieldLTE(FieldNetworkUseDisclosure, v)) +} + +// NetworkUseDisclosureContains applies the Contains predicate on the "network_use_disclosure" field. +func NetworkUseDisclosureContains(v string) predicate.Mod { + return predicate.Mod(sql.FieldContains(FieldNetworkUseDisclosure, v)) +} + +// NetworkUseDisclosureHasPrefix applies the HasPrefix predicate on the "network_use_disclosure" field. +func NetworkUseDisclosureHasPrefix(v string) predicate.Mod { + return predicate.Mod(sql.FieldHasPrefix(FieldNetworkUseDisclosure, v)) +} + +// NetworkUseDisclosureHasSuffix applies the HasSuffix predicate on the "network_use_disclosure" field. +func NetworkUseDisclosureHasSuffix(v string) predicate.Mod { + return predicate.Mod(sql.FieldHasSuffix(FieldNetworkUseDisclosure, v)) +} + +// NetworkUseDisclosureIsNil applies the IsNil predicate on the "network_use_disclosure" field. +func NetworkUseDisclosureIsNil() predicate.Mod { + return predicate.Mod(sql.FieldIsNull(FieldNetworkUseDisclosure)) +} + +// NetworkUseDisclosureNotNil applies the NotNil predicate on the "network_use_disclosure" field. +func NetworkUseDisclosureNotNil() predicate.Mod { + return predicate.Mod(sql.FieldNotNull(FieldNetworkUseDisclosure)) +} + +// NetworkUseDisclosureEqualFold applies the EqualFold predicate on the "network_use_disclosure" field. +func NetworkUseDisclosureEqualFold(v string) predicate.Mod { + return predicate.Mod(sql.FieldEqualFold(FieldNetworkUseDisclosure, v)) +} + +// NetworkUseDisclosureContainsFold applies the ContainsFold predicate on the "network_use_disclosure" field. +func NetworkUseDisclosureContainsFold(v string) predicate.Mod { + return predicate.Mod(sql.FieldContainsFold(FieldNetworkUseDisclosure, v)) +} + +// AiUseDisclosureIsNil applies the IsNil predicate on the "ai_use_disclosure" field. +func AiUseDisclosureIsNil() predicate.Mod { + return predicate.Mod(sql.FieldIsNull(FieldAiUseDisclosure)) +} + +// AiUseDisclosureNotNil applies the NotNil predicate on the "ai_use_disclosure" field. +func AiUseDisclosureNotNil() predicate.Mod { + return predicate.Mod(sql.FieldNotNull(FieldAiUseDisclosure)) } // ToggleExplicitContentEQ applies the EQ predicate on the "toggle_explicit_content" field. diff --git a/generated/ent/mod_create.go b/generated/ent/mod_create.go index 1ad9c12f..85b4b9aa 100644 --- a/generated/ent/mod_create.go +++ b/generated/ent/mod_create.go @@ -259,20 +259,26 @@ func (mc *ModCreate) SetCompatibility(ui *util.CompatibilityInfo) *ModCreate { return mc } -// SetToggleNetworkUse sets the "toggle_network_use" field. -func (mc *ModCreate) SetToggleNetworkUse(b bool) *ModCreate { - mc.mutation.SetToggleNetworkUse(b) +// SetNetworkUseDisclosure sets the "network_use_disclosure" field. +func (mc *ModCreate) SetNetworkUseDisclosure(s string) *ModCreate { + mc.mutation.SetNetworkUseDisclosure(s) return mc } -// SetNillableToggleNetworkUse sets the "toggle_network_use" field if the given value is not nil. -func (mc *ModCreate) SetNillableToggleNetworkUse(b *bool) *ModCreate { - if b != nil { - mc.SetToggleNetworkUse(*b) +// SetNillableNetworkUseDisclosure sets the "network_use_disclosure" field if the given value is not nil. +func (mc *ModCreate) SetNillableNetworkUseDisclosure(s *string) *ModCreate { + if s != nil { + mc.SetNetworkUseDisclosure(*s) } return mc } +// SetAiUseDisclosure sets the "ai_use_disclosure" field. +func (mc *ModCreate) SetAiUseDisclosure(uudi *util.AIUseDisclosureInfo) *ModCreate { + mc.mutation.SetAiUseDisclosure(uudi) + return mc +} + // SetToggleExplicitContent sets the "toggle_explicit_content" field. func (mc *ModCreate) SetToggleExplicitContent(b bool) *ModCreate { mc.mutation.SetToggleExplicitContent(b) @@ -440,10 +446,6 @@ func (mc *ModCreate) defaults() error { v := mod.DefaultHidden mc.mutation.SetHidden(v) } - if _, ok := mc.mutation.ToggleNetworkUse(); !ok { - v := mod.DefaultToggleNetworkUse - mc.mutation.SetToggleNetworkUse(v) - } if _, ok := mc.mutation.ToggleExplicitContent(); !ok { v := mod.DefaultToggleExplicitContent mc.mutation.SetToggleExplicitContent(v) @@ -517,9 +519,6 @@ func (mc *ModCreate) check() error { if _, ok := mc.mutation.Hidden(); !ok { return &ValidationError{Name: "hidden", err: errors.New(`ent: missing required field "Mod.hidden"`)} } - if _, ok := mc.mutation.ToggleNetworkUse(); !ok { - return &ValidationError{Name: "toggle_network_use", err: errors.New(`ent: missing required field "Mod.toggle_network_use"`)} - } if _, ok := mc.mutation.ToggleExplicitContent(); !ok { return &ValidationError{Name: "toggle_explicit_content", err: errors.New(`ent: missing required field "Mod.toggle_explicit_content"`)} } @@ -639,9 +638,13 @@ func (mc *ModCreate) createSpec() (*Mod, *sqlgraph.CreateSpec) { _spec.SetField(mod.FieldCompatibility, field.TypeJSON, value) _node.Compatibility = value } - if value, ok := mc.mutation.ToggleNetworkUse(); ok { - _spec.SetField(mod.FieldToggleNetworkUse, field.TypeBool, value) - _node.ToggleNetworkUse = value + if value, ok := mc.mutation.NetworkUseDisclosure(); ok { + _spec.SetField(mod.FieldNetworkUseDisclosure, field.TypeString, value) + _node.NetworkUseDisclosure = &value + } + if value, ok := mc.mutation.AiUseDisclosure(); ok { + _spec.SetField(mod.FieldAiUseDisclosure, field.TypeJSON, value) + _node.AiUseDisclosure = value } if value, ok := mc.mutation.ToggleExplicitContent(); ok { _spec.SetField(mod.FieldToggleExplicitContent, field.TypeBool, value) @@ -1055,15 +1058,39 @@ func (u *ModUpsert) ClearCompatibility() *ModUpsert { return u } -// SetToggleNetworkUse sets the "toggle_network_use" field. -func (u *ModUpsert) SetToggleNetworkUse(v bool) *ModUpsert { - u.Set(mod.FieldToggleNetworkUse, v) +// SetNetworkUseDisclosure sets the "network_use_disclosure" field. +func (u *ModUpsert) SetNetworkUseDisclosure(v string) *ModUpsert { + u.Set(mod.FieldNetworkUseDisclosure, v) + return u +} + +// UpdateNetworkUseDisclosure sets the "network_use_disclosure" field to the value that was provided on create. +func (u *ModUpsert) UpdateNetworkUseDisclosure() *ModUpsert { + u.SetExcluded(mod.FieldNetworkUseDisclosure) + return u +} + +// ClearNetworkUseDisclosure clears the value of the "network_use_disclosure" field. +func (u *ModUpsert) ClearNetworkUseDisclosure() *ModUpsert { + u.SetNull(mod.FieldNetworkUseDisclosure) + return u +} + +// SetAiUseDisclosure sets the "ai_use_disclosure" field. +func (u *ModUpsert) SetAiUseDisclosure(v *util.AIUseDisclosureInfo) *ModUpsert { + u.Set(mod.FieldAiUseDisclosure, v) + return u +} + +// UpdateAiUseDisclosure sets the "ai_use_disclosure" field to the value that was provided on create. +func (u *ModUpsert) UpdateAiUseDisclosure() *ModUpsert { + u.SetExcluded(mod.FieldAiUseDisclosure) return u } -// UpdateToggleNetworkUse sets the "toggle_network_use" field to the value that was provided on create. -func (u *ModUpsert) UpdateToggleNetworkUse() *ModUpsert { - u.SetExcluded(mod.FieldToggleNetworkUse) +// ClearAiUseDisclosure clears the value of the "ai_use_disclosure" field. +func (u *ModUpsert) ClearAiUseDisclosure() *ModUpsert { + u.SetNull(mod.FieldAiUseDisclosure) return u } @@ -1466,17 +1493,45 @@ func (u *ModUpsertOne) ClearCompatibility() *ModUpsertOne { }) } -// SetToggleNetworkUse sets the "toggle_network_use" field. -func (u *ModUpsertOne) SetToggleNetworkUse(v bool) *ModUpsertOne { +// SetNetworkUseDisclosure sets the "network_use_disclosure" field. +func (u *ModUpsertOne) SetNetworkUseDisclosure(v string) *ModUpsertOne { + return u.Update(func(s *ModUpsert) { + s.SetNetworkUseDisclosure(v) + }) +} + +// UpdateNetworkUseDisclosure sets the "network_use_disclosure" field to the value that was provided on create. +func (u *ModUpsertOne) UpdateNetworkUseDisclosure() *ModUpsertOne { + return u.Update(func(s *ModUpsert) { + s.UpdateNetworkUseDisclosure() + }) +} + +// ClearNetworkUseDisclosure clears the value of the "network_use_disclosure" field. +func (u *ModUpsertOne) ClearNetworkUseDisclosure() *ModUpsertOne { return u.Update(func(s *ModUpsert) { - s.SetToggleNetworkUse(v) + s.ClearNetworkUseDisclosure() }) } -// UpdateToggleNetworkUse sets the "toggle_network_use" field to the value that was provided on create. -func (u *ModUpsertOne) UpdateToggleNetworkUse() *ModUpsertOne { +// SetAiUseDisclosure sets the "ai_use_disclosure" field. +func (u *ModUpsertOne) SetAiUseDisclosure(v *util.AIUseDisclosureInfo) *ModUpsertOne { return u.Update(func(s *ModUpsert) { - s.UpdateToggleNetworkUse() + s.SetAiUseDisclosure(v) + }) +} + +// UpdateAiUseDisclosure sets the "ai_use_disclosure" field to the value that was provided on create. +func (u *ModUpsertOne) UpdateAiUseDisclosure() *ModUpsertOne { + return u.Update(func(s *ModUpsert) { + s.UpdateAiUseDisclosure() + }) +} + +// ClearAiUseDisclosure clears the value of the "ai_use_disclosure" field. +func (u *ModUpsertOne) ClearAiUseDisclosure() *ModUpsertOne { + return u.Update(func(s *ModUpsert) { + s.ClearAiUseDisclosure() }) } @@ -2048,17 +2103,45 @@ func (u *ModUpsertBulk) ClearCompatibility() *ModUpsertBulk { }) } -// SetToggleNetworkUse sets the "toggle_network_use" field. -func (u *ModUpsertBulk) SetToggleNetworkUse(v bool) *ModUpsertBulk { +// SetNetworkUseDisclosure sets the "network_use_disclosure" field. +func (u *ModUpsertBulk) SetNetworkUseDisclosure(v string) *ModUpsertBulk { + return u.Update(func(s *ModUpsert) { + s.SetNetworkUseDisclosure(v) + }) +} + +// UpdateNetworkUseDisclosure sets the "network_use_disclosure" field to the value that was provided on create. +func (u *ModUpsertBulk) UpdateNetworkUseDisclosure() *ModUpsertBulk { + return u.Update(func(s *ModUpsert) { + s.UpdateNetworkUseDisclosure() + }) +} + +// ClearNetworkUseDisclosure clears the value of the "network_use_disclosure" field. +func (u *ModUpsertBulk) ClearNetworkUseDisclosure() *ModUpsertBulk { + return u.Update(func(s *ModUpsert) { + s.ClearNetworkUseDisclosure() + }) +} + +// SetAiUseDisclosure sets the "ai_use_disclosure" field. +func (u *ModUpsertBulk) SetAiUseDisclosure(v *util.AIUseDisclosureInfo) *ModUpsertBulk { + return u.Update(func(s *ModUpsert) { + s.SetAiUseDisclosure(v) + }) +} + +// UpdateAiUseDisclosure sets the "ai_use_disclosure" field to the value that was provided on create. +func (u *ModUpsertBulk) UpdateAiUseDisclosure() *ModUpsertBulk { return u.Update(func(s *ModUpsert) { - s.SetToggleNetworkUse(v) + s.UpdateAiUseDisclosure() }) } -// UpdateToggleNetworkUse sets the "toggle_network_use" field to the value that was provided on create. -func (u *ModUpsertBulk) UpdateToggleNetworkUse() *ModUpsertBulk { +// ClearAiUseDisclosure clears the value of the "ai_use_disclosure" field. +func (u *ModUpsertBulk) ClearAiUseDisclosure() *ModUpsertBulk { return u.Update(func(s *ModUpsert) { - s.UpdateToggleNetworkUse() + s.ClearAiUseDisclosure() }) } diff --git a/generated/ent/mod_update.go b/generated/ent/mod_update.go index a69d4149..5a38b521 100644 --- a/generated/ent/mod_update.go +++ b/generated/ent/mod_update.go @@ -347,20 +347,38 @@ func (mu *ModUpdate) ClearCompatibility() *ModUpdate { return mu } -// SetToggleNetworkUse sets the "toggle_network_use" field. -func (mu *ModUpdate) SetToggleNetworkUse(b bool) *ModUpdate { - mu.mutation.SetToggleNetworkUse(b) +// SetNetworkUseDisclosure sets the "network_use_disclosure" field. +func (mu *ModUpdate) SetNetworkUseDisclosure(s string) *ModUpdate { + mu.mutation.SetNetworkUseDisclosure(s) return mu } -// SetNillableToggleNetworkUse sets the "toggle_network_use" field if the given value is not nil. -func (mu *ModUpdate) SetNillableToggleNetworkUse(b *bool) *ModUpdate { - if b != nil { - mu.SetToggleNetworkUse(*b) +// SetNillableNetworkUseDisclosure sets the "network_use_disclosure" field if the given value is not nil. +func (mu *ModUpdate) SetNillableNetworkUseDisclosure(s *string) *ModUpdate { + if s != nil { + mu.SetNetworkUseDisclosure(*s) } return mu } +// ClearNetworkUseDisclosure clears the value of the "network_use_disclosure" field. +func (mu *ModUpdate) ClearNetworkUseDisclosure() *ModUpdate { + mu.mutation.ClearNetworkUseDisclosure() + return mu +} + +// SetAiUseDisclosure sets the "ai_use_disclosure" field. +func (mu *ModUpdate) SetAiUseDisclosure(uudi *util.AIUseDisclosureInfo) *ModUpdate { + mu.mutation.SetAiUseDisclosure(uudi) + return mu +} + +// ClearAiUseDisclosure clears the value of the "ai_use_disclosure" field. +func (mu *ModUpdate) ClearAiUseDisclosure() *ModUpdate { + mu.mutation.ClearAiUseDisclosure() + return mu +} + // SetToggleExplicitContent sets the "toggle_explicit_content" field. func (mu *ModUpdate) SetToggleExplicitContent(b bool) *ModUpdate { mu.mutation.SetToggleExplicitContent(b) @@ -691,8 +709,17 @@ func (mu *ModUpdate) sqlSave(ctx context.Context) (n int, err error) { if mu.mutation.CompatibilityCleared() { _spec.ClearField(mod.FieldCompatibility, field.TypeJSON) } - if value, ok := mu.mutation.ToggleNetworkUse(); ok { - _spec.SetField(mod.FieldToggleNetworkUse, field.TypeBool, value) + if value, ok := mu.mutation.NetworkUseDisclosure(); ok { + _spec.SetField(mod.FieldNetworkUseDisclosure, field.TypeString, value) + } + if mu.mutation.NetworkUseDisclosureCleared() { + _spec.ClearField(mod.FieldNetworkUseDisclosure, field.TypeString) + } + if value, ok := mu.mutation.AiUseDisclosure(); ok { + _spec.SetField(mod.FieldAiUseDisclosure, field.TypeJSON, value) + } + if mu.mutation.AiUseDisclosureCleared() { + _spec.ClearField(mod.FieldAiUseDisclosure, field.TypeJSON) } if value, ok := mu.mutation.ToggleExplicitContent(); ok { _spec.SetField(mod.FieldToggleExplicitContent, field.TypeBool, value) @@ -1225,20 +1252,38 @@ func (muo *ModUpdateOne) ClearCompatibility() *ModUpdateOne { return muo } -// SetToggleNetworkUse sets the "toggle_network_use" field. -func (muo *ModUpdateOne) SetToggleNetworkUse(b bool) *ModUpdateOne { - muo.mutation.SetToggleNetworkUse(b) +// SetNetworkUseDisclosure sets the "network_use_disclosure" field. +func (muo *ModUpdateOne) SetNetworkUseDisclosure(s string) *ModUpdateOne { + muo.mutation.SetNetworkUseDisclosure(s) return muo } -// SetNillableToggleNetworkUse sets the "toggle_network_use" field if the given value is not nil. -func (muo *ModUpdateOne) SetNillableToggleNetworkUse(b *bool) *ModUpdateOne { - if b != nil { - muo.SetToggleNetworkUse(*b) +// SetNillableNetworkUseDisclosure sets the "network_use_disclosure" field if the given value is not nil. +func (muo *ModUpdateOne) SetNillableNetworkUseDisclosure(s *string) *ModUpdateOne { + if s != nil { + muo.SetNetworkUseDisclosure(*s) } return muo } +// ClearNetworkUseDisclosure clears the value of the "network_use_disclosure" field. +func (muo *ModUpdateOne) ClearNetworkUseDisclosure() *ModUpdateOne { + muo.mutation.ClearNetworkUseDisclosure() + return muo +} + +// SetAiUseDisclosure sets the "ai_use_disclosure" field. +func (muo *ModUpdateOne) SetAiUseDisclosure(uudi *util.AIUseDisclosureInfo) *ModUpdateOne { + muo.mutation.SetAiUseDisclosure(uudi) + return muo +} + +// ClearAiUseDisclosure clears the value of the "ai_use_disclosure" field. +func (muo *ModUpdateOne) ClearAiUseDisclosure() *ModUpdateOne { + muo.mutation.ClearAiUseDisclosure() + return muo +} + // SetToggleExplicitContent sets the "toggle_explicit_content" field. func (muo *ModUpdateOne) SetToggleExplicitContent(b bool) *ModUpdateOne { muo.mutation.SetToggleExplicitContent(b) @@ -1599,8 +1644,17 @@ func (muo *ModUpdateOne) sqlSave(ctx context.Context) (_node *Mod, err error) { if muo.mutation.CompatibilityCleared() { _spec.ClearField(mod.FieldCompatibility, field.TypeJSON) } - if value, ok := muo.mutation.ToggleNetworkUse(); ok { - _spec.SetField(mod.FieldToggleNetworkUse, field.TypeBool, value) + if value, ok := muo.mutation.NetworkUseDisclosure(); ok { + _spec.SetField(mod.FieldNetworkUseDisclosure, field.TypeString, value) + } + if muo.mutation.NetworkUseDisclosureCleared() { + _spec.ClearField(mod.FieldNetworkUseDisclosure, field.TypeString) + } + if value, ok := muo.mutation.AiUseDisclosure(); ok { + _spec.SetField(mod.FieldAiUseDisclosure, field.TypeJSON, value) + } + if muo.mutation.AiUseDisclosureCleared() { + _spec.ClearField(mod.FieldAiUseDisclosure, field.TypeJSON) } if value, ok := muo.mutation.ToggleExplicitContent(); ok { _spec.SetField(mod.FieldToggleExplicitContent, field.TypeBool, value) diff --git a/generated/ent/mutation.go b/generated/ent/mutation.go index b74b67dd..81553115 100644 --- a/generated/ent/mutation.go +++ b/generated/ent/mutation.go @@ -1961,7 +1961,8 @@ type ModMutation struct { mod_reference *string hidden *bool compatibility **util.CompatibilityInfo - toggle_network_use *bool + network_use_disclosure *string + ai_use_disclosure **util.AIUseDisclosureInfo toggle_explicit_content *bool clearedFields map[string]struct{} versions map[string]struct{} @@ -2963,40 +2964,102 @@ func (m *ModMutation) ResetCompatibility() { delete(m.clearedFields, mod.FieldCompatibility) } -// SetToggleNetworkUse sets the "toggle_network_use" field. -func (m *ModMutation) SetToggleNetworkUse(b bool) { - m.toggle_network_use = &b +// SetNetworkUseDisclosure sets the "network_use_disclosure" field. +func (m *ModMutation) SetNetworkUseDisclosure(s string) { + m.network_use_disclosure = &s } -// ToggleNetworkUse returns the value of the "toggle_network_use" field in the mutation. -func (m *ModMutation) ToggleNetworkUse() (r bool, exists bool) { - v := m.toggle_network_use +// NetworkUseDisclosure returns the value of the "network_use_disclosure" field in the mutation. +func (m *ModMutation) NetworkUseDisclosure() (r string, exists bool) { + v := m.network_use_disclosure if v == nil { return } return *v, true } -// OldToggleNetworkUse returns the old "toggle_network_use" field's value of the Mod entity. +// OldNetworkUseDisclosure returns the old "network_use_disclosure" field's value of the Mod entity. // If the Mod object wasn't provided to the builder, the object is fetched from the database. // An error is returned if the mutation operation is not UpdateOne, or the database query fails. -func (m *ModMutation) OldToggleNetworkUse(ctx context.Context) (v bool, err error) { +func (m *ModMutation) OldNetworkUseDisclosure(ctx context.Context) (v *string, err error) { if !m.op.Is(OpUpdateOne) { - return v, errors.New("OldToggleNetworkUse is only allowed on UpdateOne operations") + return v, errors.New("OldNetworkUseDisclosure is only allowed on UpdateOne operations") } if m.id == nil || m.oldValue == nil { - return v, errors.New("OldToggleNetworkUse requires an ID field in the mutation") + return v, errors.New("OldNetworkUseDisclosure requires an ID field in the mutation") } oldValue, err := m.oldValue(ctx) if err != nil { - return v, fmt.Errorf("querying old value for OldToggleNetworkUse: %w", err) + return v, fmt.Errorf("querying old value for OldNetworkUseDisclosure: %w", err) } - return oldValue.ToggleNetworkUse, nil + return oldValue.NetworkUseDisclosure, nil } -// ResetToggleNetworkUse resets all changes to the "toggle_network_use" field. -func (m *ModMutation) ResetToggleNetworkUse() { - m.toggle_network_use = nil +// ClearNetworkUseDisclosure clears the value of the "network_use_disclosure" field. +func (m *ModMutation) ClearNetworkUseDisclosure() { + m.network_use_disclosure = nil + m.clearedFields[mod.FieldNetworkUseDisclosure] = struct{}{} +} + +// NetworkUseDisclosureCleared returns if the "network_use_disclosure" field was cleared in this mutation. +func (m *ModMutation) NetworkUseDisclosureCleared() bool { + _, ok := m.clearedFields[mod.FieldNetworkUseDisclosure] + return ok +} + +// ResetNetworkUseDisclosure resets all changes to the "network_use_disclosure" field. +func (m *ModMutation) ResetNetworkUseDisclosure() { + m.network_use_disclosure = nil + delete(m.clearedFields, mod.FieldNetworkUseDisclosure) +} + +// SetAiUseDisclosure sets the "ai_use_disclosure" field. +func (m *ModMutation) SetAiUseDisclosure(uudi *util.AIUseDisclosureInfo) { + m.ai_use_disclosure = &uudi +} + +// AiUseDisclosure returns the value of the "ai_use_disclosure" field in the mutation. +func (m *ModMutation) AiUseDisclosure() (r *util.AIUseDisclosureInfo, exists bool) { + v := m.ai_use_disclosure + if v == nil { + return + } + return *v, true +} + +// OldAiUseDisclosure returns the old "ai_use_disclosure" field's value of the Mod entity. +// If the Mod object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ModMutation) OldAiUseDisclosure(ctx context.Context) (v *util.AIUseDisclosureInfo, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldAiUseDisclosure is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldAiUseDisclosure requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldAiUseDisclosure: %w", err) + } + return oldValue.AiUseDisclosure, nil +} + +// ClearAiUseDisclosure clears the value of the "ai_use_disclosure" field. +func (m *ModMutation) ClearAiUseDisclosure() { + m.ai_use_disclosure = nil + m.clearedFields[mod.FieldAiUseDisclosure] = struct{}{} +} + +// AiUseDisclosureCleared returns if the "ai_use_disclosure" field was cleared in this mutation. +func (m *ModMutation) AiUseDisclosureCleared() bool { + _, ok := m.clearedFields[mod.FieldAiUseDisclosure] + return ok +} + +// ResetAiUseDisclosure resets all changes to the "ai_use_disclosure" field. +func (m *ModMutation) ResetAiUseDisclosure() { + m.ai_use_disclosure = nil + delete(m.clearedFields, mod.FieldAiUseDisclosure) } // SetToggleExplicitContent sets the "toggle_explicit_content" field. @@ -3285,7 +3348,7 @@ func (m *ModMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *ModMutation) Fields() []string { - fields := make([]string, 0, 22) + fields := make([]string, 0, 23) if m.created_at != nil { fields = append(fields, mod.FieldCreatedAt) } @@ -3346,8 +3409,11 @@ func (m *ModMutation) Fields() []string { if m.compatibility != nil { fields = append(fields, mod.FieldCompatibility) } - if m.toggle_network_use != nil { - fields = append(fields, mod.FieldToggleNetworkUse) + if m.network_use_disclosure != nil { + fields = append(fields, mod.FieldNetworkUseDisclosure) + } + if m.ai_use_disclosure != nil { + fields = append(fields, mod.FieldAiUseDisclosure) } if m.toggle_explicit_content != nil { fields = append(fields, mod.FieldToggleExplicitContent) @@ -3400,8 +3466,10 @@ func (m *ModMutation) Field(name string) (ent.Value, bool) { return m.Hidden() case mod.FieldCompatibility: return m.Compatibility() - case mod.FieldToggleNetworkUse: - return m.ToggleNetworkUse() + case mod.FieldNetworkUseDisclosure: + return m.NetworkUseDisclosure() + case mod.FieldAiUseDisclosure: + return m.AiUseDisclosure() case mod.FieldToggleExplicitContent: return m.ToggleExplicitContent() } @@ -3453,8 +3521,10 @@ func (m *ModMutation) OldField(ctx context.Context, name string) (ent.Value, err return m.OldHidden(ctx) case mod.FieldCompatibility: return m.OldCompatibility(ctx) - case mod.FieldToggleNetworkUse: - return m.OldToggleNetworkUse(ctx) + case mod.FieldNetworkUseDisclosure: + return m.OldNetworkUseDisclosure(ctx) + case mod.FieldAiUseDisclosure: + return m.OldAiUseDisclosure(ctx) case mod.FieldToggleExplicitContent: return m.OldToggleExplicitContent(ctx) } @@ -3606,12 +3676,19 @@ func (m *ModMutation) SetField(name string, value ent.Value) error { } m.SetCompatibility(v) return nil - case mod.FieldToggleNetworkUse: - v, ok := value.(bool) + case mod.FieldNetworkUseDisclosure: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetNetworkUseDisclosure(v) + return nil + case mod.FieldAiUseDisclosure: + v, ok := value.(*util.AIUseDisclosureInfo) if !ok { return fmt.Errorf("unexpected type %T for field %s", value, name) } - m.SetToggleNetworkUse(v) + m.SetAiUseDisclosure(v) return nil case mod.FieldToggleExplicitContent: v, ok := value.(bool) @@ -3719,6 +3796,12 @@ func (m *ModMutation) ClearedFields() []string { if m.FieldCleared(mod.FieldCompatibility) { fields = append(fields, mod.FieldCompatibility) } + if m.FieldCleared(mod.FieldNetworkUseDisclosure) { + fields = append(fields, mod.FieldNetworkUseDisclosure) + } + if m.FieldCleared(mod.FieldAiUseDisclosure) { + fields = append(fields, mod.FieldAiUseDisclosure) + } return fields } @@ -3751,6 +3834,12 @@ func (m *ModMutation) ClearField(name string) error { case mod.FieldCompatibility: m.ClearCompatibility() return nil + case mod.FieldNetworkUseDisclosure: + m.ClearNetworkUseDisclosure() + return nil + case mod.FieldAiUseDisclosure: + m.ClearAiUseDisclosure() + return nil } return fmt.Errorf("unknown Mod nullable field %s", name) } @@ -3819,8 +3908,11 @@ func (m *ModMutation) ResetField(name string) error { case mod.FieldCompatibility: m.ResetCompatibility() return nil - case mod.FieldToggleNetworkUse: - m.ResetToggleNetworkUse() + case mod.FieldNetworkUseDisclosure: + m.ResetNetworkUseDisclosure() + return nil + case mod.FieldAiUseDisclosure: + m.ResetAiUseDisclosure() return nil case mod.FieldToggleExplicitContent: m.ResetToggleExplicitContent() diff --git a/generated/ent/runtime/runtime.go b/generated/ent/runtime/runtime.go index 2d6baa8d..b1666ef6 100644 --- a/generated/ent/runtime/runtime.go +++ b/generated/ent/runtime/runtime.go @@ -147,12 +147,8 @@ func init() { modDescHidden := modFields[15].Descriptor() // mod.DefaultHidden holds the default value on creation for the hidden field. mod.DefaultHidden = modDescHidden.Default.(bool) - // modDescToggleNetworkUse is the schema descriptor for toggle_network_use field. - modDescToggleNetworkUse := modFields[17].Descriptor() - // mod.DefaultToggleNetworkUse holds the default value on creation for the toggle_network_use field. - mod.DefaultToggleNetworkUse = modDescToggleNetworkUse.Default.(bool) // modDescToggleExplicitContent is the schema descriptor for toggle_explicit_content field. - modDescToggleExplicitContent := modFields[18].Descriptor() + modDescToggleExplicitContent := modFields[19].Descriptor() // mod.DefaultToggleExplicitContent holds the default value on creation for the toggle_explicit_content field. mod.DefaultToggleExplicitContent = modDescToggleExplicitContent.Default.(bool) // modDescID is the schema descriptor for id field. diff --git a/generated/generated.go b/generated/generated.go index 34d11a07..11c28ce2 100644 --- a/generated/generated.go +++ b/generated/generated.go @@ -73,6 +73,11 @@ type DirectiveRoot struct { } type ComplexityRoot struct { + AIUseDisclosureInfo struct { + DisclosureType func(childComplexity int) int + Message func(childComplexity int) int + } + Announcement struct { ID func(childComplexity int) int Importance func(childComplexity int) int @@ -85,8 +90,14 @@ type ComplexityRoot struct { } CompatibilityInfo struct { - Ea func(childComplexity int) int - Exp func(childComplexity int) int + Controller func(childComplexity int) int + Ea func(childComplexity int) int + Exp func(childComplexity int) int + } + + ControllerCompatibility struct { + Note func(childComplexity int) int + State func(childComplexity int) int } CreateVersionResponse struct { @@ -149,6 +160,7 @@ type ComplexityRoot struct { } Mod struct { + AiUseDisclosure func(childComplexity int) int Approved func(childComplexity int) int Authors func(childComplexity int) int Compatibility func(childComplexity int) int @@ -165,12 +177,12 @@ type ComplexityRoot struct { LogoThumbhash func(childComplexity int) int ModReference func(childComplexity int) int Name func(childComplexity int) int + NetworkUseDisclosure func(childComplexity int) int Popularity func(childComplexity int) int ShortDescription func(childComplexity int) int SourceURL func(childComplexity int) int Tags func(childComplexity int) int ToggleExplicitContent func(childComplexity int) int - ToggleNetworkUse func(childComplexity int) int UpdatedAt func(childComplexity int) int Version func(childComplexity int, version string) int Versions func(childComplexity int, filter map[string]interface{}) int @@ -538,6 +550,20 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin _ = ec switch typeName + "." + field { + case "AIUseDisclosureInfo.disclosure_type": + if e.complexity.AIUseDisclosureInfo.DisclosureType == nil { + break + } + + return e.complexity.AIUseDisclosureInfo.DisclosureType(childComplexity), true + + case "AIUseDisclosureInfo.message": + if e.complexity.AIUseDisclosureInfo.Message == nil { + break + } + + return e.complexity.AIUseDisclosureInfo.Message(childComplexity), true + case "Announcement.id": if e.complexity.Announcement.ID == nil { break @@ -573,6 +599,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Compatibility.State(childComplexity), true + case "CompatibilityInfo.Controller": + if e.complexity.CompatibilityInfo.Controller == nil { + break + } + + return e.complexity.CompatibilityInfo.Controller(childComplexity), true + case "CompatibilityInfo.EA": if e.complexity.CompatibilityInfo.Ea == nil { break @@ -587,6 +620,20 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.CompatibilityInfo.Exp(childComplexity), true + case "ControllerCompatibility.note": + if e.complexity.ControllerCompatibility.Note == nil { + break + } + + return e.complexity.ControllerCompatibility.Note(childComplexity), true + + case "ControllerCompatibility.state": + if e.complexity.ControllerCompatibility.State == nil { + break + } + + return e.complexity.ControllerCompatibility.State(childComplexity), true + case "CreateVersionResponse.auto_approved": if e.complexity.CreateVersionResponse.AutoApproved == nil { break @@ -790,6 +837,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.LatestVersions.Release(childComplexity), true + case "Mod.ai_use_disclosure": + if e.complexity.Mod.AiUseDisclosure == nil { + break + } + + return e.complexity.Mod.AiUseDisclosure(childComplexity), true + case "Mod.approved": if e.complexity.Mod.Approved == nil { break @@ -902,6 +956,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Mod.Name(childComplexity), true + case "Mod.network_use_disclosure": + if e.complexity.Mod.NetworkUseDisclosure == nil { + break + } + + return e.complexity.Mod.NetworkUseDisclosure(childComplexity), true + case "Mod.popularity": if e.complexity.Mod.Popularity == nil { break @@ -937,13 +998,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Mod.ToggleExplicitContent(childComplexity), true - case "Mod.toggle_network_use": - if e.complexity.Mod.ToggleNetworkUse == nil { - break - } - - return e.complexity.Mod.ToggleNetworkUse(childComplexity), true - case "Mod.updated_at": if e.complexity.Mod.UpdatedAt == nil { break @@ -2377,8 +2431,10 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { opCtx := graphql.GetOperationContext(ctx) ec := executionContext{opCtx, e, 0, 0, make(chan graphql.DeferredResult)} inputUnmarshalMap := graphql.BuildUnmarshalerMap( + ec.unmarshalInputAIUseDisclosureInput, ec.unmarshalInputCompatibilityInfoInput, ec.unmarshalInputCompatibilityInput, + ec.unmarshalInputControllerCompatibilityInput, ec.unmarshalInputGuideFilter, ec.unmarshalInputModFilter, ec.unmarshalInputModVersionConstraint, @@ -2578,20 +2634,41 @@ input CompatibilityInput { note: String } +enum ControllerCompatibilityState { + Untested + Unsupported + Partial + Implicit + Supported +} + +type ControllerCompatibility { + state: ControllerCompatibilityState! + note: String +} + +input ControllerCompatibilityInput { + state: ControllerCompatibilityState! + note: String +} + type CompatibilityInfo { EA: Compatibility! EXP: Compatibility! + Controller: ControllerCompatibility! } input CompatibilityInfoInput { EA: CompatibilityInput! EXP: CompatibilityInput! + Controller: ControllerCompatibilityInput! } extend type Mutation { updateModCompatibility(modId: ModID!, compatibility: CompatibilityInfoInput!): Boolean! @canEditModCompatibility(field: "modId") @isLoggedIn updateMultipleModCompatibilities(modIDs: [ModID!]!, compatibility: CompatibilityInfoInput!): Boolean! @canEditModCompatibility @isLoggedIn -}`, BuiltIn: false}, +} +`, BuiltIn: false}, {Name: "../schemas/directives.graphql", Input: `directive @isLoggedIn on FIELD_DEFINITION | INPUT_FIELD_DEFINITION directive @isNotLoggedIn on FIELD_DEFINITION | INPUT_FIELD_DEFINITION @@ -2695,6 +2772,12 @@ enum ModFields { search } +enum AIUseDisclosureType { + no_ai_usage + ai_usage + runtime_ai_usage +} + type Mod { id: ModID! name: String! @@ -2716,7 +2799,8 @@ type Mod { hidden: Boolean! tags: [Tag!] compatibility: CompatibilityInfo - toggle_network_use: Boolean! + network_use_disclosure: String + ai_use_disclosure: AIUseDisclosureInfo toggle_explicit_content: Boolean! authors: [UserMod!]! @@ -2741,6 +2825,11 @@ type ModVersion { versions: [Version!]! } +type AIUseDisclosureInfo { + disclosure_type: AIUseDisclosureType! + message: String +} + ### Inputs input ModFilter { @@ -2764,7 +2853,6 @@ input NewMod { mod_reference: ModReference! hidden: Boolean tagIDs: [TagID!] - toggle_network_use: Boolean toggle_explicit_content: Boolean } @@ -2779,7 +2867,8 @@ input UpdateMod { hidden: Boolean tagIDs: [TagID!] compatibility: CompatibilityInfoInput - toggle_network_use: Boolean + network_use_disclosure: String + ai_use_disclosure: AIUseDisclosureInput toggle_explicit_content: Boolean } @@ -2793,6 +2882,11 @@ input ModVersionConstraint { version: String! } +input AIUseDisclosureInput { + disclosure_type: AIUseDisclosureType! + message: String +} + ### Queries extend type Query { @@ -5686,6 +5780,91 @@ func (ec *executionContext) field___Type_fields_argsIncludeDeprecated( // region **************************** field.gotpl ***************************** +func (ec *executionContext) _AIUseDisclosureInfo_disclosure_type(ctx context.Context, field graphql.CollectedField, obj *AIUseDisclosureInfo) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_AIUseDisclosureInfo_disclosure_type(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.DisclosureType, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(AIUseDisclosureType) + fc.Result = res + return ec.marshalNAIUseDisclosureType2githubᚗcomᚋsatisfactorymoddingᚋsmrᚑapiᚋgeneratedᚐAIUseDisclosureType(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_AIUseDisclosureInfo_disclosure_type(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "AIUseDisclosureInfo", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type AIUseDisclosureType does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _AIUseDisclosureInfo_message(ctx context.Context, field graphql.CollectedField, obj *AIUseDisclosureInfo) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_AIUseDisclosureInfo_message(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.Message, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_AIUseDisclosureInfo_message(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "AIUseDisclosureInfo", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _Announcement_id(ctx context.Context, field graphql.CollectedField, obj *Announcement) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Announcement_id(ctx, field) if err != nil { @@ -6003,6 +6182,141 @@ func (ec *executionContext) fieldContext_CompatibilityInfo_EXP(_ context.Context return fc, nil } +func (ec *executionContext) _CompatibilityInfo_Controller(ctx context.Context, field graphql.CollectedField, obj *CompatibilityInfo) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_CompatibilityInfo_Controller(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.Controller, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*ControllerCompatibility) + fc.Result = res + return ec.marshalNControllerCompatibility2ᚖgithubᚗcomᚋsatisfactorymoddingᚋsmrᚑapiᚋgeneratedᚐControllerCompatibility(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_CompatibilityInfo_Controller(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "CompatibilityInfo", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "state": + return ec.fieldContext_ControllerCompatibility_state(ctx, field) + case "note": + return ec.fieldContext_ControllerCompatibility_note(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type ControllerCompatibility", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _ControllerCompatibility_state(ctx context.Context, field graphql.CollectedField, obj *ControllerCompatibility) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ControllerCompatibility_state(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.State, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(ControllerCompatibilityState) + fc.Result = res + return ec.marshalNControllerCompatibilityState2githubᚗcomᚋsatisfactorymoddingᚋsmrᚑapiᚋgeneratedᚐControllerCompatibilityState(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ControllerCompatibility_state(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ControllerCompatibility", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ControllerCompatibilityState does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _ControllerCompatibility_note(ctx context.Context, field graphql.CollectedField, obj *ControllerCompatibility) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ControllerCompatibility_note(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.Note, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ControllerCompatibility_note(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ControllerCompatibility", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _CreateVersionResponse_auto_approved(ctx context.Context, field graphql.CollectedField, obj *CreateVersionResponse) (ret graphql.Marshaler) { fc, err := ec.fieldContext_CreateVersionResponse_auto_approved(ctx, field) if err != nil { @@ -6319,8 +6633,10 @@ func (ec *executionContext) fieldContext_GetMods_mods(_ context.Context, field g return ec.fieldContext_Mod_tags(ctx, field) case "compatibility": return ec.fieldContext_Mod_compatibility(ctx, field) - case "toggle_network_use": - return ec.fieldContext_Mod_toggle_network_use(ctx, field) + case "network_use_disclosure": + return ec.fieldContext_Mod_network_use_disclosure(ctx, field) + case "ai_use_disclosure": + return ec.fieldContext_Mod_ai_use_disclosure(ctx, field) case "toggle_explicit_content": return ec.fieldContext_Mod_toggle_explicit_content(ctx, field) case "authors": @@ -6461,8 +6777,10 @@ func (ec *executionContext) fieldContext_GetMyMods_mods(_ context.Context, field return ec.fieldContext_Mod_tags(ctx, field) case "compatibility": return ec.fieldContext_Mod_compatibility(ctx, field) - case "toggle_network_use": - return ec.fieldContext_Mod_toggle_network_use(ctx, field) + case "network_use_disclosure": + return ec.fieldContext_Mod_network_use_disclosure(ctx, field) + case "ai_use_disclosure": + return ec.fieldContext_Mod_ai_use_disclosure(ctx, field) case "toggle_explicit_content": return ec.fieldContext_Mod_toggle_explicit_content(ctx, field) case "authors": @@ -8577,6 +8895,8 @@ func (ec *executionContext) fieldContext_Mod_compatibility(_ context.Context, fi return ec.fieldContext_CompatibilityInfo_EA(ctx, field) case "EXP": return ec.fieldContext_CompatibilityInfo_EXP(ctx, field) + case "Controller": + return ec.fieldContext_CompatibilityInfo_Controller(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type CompatibilityInfo", field.Name) }, @@ -8584,8 +8904,8 @@ func (ec *executionContext) fieldContext_Mod_compatibility(_ context.Context, fi return fc, nil } -func (ec *executionContext) _Mod_toggle_network_use(ctx context.Context, field graphql.CollectedField, obj *Mod) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mod_toggle_network_use(ctx, field) +func (ec *executionContext) _Mod_network_use_disclosure(ctx context.Context, field graphql.CollectedField, obj *Mod) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mod_network_use_disclosure(ctx, field) if err != nil { return graphql.Null } @@ -8598,31 +8918,75 @@ func (ec *executionContext) _Mod_toggle_network_use(ctx context.Context, field g }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return obj.ToggleNetworkUse, nil + return obj.NetworkUseDisclosure, nil }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mod_network_use_disclosure(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mod", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Mod_ai_use_disclosure(ctx context.Context, field graphql.CollectedField, obj *Mod) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mod_ai_use_disclosure(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.AiUseDisclosure, nil + }) + if err != nil { + ec.Error(ctx, err) return graphql.Null } - res := resTmp.(bool) + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*AIUseDisclosureInfo) fc.Result = res - return ec.marshalNBoolean2bool(ctx, field.Selections, res) + return ec.marshalOAIUseDisclosureInfo2ᚖgithubᚗcomᚋsatisfactorymoddingᚋsmrᚑapiᚋgeneratedᚐAIUseDisclosureInfo(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Mod_toggle_network_use(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Mod_ai_use_disclosure(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mod", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Boolean does not have child fields") + switch field.Name { + case "disclosure_type": + return ec.fieldContext_AIUseDisclosureInfo_disclosure_type(ctx, field) + case "message": + return ec.fieldContext_AIUseDisclosureInfo_message(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type AIUseDisclosureInfo", field.Name) }, } return fc, nil @@ -10051,8 +10415,10 @@ func (ec *executionContext) fieldContext_Mutation_createMod(ctx context.Context, return ec.fieldContext_Mod_tags(ctx, field) case "compatibility": return ec.fieldContext_Mod_compatibility(ctx, field) - case "toggle_network_use": - return ec.fieldContext_Mod_toggle_network_use(ctx, field) + case "network_use_disclosure": + return ec.fieldContext_Mod_network_use_disclosure(ctx, field) + case "ai_use_disclosure": + return ec.fieldContext_Mod_ai_use_disclosure(ctx, field) case "toggle_explicit_content": return ec.fieldContext_Mod_toggle_explicit_content(ctx, field) case "authors": @@ -10194,8 +10560,10 @@ func (ec *executionContext) fieldContext_Mutation_updateMod(ctx context.Context, return ec.fieldContext_Mod_tags(ctx, field) case "compatibility": return ec.fieldContext_Mod_compatibility(ctx, field) - case "toggle_network_use": - return ec.fieldContext_Mod_toggle_network_use(ctx, field) + case "network_use_disclosure": + return ec.fieldContext_Mod_network_use_disclosure(ctx, field) + case "ai_use_disclosure": + return ec.fieldContext_Mod_ai_use_disclosure(ctx, field) case "toggle_explicit_content": return ec.fieldContext_Mod_toggle_explicit_content(ctx, field) case "authors": @@ -12764,8 +13132,10 @@ func (ec *executionContext) fieldContext_Query_getMod(ctx context.Context, field return ec.fieldContext_Mod_tags(ctx, field) case "compatibility": return ec.fieldContext_Mod_compatibility(ctx, field) - case "toggle_network_use": - return ec.fieldContext_Mod_toggle_network_use(ctx, field) + case "network_use_disclosure": + return ec.fieldContext_Mod_network_use_disclosure(ctx, field) + case "ai_use_disclosure": + return ec.fieldContext_Mod_ai_use_disclosure(ctx, field) case "toggle_explicit_content": return ec.fieldContext_Mod_toggle_explicit_content(ctx, field) case "authors": @@ -12870,8 +13240,10 @@ func (ec *executionContext) fieldContext_Query_getModByReference(ctx context.Con return ec.fieldContext_Mod_tags(ctx, field) case "compatibility": return ec.fieldContext_Mod_compatibility(ctx, field) - case "toggle_network_use": - return ec.fieldContext_Mod_toggle_network_use(ctx, field) + case "network_use_disclosure": + return ec.fieldContext_Mod_network_use_disclosure(ctx, field) + case "ai_use_disclosure": + return ec.fieldContext_Mod_ai_use_disclosure(ctx, field) case "toggle_explicit_content": return ec.fieldContext_Mod_toggle_explicit_content(ctx, field) case "authors": @@ -12976,8 +13348,10 @@ func (ec *executionContext) fieldContext_Query_getModByIdOrReference(ctx context return ec.fieldContext_Mod_tags(ctx, field) case "compatibility": return ec.fieldContext_Mod_compatibility(ctx, field) - case "toggle_network_use": - return ec.fieldContext_Mod_toggle_network_use(ctx, field) + case "network_use_disclosure": + return ec.fieldContext_Mod_network_use_disclosure(ctx, field) + case "ai_use_disclosure": + return ec.fieldContext_Mod_ai_use_disclosure(ctx, field) case "toggle_explicit_content": return ec.fieldContext_Mod_toggle_explicit_content(ctx, field) case "authors": @@ -16761,8 +17135,10 @@ func (ec *executionContext) fieldContext_UserMod_mod(_ context.Context, field gr return ec.fieldContext_Mod_tags(ctx, field) case "compatibility": return ec.fieldContext_Mod_compatibility(ctx, field) - case "toggle_network_use": - return ec.fieldContext_Mod_toggle_network_use(ctx, field) + case "network_use_disclosure": + return ec.fieldContext_Mod_network_use_disclosure(ctx, field) + case "ai_use_disclosure": + return ec.fieldContext_Mod_ai_use_disclosure(ctx, field) case "toggle_explicit_content": return ec.fieldContext_Mod_toggle_explicit_content(ctx, field) case "authors": @@ -18006,8 +18382,10 @@ func (ec *executionContext) fieldContext_Version_mod(_ context.Context, field gr return ec.fieldContext_Mod_tags(ctx, field) case "compatibility": return ec.fieldContext_Mod_compatibility(ctx, field) - case "toggle_network_use": - return ec.fieldContext_Mod_toggle_network_use(ctx, field) + case "network_use_disclosure": + return ec.fieldContext_Mod_network_use_disclosure(ctx, field) + case "ai_use_disclosure": + return ec.fieldContext_Mod_ai_use_disclosure(ctx, field) case "toggle_explicit_content": return ec.fieldContext_Mod_toggle_explicit_content(ctx, field) case "authors": @@ -18441,8 +18819,10 @@ func (ec *executionContext) fieldContext_VersionDependency_mod(_ context.Context return ec.fieldContext_Mod_tags(ctx, field) case "compatibility": return ec.fieldContext_Mod_compatibility(ctx, field) - case "toggle_network_use": - return ec.fieldContext_Mod_toggle_network_use(ctx, field) + case "network_use_disclosure": + return ec.fieldContext_Mod_network_use_disclosure(ctx, field) + case "ai_use_disclosure": + return ec.fieldContext_Mod_ai_use_disclosure(ctx, field) case "toggle_explicit_content": return ec.fieldContext_Mod_toggle_explicit_content(ctx, field) case "authors": @@ -21010,6 +21390,40 @@ func (ec *executionContext) fieldContext___Type_isOneOf(_ context.Context, field // region **************************** input.gotpl ***************************** +func (ec *executionContext) unmarshalInputAIUseDisclosureInput(ctx context.Context, obj any) (AIUseDisclosureInput, error) { + var it AIUseDisclosureInput + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"disclosure_type", "message"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "disclosure_type": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("disclosure_type")) + data, err := ec.unmarshalNAIUseDisclosureType2githubᚗcomᚋsatisfactorymoddingᚋsmrᚑapiᚋgeneratedᚐAIUseDisclosureType(ctx, v) + if err != nil { + return it, err + } + it.DisclosureType = data + case "message": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("message")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.Message = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputCompatibilityInfoInput(ctx context.Context, obj any) (CompatibilityInfoInput, error) { var it CompatibilityInfoInput asMap := map[string]any{} @@ -21017,7 +21431,7 @@ func (ec *executionContext) unmarshalInputCompatibilityInfoInput(ctx context.Con asMap[k] = v } - fieldsInOrder := [...]string{"EA", "EXP"} + fieldsInOrder := [...]string{"EA", "EXP", "Controller"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -21038,6 +21452,13 @@ func (ec *executionContext) unmarshalInputCompatibilityInfoInput(ctx context.Con return it, err } it.Exp = data + case "Controller": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("Controller")) + data, err := ec.unmarshalNControllerCompatibilityInput2ᚖgithubᚗcomᚋsatisfactorymoddingᚋsmrᚑapiᚋgeneratedᚐControllerCompatibilityInput(ctx, v) + if err != nil { + return it, err + } + it.Controller = data } } @@ -21078,6 +21499,40 @@ func (ec *executionContext) unmarshalInputCompatibilityInput(ctx context.Context return it, nil } +func (ec *executionContext) unmarshalInputControllerCompatibilityInput(ctx context.Context, obj any) (ControllerCompatibilityInput, error) { + var it ControllerCompatibilityInput + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"state", "note"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "state": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("state")) + data, err := ec.unmarshalNControllerCompatibilityState2githubᚗcomᚋsatisfactorymoddingᚋsmrᚑapiᚋgeneratedᚐControllerCompatibilityState(ctx, v) + if err != nil { + return it, err + } + it.State = data + case "note": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("note")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.Note = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputGuideFilter(ctx context.Context, obj any) (map[string]any, error) { it := make(map[string]any, len(obj.(map[string]any))) asMap := map[string]any{} @@ -21353,7 +21808,7 @@ func (ec *executionContext) unmarshalInputNewMod(ctx context.Context, obj any) ( asMap[k] = v } - fieldsInOrder := [...]string{"name", "short_description", "full_description", "logo", "source_url", "mod_reference", "hidden", "tagIDs", "toggle_network_use", "toggle_explicit_content"} + fieldsInOrder := [...]string{"name", "short_description", "full_description", "logo", "source_url", "mod_reference", "hidden", "tagIDs", "toggle_explicit_content"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -21416,13 +21871,6 @@ func (ec *executionContext) unmarshalInputNewMod(ctx context.Context, obj any) ( return it, err } it.TagIDs = data - case "toggle_network_use": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("toggle_network_use")) - data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) - if err != nil { - return it, err - } - it.ToggleNetworkUse = data case "toggle_explicit_content": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("toggle_explicit_content")) data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) @@ -21744,7 +22192,7 @@ func (ec *executionContext) unmarshalInputUpdateMod(ctx context.Context, obj any asMap[k] = v } - fieldsInOrder := [...]string{"name", "short_description", "full_description", "logo", "source_url", "mod_reference", "authors", "hidden", "tagIDs", "compatibility", "toggle_network_use", "toggle_explicit_content"} + fieldsInOrder := [...]string{"name", "short_description", "full_description", "logo", "source_url", "mod_reference", "authors", "hidden", "tagIDs", "compatibility", "network_use_disclosure", "ai_use_disclosure", "toggle_explicit_content"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -21821,13 +22269,20 @@ func (ec *executionContext) unmarshalInputUpdateMod(ctx context.Context, obj any return it, err } it.Compatibility = data - case "toggle_network_use": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("toggle_network_use")) - data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) + case "network_use_disclosure": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("network_use_disclosure")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.NetworkUseDisclosure = graphql.OmittableOf(data) + case "ai_use_disclosure": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ai_use_disclosure")) + data, err := ec.unmarshalOAIUseDisclosureInput2ᚖgithubᚗcomᚋsatisfactorymoddingᚋsmrᚑapiᚋgeneratedᚐAIUseDisclosureInput(ctx, v) if err != nil { return it, err } - it.ToggleNetworkUse = data + it.AiUseDisclosure = graphql.OmittableOf(data) case "toggle_explicit_content": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("toggle_explicit_content")) data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) @@ -22078,6 +22533,47 @@ func (ec *executionContext) unmarshalInputVersionFilter(ctx context.Context, obj // region **************************** object.gotpl **************************** +var aIUseDisclosureInfoImplementors = []string{"AIUseDisclosureInfo"} + +func (ec *executionContext) _AIUseDisclosureInfo(ctx context.Context, sel ast.SelectionSet, obj *AIUseDisclosureInfo) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, aIUseDisclosureInfoImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("AIUseDisclosureInfo") + case "disclosure_type": + out.Values[i] = ec._AIUseDisclosureInfo_disclosure_type(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "message": + out.Values[i] = ec._AIUseDisclosureInfo_message(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var announcementImplementors = []string{"Announcement"} func (ec *executionContext) _Announcement(ctx context.Context, sel ast.SelectionSet, obj *Announcement) graphql.Marshaler { @@ -22189,6 +22685,52 @@ func (ec *executionContext) _CompatibilityInfo(ctx context.Context, sel ast.Sele if out.Values[i] == graphql.Null { out.Invalids++ } + case "Controller": + out.Values[i] = ec._CompatibilityInfo_Controller(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var controllerCompatibilityImplementors = []string{"ControllerCompatibility"} + +func (ec *executionContext) _ControllerCompatibility(ctx context.Context, sel ast.SelectionSet, obj *ControllerCompatibility) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, controllerCompatibilityImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ControllerCompatibility") + case "state": + out.Values[i] = ec._ControllerCompatibility_state(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "note": + out.Values[i] = ec._ControllerCompatibility_note(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -23178,11 +23720,10 @@ func (ec *executionContext) _Mod(ctx context.Context, sel ast.SelectionSet, obj out.Values[i] = ec._Mod_tags(ctx, field, obj) case "compatibility": out.Values[i] = ec._Mod_compatibility(ctx, field, obj) - case "toggle_network_use": - out.Values[i] = ec._Mod_toggle_network_use(ctx, field, obj) - if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) - } + case "network_use_disclosure": + out.Values[i] = ec._Mod_network_use_disclosure(ctx, field, obj) + case "ai_use_disclosure": + out.Values[i] = ec._Mod_ai_use_disclosure(ctx, field, obj) case "toggle_explicit_content": out.Values[i] = ec._Mod_toggle_explicit_content(ctx, field, obj) if out.Values[i] == graphql.Null { @@ -26092,6 +26633,16 @@ func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, o // region ***************************** type.gotpl ***************************** +func (ec *executionContext) unmarshalNAIUseDisclosureType2githubᚗcomᚋsatisfactorymoddingᚋsmrᚑapiᚋgeneratedᚐAIUseDisclosureType(ctx context.Context, v any) (AIUseDisclosureType, error) { + var res AIUseDisclosureType + err := res.UnmarshalGQL(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNAIUseDisclosureType2githubᚗcomᚋsatisfactorymoddingᚋsmrᚑapiᚋgeneratedᚐAIUseDisclosureType(ctx context.Context, sel ast.SelectionSet, v AIUseDisclosureType) graphql.Marshaler { + return v +} + func (ec *executionContext) marshalNAnnouncement2githubᚗcomᚋsatisfactorymoddingᚋsmrᚑapiᚋgeneratedᚐAnnouncement(ctx context.Context, sel ast.SelectionSet, v Announcement) graphql.Marshaler { return ec._Announcement(ctx, sel, &v) } @@ -26222,6 +26773,31 @@ func (ec *executionContext) marshalNCompatibilityState2githubᚗcomᚋsatisfacto return v } +func (ec *executionContext) marshalNControllerCompatibility2ᚖgithubᚗcomᚋsatisfactorymoddingᚋsmrᚑapiᚋgeneratedᚐControllerCompatibility(ctx context.Context, sel ast.SelectionSet, v *ControllerCompatibility) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._ControllerCompatibility(ctx, sel, v) +} + +func (ec *executionContext) unmarshalNControllerCompatibilityInput2ᚖgithubᚗcomᚋsatisfactorymoddingᚋsmrᚑapiᚋgeneratedᚐControllerCompatibilityInput(ctx context.Context, v any) (*ControllerCompatibilityInput, error) { + res, err := ec.unmarshalInputControllerCompatibilityInput(ctx, v) + return &res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) unmarshalNControllerCompatibilityState2githubᚗcomᚋsatisfactorymoddingᚋsmrᚑapiᚋgeneratedᚐControllerCompatibilityState(ctx context.Context, v any) (ControllerCompatibilityState, error) { + var res ControllerCompatibilityState + err := res.UnmarshalGQL(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNControllerCompatibilityState2githubᚗcomᚋsatisfactorymoddingᚋsmrᚑapiᚋgeneratedᚐControllerCompatibilityState(ctx context.Context, sel ast.SelectionSet, v ControllerCompatibilityState) graphql.Marshaler { + return v +} + func (ec *executionContext) unmarshalNDate2string(ctx context.Context, v any) (string, error) { res, err := graphql.UnmarshalString(v) return res, graphql.ErrorOnPath(ctx, err) @@ -27777,6 +28353,21 @@ func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel a return res } +func (ec *executionContext) marshalOAIUseDisclosureInfo2ᚖgithubᚗcomᚋsatisfactorymoddingᚋsmrᚑapiᚋgeneratedᚐAIUseDisclosureInfo(ctx context.Context, sel ast.SelectionSet, v *AIUseDisclosureInfo) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._AIUseDisclosureInfo(ctx, sel, v) +} + +func (ec *executionContext) unmarshalOAIUseDisclosureInput2ᚖgithubᚗcomᚋsatisfactorymoddingᚋsmrᚑapiᚋgeneratedᚐAIUseDisclosureInput(ctx context.Context, v any) (*AIUseDisclosureInput, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalInputAIUseDisclosureInput(ctx, v) + return &res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) marshalOAnnouncement2ᚖgithubᚗcomᚋsatisfactorymoddingᚋsmrᚑapiᚋgeneratedᚐAnnouncement(ctx context.Context, sel ast.SelectionSet, v *Announcement) graphql.Marshaler { if v == nil { return graphql.Null diff --git a/generated/models_gen.go b/generated/models_gen.go index 7656cdf0..41daceeb 100644 --- a/generated/models_gen.go +++ b/generated/models_gen.go @@ -11,6 +11,16 @@ import ( "github.com/99designs/gqlgen/graphql" ) +type AIUseDisclosureInfo struct { + DisclosureType AIUseDisclosureType `json:"disclosure_type"` + Message *string `json:"message,omitempty"` +} + +type AIUseDisclosureInput struct { + DisclosureType AIUseDisclosureType `json:"disclosure_type"` + Message *string `json:"message,omitempty"` +} + type Announcement struct { ID string `json:"id"` Message string `json:"message"` @@ -23,13 +33,15 @@ type Compatibility struct { } type CompatibilityInfo struct { - Ea *Compatibility `json:"EA"` - Exp *Compatibility `json:"EXP"` + Ea *Compatibility `json:"EA"` + Exp *Compatibility `json:"EXP"` + Controller *ControllerCompatibility `json:"Controller"` } type CompatibilityInfoInput struct { - Ea *CompatibilityInput `json:"EA"` - Exp *CompatibilityInput `json:"EXP"` + Ea *CompatibilityInput `json:"EA"` + Exp *CompatibilityInput `json:"EXP"` + Controller *ControllerCompatibilityInput `json:"Controller"` } type CompatibilityInput struct { @@ -37,6 +49,16 @@ type CompatibilityInput struct { Note *string `json:"note,omitempty"` } +type ControllerCompatibility struct { + State ControllerCompatibilityState `json:"state"` + Note *string `json:"note,omitempty"` +} + +type ControllerCompatibilityInput struct { + State ControllerCompatibilityState `json:"state"` + Note *string `json:"note,omitempty"` +} + type CreateVersionResponse struct { AutoApproved bool `json:"auto_approved"` Version *Version `json:"version,omitempty"` @@ -97,32 +119,33 @@ type LatestVersions struct { } type Mod struct { - ID string `json:"id"` - Name string `json:"name"` - ShortDescription string `json:"short_description"` - FullDescription *string `json:"full_description,omitempty"` - Logo *string `json:"logo,omitempty"` - LogoThumbhash *string `json:"logo_thumbhash,omitempty"` - SourceURL *string `json:"source_url,omitempty"` - CreatorID string `json:"creator_id"` - Approved bool `json:"approved"` - Views int `json:"views"` - Downloads int `json:"downloads"` - Hotness int `json:"hotness"` - Popularity int `json:"popularity"` - UpdatedAt string `json:"updated_at"` - CreatedAt string `json:"created_at"` - LastVersionDate *string `json:"last_version_date,omitempty"` - ModReference string `json:"mod_reference"` - Hidden bool `json:"hidden"` - Tags []*Tag `json:"tags,omitempty"` - Compatibility *CompatibilityInfo `json:"compatibility,omitempty"` - ToggleNetworkUse bool `json:"toggle_network_use"` - ToggleExplicitContent bool `json:"toggle_explicit_content"` - Authors []*UserMod `json:"authors"` - Version *Version `json:"version,omitempty"` - Versions []*Version `json:"versions"` - LatestVersions *LatestVersions `json:"latestVersions"` + ID string `json:"id"` + Name string `json:"name"` + ShortDescription string `json:"short_description"` + FullDescription *string `json:"full_description,omitempty"` + Logo *string `json:"logo,omitempty"` + LogoThumbhash *string `json:"logo_thumbhash,omitempty"` + SourceURL *string `json:"source_url,omitempty"` + CreatorID string `json:"creator_id"` + Approved bool `json:"approved"` + Views int `json:"views"` + Downloads int `json:"downloads"` + Hotness int `json:"hotness"` + Popularity int `json:"popularity"` + UpdatedAt string `json:"updated_at"` + CreatedAt string `json:"created_at"` + LastVersionDate *string `json:"last_version_date,omitempty"` + ModReference string `json:"mod_reference"` + Hidden bool `json:"hidden"` + Tags []*Tag `json:"tags,omitempty"` + Compatibility *CompatibilityInfo `json:"compatibility,omitempty"` + NetworkUseDisclosure *string `json:"network_use_disclosure,omitempty"` + AiUseDisclosure *AIUseDisclosureInfo `json:"ai_use_disclosure,omitempty"` + ToggleExplicitContent bool `json:"toggle_explicit_content"` + Authors []*UserMod `json:"authors"` + Version *Version `json:"version,omitempty"` + Versions []*Version `json:"versions"` + LatestVersions *LatestVersions `json:"latestVersions"` } type ModVersion struct { @@ -339,6 +362,63 @@ type VirustotalResult struct { UpdatedAt *string `json:"updated_at,omitempty"` } +type AIUseDisclosureType string + +const ( + AIUseDisclosureTypeNoAiUsage AIUseDisclosureType = "no_ai_usage" + AIUseDisclosureTypeAiUsage AIUseDisclosureType = "ai_usage" + AIUseDisclosureTypeRuntimeAiUsage AIUseDisclosureType = "runtime_ai_usage" +) + +var AllAIUseDisclosureType = []AIUseDisclosureType{ + AIUseDisclosureTypeNoAiUsage, + AIUseDisclosureTypeAiUsage, + AIUseDisclosureTypeRuntimeAiUsage, +} + +func (e AIUseDisclosureType) IsValid() bool { + switch e { + case AIUseDisclosureTypeNoAiUsage, AIUseDisclosureTypeAiUsage, AIUseDisclosureTypeRuntimeAiUsage: + return true + } + return false +} + +func (e AIUseDisclosureType) String() string { + return string(e) +} + +func (e *AIUseDisclosureType) UnmarshalGQL(v any) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = AIUseDisclosureType(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid AIUseDisclosureType", str) + } + return nil +} + +func (e AIUseDisclosureType) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} + +func (e *AIUseDisclosureType) UnmarshalJSON(b []byte) error { + s, err := strconv.Unquote(string(b)) + if err != nil { + return err + } + return e.UnmarshalGQL(s) +} + +func (e AIUseDisclosureType) MarshalJSON() ([]byte, error) { + var buf bytes.Buffer + e.MarshalGQL(&buf) + return buf.Bytes(), nil +} + type AnnouncementImportance string const ( @@ -455,6 +535,67 @@ func (e CompatibilityState) MarshalJSON() ([]byte, error) { return buf.Bytes(), nil } +type ControllerCompatibilityState string + +const ( + ControllerCompatibilityStateUntested ControllerCompatibilityState = "Untested" + ControllerCompatibilityStateUnsupported ControllerCompatibilityState = "Unsupported" + ControllerCompatibilityStatePartial ControllerCompatibilityState = "Partial" + ControllerCompatibilityStateImplicit ControllerCompatibilityState = "Implicit" + ControllerCompatibilityStateSupported ControllerCompatibilityState = "Supported" +) + +var AllControllerCompatibilityState = []ControllerCompatibilityState{ + ControllerCompatibilityStateUntested, + ControllerCompatibilityStateUnsupported, + ControllerCompatibilityStatePartial, + ControllerCompatibilityStateImplicit, + ControllerCompatibilityStateSupported, +} + +func (e ControllerCompatibilityState) IsValid() bool { + switch e { + case ControllerCompatibilityStateUntested, ControllerCompatibilityStateUnsupported, ControllerCompatibilityStatePartial, ControllerCompatibilityStateImplicit, ControllerCompatibilityStateSupported: + return true + } + return false +} + +func (e ControllerCompatibilityState) String() string { + return string(e) +} + +func (e *ControllerCompatibilityState) UnmarshalGQL(v any) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = ControllerCompatibilityState(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid ControllerCompatibilityState", str) + } + return nil +} + +func (e ControllerCompatibilityState) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} + +func (e *ControllerCompatibilityState) UnmarshalJSON(b []byte) error { + s, err := strconv.Unquote(string(b)) + if err != nil { + return err + } + return e.UnmarshalGQL(s) +} + +func (e ControllerCompatibilityState) MarshalJSON() ([]byte, error) { + var buf bytes.Buffer + e.MarshalGQL(&buf) + return buf.Bytes(), nil +} + type GuideFields string const ( diff --git a/go.mod b/go.mod index 590a743e..2c7decd2 100755 --- a/go.mod +++ b/go.mod @@ -1,5 +1,6 @@ module github.com/satisfactorymodding/smr-api +// when updating, also update .devcontainer/Dockerfile go 1.24.4 require ( diff --git a/gql/gql_types.go b/gql/gql_types.go index 52aef7b3..b7528bd6 100644 --- a/gql/gql_types.go +++ b/gql/gql_types.go @@ -10,15 +10,35 @@ func GenCompInfoToDBCompInfo(gen *generated.CompatibilityInfoInput) *util.Compat return nil } return &util.CompatibilityInfo{ - Ea: GenCompToDBComp(gen.Ea), - Exp: GenCompToDBComp(gen.Exp), + Ea: GenCompToDBComp(gen.Ea), + Exp: GenCompToDBComp(gen.Exp), + Controller: GenControllerCompToDBControllerComp(gen.Controller), } } -func GenCompToDBComp(gen *generated.CompatibilityInput) util.Compatibility { +func setStateINN(state string, note *string) util.Compatibility { r := util.Compatibility{ - State: string(gen.State), + State: state, + } + SetINN(note, &r.Note) + return r +} + +func GenCompToDBComp(gen *generated.CompatibilityInput) util.Compatibility { + return setStateINN(string(gen.State), gen.Note) +} + +func GenControllerCompToDBControllerComp(gen *generated.ControllerCompatibilityInput) util.Compatibility { + return setStateINN(string(gen.State), gen.Note) +} + +func GenAIDisclosureInfoToDBAIDisclosureInfo(gen *generated.AIUseDisclosureInput) *util.AIUseDisclosureInfo { + if gen == nil { + return nil + } + r := &util.AIUseDisclosureInfo{ + DisclosureType: string(gen.DisclosureType), } - SetINN(gen.Note, &r.Note) + SetINN(gen.Message, &r.Message) return r } diff --git a/gql/gql_utils.go b/gql/gql_utils.go index 925f293f..268c9899 100644 --- a/gql/gql_utils.go +++ b/gql/gql_utils.go @@ -18,6 +18,7 @@ func SetINN[T any](v *T, target *T) { } } +// SetCompatibilityINNF calls function 'target' to set value if not nil func SetCompatibilityINNF[B any](value *generated.CompatibilityInfoInput, target func(*util.CompatibilityInfo) B) { if value == nil { return @@ -25,26 +26,36 @@ func SetCompatibilityINNF[B any](value *generated.CompatibilityInfoInput, target target(GenCompInfoToDBCompInfo(value)) } -// SetINNF - Set if not null function +// SetAIDisclosureINNF calls function 'target' to set value if not nil +func SetAIDisclosureINNF[B any](value *generated.AIUseDisclosureInput, target func(*util.AIUseDisclosureInfo) B) { + if value == nil { + return + } + target(GenAIDisclosureInfoToDBAIDisclosureInfo(value)) +} + +// SetINNF calls function 'target' to set value if not nil func SetINNF[T any, B any](value *T, target func(T) B) { if value != nil { target(*value) } } -// SetINNOEF - Set if not null or empty function +// SetINNOEF calls function 'target' to set value if not nil or empty func SetINNOEF[T comparable, B any](value *T, target func(T) B) { if value != nil && *value != *(new(T)) { target(*value) } } +// SetStabilityINNF calls function 'target' to set value if not nil func SetStabilityINNF[B any](value *generated.VersionStabilities, target func(util.Stability) B) { if value != nil { target(util.Stability(*value)) } } +// SetDateINNF calls function 'target' to set value if not nil func SetDateINNF[B any](value *string, target func(time.Time) B) { if value != nil { t, _ := time.Parse(time.RFC3339Nano, *value) diff --git a/gql/resolver_guides.go b/gql/resolver_guides.go index cda742cf..bd476c62 100644 --- a/gql/resolver_guides.go +++ b/gql/resolver_guides.go @@ -35,7 +35,7 @@ func (r *mutationResolver) CreateGuide(ctx context.Context, g generated.NewGuide return nil, err } - // Allow only 8util.GuidesPer24h new guides per 24h + // Allow only util.GuidesPer24h new guides per 24h guides, err := db.From(ctx).Guide.Query(). Order(guide.ByCreatedAt(sql.OrderAsc())). Where( diff --git a/gql/resolver_mods.go b/gql/resolver_mods.go index 729638be..d4b0ece8 100644 --- a/gql/resolver_mods.go +++ b/gql/resolver_mods.go @@ -79,7 +79,6 @@ func (r *mutationResolver) CreateMod(ctx context.Context, newMod generated.NewMo SetINNF(newMod.SourceURL, dbMod.SetSourceURL) SetINNF(newMod.FullDescription, dbMod.SetFullDescription) SetINNF(newMod.Hidden, dbMod.SetHidden) - SetINNF(newMod.ToggleNetworkUse, dbMod.SetToggleNetworkUse) SetINNF(newMod.ToggleExplicitContent, dbMod.SetToggleExplicitContent) user, _, err := db.UserFromGQLContext(ctx) @@ -160,6 +159,10 @@ func (r *mutationResolver) CreateMod(ctx context.Context, newMod generated.NewMo return (*conv.ModImpl)(nil).Convert(resultMod), nil } +func requiresMessage(disclosureType generated.AIUseDisclosureType) bool { + return disclosureType == generated.AIUseDisclosureTypeAiUsage || disclosureType == generated.AIUseDisclosureTypeRuntimeAiUsage +} + func (r *mutationResolver) UpdateMod(ctx context.Context, modID string, updateMod generated.UpdateMod) (*generated.Mod, error) { val := ctx.Value(util.ContextValidator{}).(*validator.Validate) if err := val.Struct(&updateMod); err != nil { @@ -187,9 +190,29 @@ func (r *mutationResolver) UpdateMod(ctx context.Context, modID string, updateMo SetINNF(updateMod.ModReference, dbUpdate.SetModReference) SetINNF(updateMod.Hidden, dbUpdate.SetHidden) SetCompatibilityINNF(updateMod.Compatibility, dbUpdate.SetCompatibility) - SetINNF(updateMod.ToggleNetworkUse, dbUpdate.SetToggleNetworkUse) SetINNF(updateMod.ToggleExplicitContent, dbUpdate.SetToggleExplicitContent) + aiDisclosureUpdate, isSet := updateMod.AiUseDisclosure.ValueOK() + if isSet { + if aiDisclosureUpdate != nil { + if requiresMessage(aiDisclosureUpdate.DisclosureType) && (aiDisclosureUpdate.Message == nil || *aiDisclosureUpdate.Message == "") { + return nil, errors.New("you need to input a disclosure message when disclosing AI usage") + } + SetAIDisclosureINNF(aiDisclosureUpdate, dbUpdate.SetAiUseDisclosure) + } else if dbMod.AiUseDisclosure != nil { + return nil, errors.New("this mod already has an AI use disclosure, and thus it cannot be cleared") + } + } + + newNetworkDisclosure, isSet := updateMod.NetworkUseDisclosure.ValueOK() + if isSet { + if newNetworkDisclosure != nil { + dbUpdate.SetNetworkUseDisclosure(*newNetworkDisclosure) + } else if dbMod.NetworkUseDisclosure != nil { + return nil, errors.New("this mod already has a network use disclosure, and thus it cannot be cleared") + } + } + if updateMod.Logo != nil { file, err := io.ReadAll(updateMod.Logo.File) if err != nil { diff --git a/gql/resolver_versions.go b/gql/resolver_versions.go index db94f86a..f84c1edc 100644 --- a/gql/resolver_versions.go +++ b/gql/resolver_versions.go @@ -51,6 +51,18 @@ func (r *mutationResolver) CreateVersion(ctx context.Context, modID string) (str return "", errors.New("you must update your mod reference on the site to match your mod_reference in your data.json") } + if mod.AiUseDisclosure == nil { + return "", errors.New("you must provide an AI use disclosure before uploading a version") + } + + if mod.AiUseDisclosure.DisclosureType != generated.AIUseDisclosureTypeNoAiUsage.String() && mod.AiUseDisclosure.Message == "" { + return "", errors.New("you must provide a description for your AI use disclosure before uploading a version") + } + + if mod.NetworkUseDisclosure == nil { + return "", errors.New("you must provide a network use disclosure before uploading a version") + } + uploadID := util.GenerateUniqueID() _, _ = storage.StartUploadMultipartMod(ctx, mod.ID, mod.Name, uploadID) diff --git a/gqlgen.yml b/gqlgen.yml index 545b7c22..40adb0c4 100755 --- a/gqlgen.yml +++ b/gqlgen.yml @@ -12,6 +12,7 @@ model: resolver: filename: ./gql/resolver.go type: Resolver + # https://github.com/99designs/gqlgen/issues/3321 preserve_resolver: true models: @@ -20,6 +21,11 @@ models: model: github.com/satisfactorymodding/smr-api/generated.NewMod UpdateMod: model: github.com/satisfactorymodding/smr-api/generated.UpdateMod + fields: + network_use_disclosure: + omittable: true + ai_use_disclosure: + omittable: true VersionFilter: model: "map[string]interface{}" diff --git a/migrations/sql/20250411023207_add_network_usage_disclosure.down.sql b/migrations/sql/20250411023207_add_network_usage_disclosure.down.sql new file mode 100644 index 00000000..7ff9c976 --- /dev/null +++ b/migrations/sql/20250411023207_add_network_usage_disclosure.down.sql @@ -0,0 +1,2 @@ +-- reverse: modify "mods" table +ALTER TABLE "mods" DROP COLUMN "network_use_disclosure"; diff --git a/migrations/sql/20250411023207_add_network_usage_disclosure.up.sql b/migrations/sql/20250411023207_add_network_usage_disclosure.up.sql new file mode 100644 index 00000000..a94bbee5 --- /dev/null +++ b/migrations/sql/20250411023207_add_network_usage_disclosure.up.sql @@ -0,0 +1,2 @@ +-- modify "mods" table +ALTER TABLE "mods" ADD COLUMN "network_use_disclosure" character varying NULL; diff --git a/migrations/sql/20260427195353_add_ai_disclosure.down.sql b/migrations/sql/20260427195353_add_ai_disclosure.down.sql new file mode 100644 index 00000000..3235961a --- /dev/null +++ b/migrations/sql/20260427195353_add_ai_disclosure.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE mods + DROP COLUMN ai_use_disclosure \ No newline at end of file diff --git a/migrations/sql/20260427195353_add_ai_disclosure.up.sql b/migrations/sql/20260427195353_add_ai_disclosure.up.sql new file mode 100644 index 00000000..93475f2f --- /dev/null +++ b/migrations/sql/20260427195353_add_ai_disclosure.up.sql @@ -0,0 +1,2 @@ +ALTER TABLE mods + ADD COLUMN ai_use_disclosure jsonb \ No newline at end of file diff --git a/migrations/sql/20260501041455_add_default_controller_compatibility.down.sql b/migrations/sql/20260501041455_add_default_controller_compatibility.down.sql new file mode 100644 index 00000000..473c3c7a --- /dev/null +++ b/migrations/sql/20260501041455_add_default_controller_compatibility.down.sql @@ -0,0 +1,3 @@ +UPDATE "mods" + SET "compatibility" = mods.compatibility - 'Controller' + WHERE mods.compatibility ? 'Controller' AND mods.compatibility ? 'EA'; diff --git a/migrations/sql/20260501041455_add_default_controller_compatibility.up.sql b/migrations/sql/20260501041455_add_default_controller_compatibility.up.sql new file mode 100644 index 00000000..ed8d718c --- /dev/null +++ b/migrations/sql/20260501041455_add_default_controller_compatibility.up.sql @@ -0,0 +1,5 @@ +UPDATE "mods" + -- Assign Controller compatibility of Untested... + SET "compatibility" = jsonb_set(mods.compatibility, '{Controller}', '{"Note":"","State":"Untested"}'::jsonb) + -- ... to mods with pre-controller Compatibility already set + no leftover existing controller compatibility info + WHERE compatibility ? 'EA' and (NOT compatibility ? 'Controller'); diff --git a/migrations/sql/20260523001901_remove_toggle_network_use.down.sql b/migrations/sql/20260523001901_remove_toggle_network_use.down.sql new file mode 100644 index 00000000..2996ebfe --- /dev/null +++ b/migrations/sql/20260523001901_remove_toggle_network_use.down.sql @@ -0,0 +1,2 @@ +-- reverse: modify "mods" table +ALTER TABLE "mods" ADD COLUMN "toggle_network_use" boolean NOT NULL DEFAULT false; diff --git a/migrations/sql/20260523001901_remove_toggle_network_use.up.sql b/migrations/sql/20260523001901_remove_toggle_network_use.up.sql new file mode 100644 index 00000000..9c8c72ea --- /dev/null +++ b/migrations/sql/20260523001901_remove_toggle_network_use.up.sql @@ -0,0 +1,2 @@ +-- modify "mods" table +ALTER TABLE "mods" DROP COLUMN "toggle_network_use"; diff --git a/migrations/sql/atlas.sum b/migrations/sql/atlas.sum index e9b312c3..6eaf7251 100644 --- a/migrations/sql/atlas.sum +++ b/migrations/sql/atlas.sum @@ -1,81 +1,45 @@ -h1:NVXwUmNMPEOBFBSqgQGuw/OMarJOpSsxkE/8o1qQH3k= -000001_create_initial_tables.down.sql h1:QcXXwE8ir3PM3vZjQfBihY55WiuLYjN8pbbk/L6U+bs= -000001_create_initial_tables.up.sql h1:EfAqETefs7TW9BDVS4ukiB7wUFs+HQzVdc3qHhdAFd4= -000002_create_user_group_table.down.sql h1:uJjRbQ3H7yvPGNXLD5iSPmderEoWhCNGdsqN8yqBIRY= -000002_create_user_group_table.up.sql h1:vv+FICnFttPJjETbbP3zC20qjeaoD22GsTIhbiqAabI= -000003_add_last_version_date_mod_table.down.sql h1:7XgG/ar7HtfaelfZqAUay9tbGNuE9Zpr8HCXy43Bzho= -000003_add_last_version_date_mod_table.up.sql h1:XS+Wq0PxMje4FspHU0Vf+XMmRPUaNzlzUf2LwBaMJ44= -000004_add_more_oauth_options.down.sql h1:Nh6jm45ZwD5ILB9hD53n3E0FGJBJYiDcgeqKDNa2VEs= -000004_add_more_oauth_options.up.sql h1:1AEKJpNonhN2foWAQy3XEZ7o7Uzz/3VSlSp/HCx2syA= -000005_create_user_group_table.down.sql h1:eT2Sxdjl5PbCEYI2V+iS+ZWqOzBZmX8P022kuYSk8ys= -000005_create_user_group_table.up.sql h1:WiSmqlhOxkcjpe17HaoyHNgIm6R3ZjmDu3JcAig2qww= -000006_sml_versions_table.down.sql h1:9dF9n2s+VTs19tBIF2a/1j8fxmPPR9DACt+3AjFIWj4= -000006_sml_versions_table.up.sql h1:q5mTTHw6XUuHeEGwAQwTbU4XD99j34AiX+D4jL+OZhg= -000007_relationships.down.sql h1:RQK9FsUwEQpH/R1P8lDd1Kj5Qn9K2b7FSSI0kc9fv68= -000007_relationships.up.sql h1:1ssg/HrReOUFJ3fJT64ZUfJyNmn7iCKXNMOdPMEPUv8= -000008_version_dependencies.down.sql h1:lC7lLTXlHMcfHk0o9zdqVnPBwEN65jPziIRjhj69UMQ= -000008_version_dependencies.up.sql h1:tKOBn8Ce6V0ycMDCzGPtscaVElc0Lum4a8uXW9omYlw= -000009_bootstrap_versions_table.down.sql h1:w0K92Mbw7AXU56U5wJVeNE2GvftvQVIeITV2pvIjFCI= -000009_bootstrap_versions_table.up.sql h1:ERPrO2NWBqs6q2ttKNaI0rid3jYKZj6qR913jwzrlYg= -000010_add_version_dependency_optional.down.sql h1:y7DGX+fLPcd/YTHOSHkPleglQDxrNSoeDHwPLQHLMh0= -000010_add_version_dependency_optional.up.sql h1:YjPoFnJhBKD2fnGFhOFtfGEvC6eyXYAsUxsSlnAsDz4= -000011_add_mod_reference.down.sql h1:nr8I6DoIUWPuRDysXh6sOkfC3HpLm/a6UVCLrf0xPMc= -000011_add_mod_reference.up.sql h1:KZS/NMJoWieGP1jtJC51i/lF2a4jOiUWasQibCJ8p9o= -000012_add_version_metadata.down.sql h1:zCNOV0MM5mf636RYhQ7Yz9GKmB+OZ18DnWaIa1ENq5s= -000012_add_version_metadata.up.sql h1:tsd7mN8319cn7XGsdgCmVourq4jhbmuZ/Uapsu9rjJ8= -000013_add_version_mod_reference.down.sql h1:qUmWSHyAGz9AT/Jt2llZnVFADYN1hhgzLYwwuMiMKKo= -000013_add_version_mod_reference.up.sql h1:d65ZVSgh92pwIDrMIwGGJZ6v5fux7AQsrQr8G40iADk= -000014_add_version_split_hidden.down.sql h1:iZcK2FjO+I+xOYWYVF4BJ7ukmBGO0jPGlai2rgOH2P8= -000014_add_version_split_hidden.up.sql h1:3oVTcZfJBy4Fhl6rbD85VGRWKExxHb4ax3hYGbPpkY0= -000015_enable_trgm.down.sql h1:AJJmClZ48VYAJS+Q2rLrPlmIFWktOJInnqrh8SfUrn0= -000015_enable_trgm.up.sql h1:BuogUZkedrKpWLCyX+mtPJrK07tRRAvd30cBUq7T70k= -000016_add_user_groups_dates.down.sql h1:WuPC7OtC0GWeczc2J9ikGGjgnjeqY17iorFBe0tfHZg= -000016_add_user_groups_dates.up.sql h1:KEqV3mtM7RLoBJLxnW++X8dMK16ptMN6Iy/T0QLJZLE= -000017_add_version_indexes.down.sql h1:KiSzz+mDVeHRnUy43t9MdVAC84iXHan64sZNk18+Q/8= -000017_add_version_indexes.up.sql h1:7TqNLBwA+fRodGwo7mQjWm70kEa7yCzhN40WwAvWLE0= -000018_add_announcements.down.sql h1:deFRIsA9cNi5yPqRdzKk/5MvUsSPl8b7HUQnfhBZJvM= -000018_add_announcements.up.sql h1:RD9TFmGFPMiJW19jNwXJ9XjfoNtNcw4blzaLS3Rrvow= -000019_add_tags.down.sql h1:CStsWh+638pZQbFbEEwZoWC+XF5S/xHSJSjzdhP9ybU= -000019_add_tags.up.sql h1:18KalrGuJNFDjFmVlXRGNsEm768VymvCFzvNB0KKtB8= -000020_add_compatibility.down.sql h1:4v6wWre9XOs+z140mpTDuRueHb/6iOcS0ezn/LHf13o= -000020_add_compatibility.up.sql h1:XgJ1a1joBZtLnoVNt24FfmXrYXn0d8iZa61kJ4EvmZ0= -000021_add_mod_platform.down.sql h1:vtA2qkHxQfc+fHlvJ8KXjk4K0rVG4MPTopP1TSMbiPY= -000021_add_mod_platform.up.sql h1:mj/TKRTjPcpmyQdIasBteHe36JkLfrVphsyw9yZTApI= -000022_update_mod_targets.down.sql h1:CP8p7mS9QaWacjBS8CAUaT4Cy7/qWjMt7wBbVq1qjJI= -000022_update_mod_targets.up.sql h1:gUZTxiHhZ7taXyV+C3188GnmeBI/uI7uBqjD41UgQEs= -000023_migrate_versions_to_targets.down.sql h1:VInDE7go02NuOl82UHeibzgZJqxPhWgmvH5fylAWJTE= -000023_migrate_versions_to_targets.up.sql h1:vdqjCswMAe+rma9iHtXbFSQu9lD13TiXIRMYpDhmm1M= -000024_add_sml_engine_version.down.sql h1:2v4S22nL7rL6lCeqLijs62srTmhm+1bHvpbpercu+U4= -000024_add_sml_engine_version.up.sql h1:FOidt1bZzyltMGmZfQVbe+4uqU2l2C8RosedCZ8DN7o= -000025_add_tag_description.down.sql h1:UYOx8SSsOukHsbDJZWLoyeDkJk+2PwbqG07txsQ3N+Y= -000025_add_tag_description.up.sql h1:f5KICtSygQSqt6T1zwvskLGEN4IQ3LoUh+a9dMEHySU= -000026_add_rng.down.sql h1:gNRv048A3SjY4QpUfBB7Jssc0yye634QMBEIH/Yxo5E= -000026_add_rng.up.sql h1:UfiORAolITEGUqaiieZUbLo4ym9ucLD9j/13XsTHw0U= -000027_add_id_columns.down.sql h1:evCZZoTTRe7D6actv9T6RnMmmsa/H/mx+iuW+peFpiw= -000027_add_id_columns.up.sql h1:FLIEmyz5jO+QPCBGb/DNSW6QWTIgVUHb7CY712IFBZ4= -000028_increase_token_length_limit.down.sql h1:4AiEPXj1XVBAZs1DReN+sBOkDdAZye15yIVNKAg/KC4= -000028_increase_token_length_limit.up.sql h1:j8x0A/MQf/Sqv0ZqULcn3AMbQkH632EW7YfzlSIeezA= -000029_sml_as_mod.down.sql h1:+OMz5BAnf/sjjO6hcnWagU2OXmabMHYMXwHmSlZk2rg= -000029_sml_as_mod.up.sql h1:LjCzX2ua9e0QmxCsYL9Yj7Rf8toWut6KdbR32ROraU0= -000030_db_normalization.down.sql h1:eHNIHjteGV6/BRywsJoV/WNQS3EVl9KISGRCjgP4XAA= -000030_db_normalization.up.sql h1:siSIt2HFybFyxqzFNw/V12GSf58Id6aBcLnT5eg0YXs= -20240705180551_initial_transfer_to_atlas.down.sql h1:naUs2XWGUoYRCxS59USK+Ic6AolQnLX3BMPUHdxBUL8= -20240705180551_initial_transfer_to_atlas.up.sql h1:x51llUVQXurUJEu3S6QckS4S3FBPhrSCoTK5ay/okG8= -20240815141045_drop_version_stability_enum.down.sql h1:goFiSI0l6xzq5MSB0z7gH1pLWH/DxdqNtUU8tW5ff5g= -20240815141045_drop_version_stability_enum.up.sql h1:vPGVKylyRRIvaQwdlOtAdn6M6rpA2HrXxLXRf2aDO4Q= -20240818235330_index_fixes.down.sql h1:RbMhIdLIODCHYHWp/WxFpVBcmwKYedsudaVAuYHX+zY= -20240818235330_index_fixes.up.sql h1:xTw9pSSWkMcjZeIC+npdWT2nk+bvcjVMHHvyB2cDz5g= -20240819092347_user_indexes.down.sql h1:a+LhZ3NoCFBFWrBDcZAKjh8szFZsKWSLFd9LfsoDWbs= -20240819092347_user_indexes.up.sql h1:Ei9ma1Kd/88nB4QOKmSfjz+gSs/sW1rB7LM3+3bY71s= -20240823233610_add_mod_toggles.down.sql h1:6M1jiInRvHFBMTj2+NRdipO/z5oyn7qBYt4EIOTIqXg= -20240823233610_add_mod_toggles.up.sql h1:GuKMUrlGo1PppjX0uiw3OTyi2nziRI+o/LVtWfcjyLc= -20240826153722_add_thumbhash.down.sql h1:FN73gi6XvAkodHxFuE4oDU73FfchoyonlyroQTrwCW0= -20240826153722_add_thumbhash.up.sql h1:7a9d40zpOnKMamxW14ql3WFXiwXD4O6AjwMlAOVE7ik= -20240930114249_add_required_on_remote.down.sql h1:cbW5+35gg4R78zsjcqPO94e8X1QcYB9nPllGgtKGOr8= -20240930114249_add_required_on_remote.up.sql h1:NZJmXjtKEIHRhVlSSu9nKADo/8xhZAeckrf6NoZMmjk= -20241002191358_state_fix.down.sql h1:EnNOr58ajtIPS7BIgA6l60Jr8hE0ufCE6t0zFdvfnaw= -20241002191358_state_fix.up.sql h1:4bVw9fxEP9MrHBSYuRF3vFCgaWF79EUeacD3e+vSQR4= -20241003161005_create_virustotal_results_table.down.sql h1:BPUQ6UnWq6Inwz2GhZLoy4/QghPhClf1PlfZHis92P4= -20241003161005_create_virustotal_results_table.up.sql h1:mXMWj998hZ59bbkZYIbbyxU9foptzWuXHnlS2UuY4bY= -20241008092121_nullable_mod_logo.down.sql h1:vKZrz/FqaaQctvzrTR0EvQcyQ6ENWgTbcud7q2/NvnY= -20241008092121_nullable_mod_logo.up.sql h1:7ePponYitScS4NnMP+hRoEAKnvPPpbCHXMxilYzfmD8= +h1:2lekwbGGiJgJUcm+jn9XpVs09g3L7aSK5Z2OLF3MPW0= +000001_create_initial_tables.up.sql h1:D0NgABAZGONTBH9/T9MFCYkbw/LSee86lP4XsQYMx98= +000002_create_user_group_table.up.sql h1:+fOxjCFeU5GoVTO5cXzxWsMZtz2Qz3tal9vT5kdYuFI= +000003_add_last_version_date_mod_table.up.sql h1:t73i5gC2YrwlIcDn/MZmznGnArF0aA8dLYuA9NnVtbE= +000004_add_more_oauth_options.up.sql h1:UfHJiPBYFTjXHL17LQZ4ZgV/DVrghwDXNW8/RbODtaE= +000005_create_user_group_table.up.sql h1:EJZXV0bZqwqoVa6P6PmaolKRIYicgIsChRGggsiJ6lo= +000006_sml_versions_table.up.sql h1:5XDtXz2jQbdvo60fy5B5Ce8IjIv8ps3Ft24WhUCeJgg= +000007_relationships.up.sql h1:1WYFF1wqu0RkWwkWaNwb2A/oB9w9QPG5arrp0mT4WqE= +000008_version_dependencies.up.sql h1:N1z3vwv9inkKVLNsFif1At1UKAcAESxcfxJvkFOcSDs= +000009_bootstrap_versions_table.up.sql h1:w/1bXOeE/oXZCpWrBAZqHRZpeobofO2u4fYQvLu1oGg= +000010_add_version_dependency_optional.up.sql h1:9cHZYZ6TO05wvf0KCfl7+kZJLtLk3UDzF82AN1Hn7l0= +000011_add_mod_reference.up.sql h1:xGokeJASPuf5VnbehlA+fK8zHpevyeZG+r7u1z3tBrA= +000012_add_version_metadata.up.sql h1:redOIFgiRg6ggVs6tmxXvwxJS1xrCrqMdNFm/Buc5d0= +000013_add_version_mod_reference.up.sql h1:JgnH3EpwY4tulGYAlwVztW+eXG6Fh2/rHyDQm5mxfrk= +000014_add_version_split_hidden.up.sql h1:m8+Ai12K/ktPMD5vnKzTmf826pJfsICbQ1YcIruwO4U= +000015_enable_trgm.up.sql h1:K8lVS0W+1MVfuavMgRHplm8mTJowQojOj6zYux6QqHQ= +000016_add_user_groups_dates.up.sql h1:UyASdzLCBLFXhSFU5DkIznmy/2pIj8NeiL86oac0R7I= +000017_add_version_indexes.up.sql h1:n+BDJKAqvkp+z2faXsIgwNLwqMsSS307rKHCfUou4zQ= +000018_add_announcements.up.sql h1:X6OHBgP8fHQwcfRemioYD+CbipdZW5IzQiXwz2aCaK0= +000019_add_tags.up.sql h1:XStGF4N1GNGY2HTgY8YjpCTB7+V9mj431P5zSGJ3Ewo= +000020_add_compatibility.up.sql h1:Q4v3tPOH5xhFjxHkgxBz6zAsDieltsjM0s0WgrF9C8g= +000021_add_mod_platform.up.sql h1:Gzea7AIiEqsxWT6ti3ZtnzlwaHcx8U93uVY/+A9QJrc= +000022_update_mod_targets.up.sql h1:9VZrns7VPceKdEfhfchdbss3GBP+Ih7/SJjs+sA4UnM= +000023_migrate_versions_to_targets.up.sql h1:NytNFpV/ug5hxc6OM1RWvI+eJ3n1QFsERjWZ3dP3fig= +000024_add_sml_engine_version.up.sql h1:s1fzd/7sjyxtfFuh8bFbGCLTlZLjryMV6GHtJNnuTaY= +000025_add_tag_description.up.sql h1:7UdZZTJ70RJ+tA9M+EiVh+KqwwljYdPw27UQxrMedH8= +000026_add_rng.up.sql h1:y2Q8DUV27wx8/eKvTPduSU0RseM7wfCU79x1tvMmRY0= +000027_add_id_columns.up.sql h1:lILQ8le1eipNJuHuqKMaRK6RW8jBGpWOz8GDhiKEAIo= +000028_increase_token_length_limit.up.sql h1:U70DVHXY6f6vqwKxOQJzhnEZmYE5ML0+7Jc5Vh4tXb4= +000029_sml_as_mod.up.sql h1:e6Foai/N7l/zYvntn9+kNKGGPagGWYDaJ5X6XGse4lY= +000030_db_normalization.up.sql h1:rF0E/b2sF9jz3rzm1/1Ql0/TkMirgaj4w0jXTo65TMo= +20240705180551_initial_transfer_to_atlas.up.sql h1:ajYV7/WSvuMOYJDvHN0MY4z2VnX9ANJBIdV+ihZ9EGo= +20240815141045_drop_version_stability_enum.up.sql h1:ywxbAJ9lnwR6JOC+KRaW4r7nXRrLPx0J3INhD3dQlrw= +20240818235330_index_fixes.up.sql h1:YZvT7uroa6JFF+vRoufyn+rf/a/s45O05HTY/dv2Ai0= +20240819092347_user_indexes.up.sql h1:+QCDfycakdaavcoNA+zj0HwbzwfadE2pB3DpiezQS2g= +20240823233610_add_mod_toggles.up.sql h1:nTUp0VvrYxl9G92vjsP69Prgcwk4L4E4mehBcOH4sv0= +20240826153722_add_thumbhash.up.sql h1:1YhxpFNMlJQm3Xi42zD2XZVsJOPy4vNigFe1BP1E63c= +20240930114249_add_required_on_remote.up.sql h1:G3uEz4oAPvu+Q7kEVvZTiMYHMv6v/c+iImQGbQye+TQ= +20241002191358_state_fix.up.sql h1:PkJ9r2oq+nxMtZgWfjhPUvWhlGVLlEeky/1xqTrURjM= +20241003161005_create_virustotal_results_table.up.sql h1:u6cVcBPQnurXvy5pqbyzG6C4ThJ59v6dmhp5DgZBrBE= +20241008092121_nullable_mod_logo.up.sql h1:ZLscID5T67EWW7NVp95cXNyOadb2G5qTH0itfgoCUO4= +20250411023207_add_network_usage_disclosure.up.sql h1:4OhWjwDqv/mqsS+C8ZnVoKY85xN5yXUnwLvmehGY4qQ= +20260427195353_add_ai_disclosure.up.sql h1:BAWsfhEnYKxtLIcAKYsWsyxKLH8e23rW/Hdg/c3RuSo= +20260501041455_add_default_controller_compatibility.up.sql h1:Pw+SrN2XUpVQvS0pdmigo+RFybA3dTJyXaf2mS98z/w= +20260523001901_remove_toggle_network_use.up.sql h1:Upk2xn4VTkDtoHRaiiJDfIjGtR5i7KIRu55K75WxA1A= diff --git a/mise.lock b/mise.lock index f71ecba2..b195a74b 100644 --- a/mise.lock +++ b/mise.lock @@ -1,43 +1,202 @@ -[tools."aqua:minio/mc"] +# @generated - this file is auto-generated by `mise lock` https://mise.en.dev/dev-tools/mise-lock.html + +[[tools."aqua:minio/mc"]] version = "RELEASE.2025-04-08T15-39-49Z" backend = "aqua:minio/mc" -[tools."aqua:minio/mc".checksums] -"mc.RELEASE.2025-04-08T15-39-49Z" = "sha256:43d44d801a936e48390c8d2dc02c1c1cc1e973becbe71897f28ca06a9f456489" +[tools."aqua:minio/mc"."platforms.linux-arm64"] +checksum = "sha256:ac7448b6d3188fb94cea48c762d700584e7a0e467e21e1be4cfc823755c026eb" +url = "https://dl.min.io/client/mc/release/linux-arm64/archive/mc.RELEASE.2025-04-08T15-39-49Z" + +[tools."aqua:minio/mc"."platforms.linux-arm64-musl"] +checksum = "sha256:ac7448b6d3188fb94cea48c762d700584e7a0e467e21e1be4cfc823755c026eb" +url = "https://dl.min.io/client/mc/release/linux-arm64/archive/mc.RELEASE.2025-04-08T15-39-49Z" + +[tools."aqua:minio/mc"."platforms.linux-x64"] +checksum = "sha256:43d44d801a936e48390c8d2dc02c1c1cc1e973becbe71897f28ca06a9f456489" +url = "https://dl.min.io/client/mc/release/linux-amd64/archive/mc.RELEASE.2025-04-08T15-39-49Z" + +[tools."aqua:minio/mc"."platforms.linux-x64-musl"] +checksum = "sha256:43d44d801a936e48390c8d2dc02c1c1cc1e973becbe71897f28ca06a9f456489" +url = "https://dl.min.io/client/mc/release/linux-amd64/archive/mc.RELEASE.2025-04-08T15-39-49Z" + +[tools."aqua:minio/mc"."platforms.macos-arm64"] +checksum = "sha256:0ffce1b14eff6b3d410ed400ffbf0530ff4b11d8372115f1afa6f9b483ba5a40" +url = "https://dl.min.io/client/mc/release/darwin-arm64/archive/mc.RELEASE.2025-04-08T15-39-49Z" + +[tools."aqua:minio/mc"."platforms.macos-x64"] +checksum = "sha256:90407d70b69de8251731ed8cf644dd78836c49f1b3f559ae0c2b70dedeaf79aa" +url = "https://dl.min.io/client/mc/release/darwin-amd64/archive/mc.RELEASE.2025-04-08T15-39-49Z" -[tools.atlas] -version = "0.32.0" +[tools."aqua:minio/mc"."platforms.windows-x64"] +checksum = "sha256:45fb732d67cf26a1568c3750a1629d762c2f7b6990995cd02c4b1bb0c3de5770" +url = "https://dl.min.io/client/mc/release/windows-amd64/archive/mc.RELEASE.2025-04-08T15-39-49Z" + +[[tools.atlas]] +version = "1.2.0" backend = "aqua:ariga/atlas" -[tools.go] +[tools.atlas."platforms.linux-arm64"] +checksum = "sha256:b76308f558d50d006add507f3ab86afc1147644519dd327f7f5fac6d02d4f595" +url = "https://release.ariga.io/atlas/atlas-linux-arm64-v1.2.0" + +[tools.atlas."platforms.linux-arm64-musl"] +checksum = "sha256:b76308f558d50d006add507f3ab86afc1147644519dd327f7f5fac6d02d4f595" +url = "https://release.ariga.io/atlas/atlas-linux-arm64-v1.2.0" + +[tools.atlas."platforms.linux-x64"] +checksum = "sha256:c12b889e3349f0e5610aec32fe327e5a6911a0e472754a0c381c30c7c0630e88" +url = "https://release.ariga.io/atlas/atlas-linux-amd64-v1.2.0" + +[tools.atlas."platforms.linux-x64-musl"] +checksum = "sha256:c12b889e3349f0e5610aec32fe327e5a6911a0e472754a0c381c30c7c0630e88" +url = "https://release.ariga.io/atlas/atlas-linux-amd64-v1.2.0" + +[tools.atlas."platforms.macos-arm64"] +checksum = "sha256:c0d8443a603991c337341a303abf3812cb9f12d74d0ec0d585245735f18c1224" +url = "https://release.ariga.io/atlas/atlas-darwin-arm64-v1.2.0" + +[tools.atlas."platforms.macos-x64"] +checksum = "sha256:47f98e6f0d6a203f6c84e643f1ad99519fa8c2b5b59c177af3c449bd3ae0bb5a" +url = "https://release.ariga.io/atlas/atlas-darwin-amd64-v1.2.0" + +[tools.atlas."platforms.windows-x64"] +checksum = "sha256:5dbf3e7ec63306bce97904c6ad6ecb82633f0299b98c73987607204d551a80b1" +url = "https://release.ariga.io/atlas/atlas-windows-amd64-v1.2.0.exe" + +[[tools.go]] version = "1.24.4" backend = "core:go" -[tools.go.checksums] -"go1.24.4.linux-amd64.tar.gz" = "sha256:77e5da33bb72aeaef1ba4418b6fe511bc4d041873cbf82e5aa6318740df98717" +[tools.go."platforms.linux-arm64"] +checksum = "sha256:d5501ee5aca0f258d5fe9bfaed401958445014495dc115f202d43d5210b45241" +url = "https://dl.google.com/go/go1.24.4.linux-arm64.tar.gz" + +[tools.go."platforms.linux-arm64-musl"] +checksum = "sha256:d5501ee5aca0f258d5fe9bfaed401958445014495dc115f202d43d5210b45241" +url = "https://dl.google.com/go/go1.24.4.linux-arm64.tar.gz" + +[tools.go."platforms.linux-x64"] +checksum = "sha256:77e5da33bb72aeaef1ba4418b6fe511bc4d041873cbf82e5aa6318740df98717" +url = "https://dl.google.com/go/go1.24.4.linux-amd64.tar.gz" + +[tools.go."platforms.linux-x64-musl"] +checksum = "sha256:77e5da33bb72aeaef1ba4418b6fe511bc4d041873cbf82e5aa6318740df98717" +url = "https://dl.google.com/go/go1.24.4.linux-amd64.tar.gz" -[tools.go-junit-report] +[tools.go."platforms.macos-arm64"] +checksum = "sha256:27973684b515eaf461065054e6b572d9390c05e69ba4a423076c160165336470" +url = "https://dl.google.com/go/go1.24.4.darwin-arm64.tar.gz" + +[tools.go."platforms.macos-x64"] +checksum = "sha256:69bef555e114b4a2252452b6e7049afc31fbdf2d39790b669165e89525cd3f5c" +url = "https://dl.google.com/go/go1.24.4.darwin-amd64.tar.gz" + +[tools.go."platforms.windows-x64"] +checksum = "sha256:b751a1136cb9d8a2e7ebb22c538c4f02c09b98138c7c8bfb78a54a4566c013b1" +url = "https://dl.google.com/go/go1.24.4.windows-amd64.zip" + +[[tools.go-junit-report]] version = "2.1.0" -backend = "ubi:jstemmer/go-junit-report" +backend = "aqua:jstemmer/go-junit-report" + +[tools.go-junit-report."platforms.linux-x64"] +url = "https://github.com/jstemmer/go-junit-report/releases/download/v2.1.0/go-junit-report-v2.1.0-linux-amd64.tar.gz" + +[tools.go-junit-report."platforms.linux-x64-musl"] +url = "https://github.com/jstemmer/go-junit-report/releases/download/v2.1.0/go-junit-report-v2.1.0-linux-amd64.tar.gz" -[tools.golangci-lint] +[tools.go-junit-report."platforms.macos-arm64"] +url = "https://github.com/jstemmer/go-junit-report/releases/download/v2.1.0/go-junit-report-v2.1.0-darwin-arm64.tar.gz" + +[tools.go-junit-report."platforms.macos-x64"] +url = "https://github.com/jstemmer/go-junit-report/releases/download/v2.1.0/go-junit-report-v2.1.0-darwin-amd64.tar.gz" + +[tools.go-junit-report."platforms.windows-x64"] +url = "https://github.com/jstemmer/go-junit-report/releases/download/v2.1.0/go-junit-report-v2.1.0-windows-amd64.zip" + +[[tools.golangci-lint]] version = "2.1.6" backend = "aqua:golangci/golangci-lint" -[tools.golangci-lint.checksums] -"golangci-lint-2.1.6-linux-amd64.tar.gz" = "sha256:e55e0eb515936c0fbd178bce504798a9bd2f0b191e5e357768b18fd5415ee541" +[tools.golangci-lint."platforms.linux-arm64"] +checksum = "sha256:582eb73880f4408d7fb89f12b502d577bd7b0b63d8c681da92bb6b9d934d4363" +url = "https://github.com/golangci/golangci-lint/releases/download/v2.1.6/golangci-lint-2.1.6-linux-arm64.tar.gz" + +[tools.golangci-lint."platforms.linux-arm64-musl"] +checksum = "sha256:582eb73880f4408d7fb89f12b502d577bd7b0b63d8c681da92bb6b9d934d4363" +url = "https://github.com/golangci/golangci-lint/releases/download/v2.1.6/golangci-lint-2.1.6-linux-arm64.tar.gz" + +[tools.golangci-lint."platforms.linux-x64"] +checksum = "sha256:e55e0eb515936c0fbd178bce504798a9bd2f0b191e5e357768b18fd5415ee541" +url = "https://github.com/golangci/golangci-lint/releases/download/v2.1.6/golangci-lint-2.1.6-linux-amd64.tar.gz" + +[tools.golangci-lint."platforms.linux-x64-musl"] +checksum = "sha256:e55e0eb515936c0fbd178bce504798a9bd2f0b191e5e357768b18fd5415ee541" +url = "https://github.com/golangci/golangci-lint/releases/download/v2.1.6/golangci-lint-2.1.6-linux-amd64.tar.gz" -[tools.protoc] +[tools.golangci-lint."platforms.macos-arm64"] +checksum = "sha256:90783fa092a0f64a4f7b7d419f3da1f53207e300261773babe962957240e9ea6" +url = "https://github.com/golangci/golangci-lint/releases/download/v2.1.6/golangci-lint-2.1.6-darwin-arm64.tar.gz" + +[tools.golangci-lint."platforms.macos-x64"] +checksum = "sha256:e091107c4ca7e283902343ba3a09d14fb56b86e071effd461ce9d67193ef580e" +url = "https://github.com/golangci/golangci-lint/releases/download/v2.1.6/golangci-lint-2.1.6-darwin-amd64.tar.gz" + +[tools.golangci-lint."platforms.windows-x64"] +checksum = "sha256:fd7298019c76cf414ab083491f87f6c0a3e537ed6d727d6ff9135e503d6f9c32" +url = "https://github.com/golangci/golangci-lint/releases/download/v2.1.6/golangci-lint-2.1.6-windows-amd64.zip" + +[[tools.protoc]] version = "31.1" backend = "aqua:protocolbuffers/protobuf/protoc" -[tools.protoc.checksums] -"protoc-31.1-linux-x86_64.zip" = "sha256:96553041f1a91ea0efee963cb16f462f5985b4d65365f3907414c360044d8065" +[tools.protoc."platforms.linux-arm64"] +url = "https://github.com/protocolbuffers/protobuf/releases/download/v31.1/protoc-31.1-linux-aarch_64.zip" + +[tools.protoc."platforms.linux-arm64-musl"] +url = "https://github.com/protocolbuffers/protobuf/releases/download/v31.1/protoc-31.1-linux-aarch_64.zip" + +[tools.protoc."platforms.linux-x64"] +url = "https://github.com/protocolbuffers/protobuf/releases/download/v31.1/protoc-31.1-linux-x86_64.zip" -[tools.protoc-gen-go] +[tools.protoc."platforms.linux-x64-musl"] +url = "https://github.com/protocolbuffers/protobuf/releases/download/v31.1/protoc-31.1-linux-x86_64.zip" + +[tools.protoc."platforms.macos-arm64"] +url = "https://github.com/protocolbuffers/protobuf/releases/download/v31.1/protoc-31.1-osx-aarch_64.zip" + +[tools.protoc."platforms.macos-x64"] +url = "https://github.com/protocolbuffers/protobuf/releases/download/v31.1/protoc-31.1-osx-x86_64.zip" + +[tools.protoc."platforms.windows-x64"] +url = "https://github.com/protocolbuffers/protobuf/releases/download/v31.1/protoc-31.1-win64.zip" + +[[tools.protoc-gen-go]] version = "1.36.6" backend = "aqua:protocolbuffers/protobuf-go/protoc-gen-go" -[tools.protoc-gen-go-grpc] +[tools.protoc-gen-go."platforms.linux-arm64"] +url = "https://github.com/protocolbuffers/protobuf-go/releases/download/v1.36.6/protoc-gen-go.v1.36.6.linux.arm64.tar.gz" + +[tools.protoc-gen-go."platforms.linux-arm64-musl"] +url = "https://github.com/protocolbuffers/protobuf-go/releases/download/v1.36.6/protoc-gen-go.v1.36.6.linux.arm64.tar.gz" + +[tools.protoc-gen-go."platforms.linux-x64"] +url = "https://github.com/protocolbuffers/protobuf-go/releases/download/v1.36.6/protoc-gen-go.v1.36.6.linux.amd64.tar.gz" + +[tools.protoc-gen-go."platforms.linux-x64-musl"] +url = "https://github.com/protocolbuffers/protobuf-go/releases/download/v1.36.6/protoc-gen-go.v1.36.6.linux.amd64.tar.gz" + +[tools.protoc-gen-go."platforms.macos-arm64"] +url = "https://github.com/protocolbuffers/protobuf-go/releases/download/v1.36.6/protoc-gen-go.v1.36.6.darwin.arm64.tar.gz" + +[tools.protoc-gen-go."platforms.macos-x64"] +url = "https://github.com/protocolbuffers/protobuf-go/releases/download/v1.36.6/protoc-gen-go.v1.36.6.darwin.amd64.tar.gz" + +[tools.protoc-gen-go."platforms.windows-x64"] +url = "https://github.com/protocolbuffers/protobuf-go/releases/download/v1.36.6/protoc-gen-go.v1.36.6.windows.amd64.zip" + +[[tools.protoc-gen-go-grpc]] version = "1.5.1" backend = "aqua:grpc/grpc-go/protoc-gen-go-grpc" diff --git a/mise.toml b/mise.toml index 43dce3f0..19068609 100644 --- a/mise.toml +++ b/mise.toml @@ -1,6 +1,6 @@ [tools] "aqua:minio/mc" = "RELEASE.2025-04-08T15-39-49Z" -atlas = "0.32.0" +atlas = "1.2.0" go = "1.24.4" go-junit-report = "2.1.0" golangci-lint = "2.1.6" @@ -8,49 +8,66 @@ protoc = "31.1" protoc-gen-go = "1.36.6" protoc-gen-go-grpc = "1.5.1" +[settings] +lockfile = true + +# File-based tasks are in the .mise/tasks/ directory + +[tasks.setup] +description = "Start docker containers and setup minio access. -ci flag uses plain output for ease of reading CI logs" +run= "mise run setup_linux" +run_windows = "mise run setup_windows" + [tasks.api] +description = "Run the API server. Make sure containers are running via `mise run setup` first." run = "go run cmd/api/serve.go" [tasks.test] +description = "Run all tests (with verbose output, for CI)" run = "go test -parallel 1 -v -timeout 1h ./..." -# Run the tests without the verbose flag so it is easier to parse the output for local development [tasks.localtest] +description = "Run all tests (without the verbose flag, so it's easier to parse the output for local development)" run = "go test -parallel 1 -timeout 1h ./..." [tasks.coverage] +description = "TODO @Vilsol description? Run all tests and output coverage details" run = "go test -v -coverprofile=coverage.txt -covermode=atomic -coverpkg=./... -p 1 -timeout 1h ./..." [tasks.test_coverage_junit] +description = "TODO @Vilsol description? Run all tests and produce a JUnit coverage report in an XML" run = "go test -v -coverprofile=coverage.txt -covermode=atomic -coverpkg=./... -p 1 -timeout 1h ./... 2>&1 | go-junit-report -iocopy -set-exit-code -out junit.xml" [tasks.migrate_hash] -run = "atlas migrate hash --dir \"file://migrations/sql?format=golang-migrate\"" +description = "Recalculate Atlas migration hashes (see https://atlasgo.io/versioned/new#recalculating-the-directory-hash)" +run = 'atlas migrate hash --dir file://migrations/sql?format=golang-migrate' [tasks.generate] +description = "Update Golang generated code" run = "go generate -tags tools -x ./..." -[tasks.setup] -run = [ - "docker compose --file docker-compose-dev.yml up --detach --wait && sleep 5", - "mc alias set local http://localhost:9000 minio minio123", - "mc admin user svcacct remove local/ REPLACE_ME_KEY --dp || echo It is okay for this REMOVE command to fail if the account does not exist", - "mc admin user svcacct add local minio --access-key REPLACE_ME_KEY --secret-key REPLACE_ME_SECRET", - "mc anonymous set public local/smr" -] -run_windows = [ - "docker compose --file docker-compose-dev.yml up --detach --wait && timeout /t 5", - "mc alias set local http://localhost:9000 minio minio123", - "mc admin user svcacct remove local/ REPLACE_ME_KEY --dp || echo It is okay for this REMOVE command to fail if the account does not exist", - "mc admin user svcacct add local minio --access-key REPLACE_ME_KEY --secret-key REPLACE_ME_SECRET", - "mc anonymous set public local/smr" -] - [tasks.teardown] +description = "Stop and destroy docker containers. Volumes are preserved." run = "docker compose --file docker-compose-dev.yml down" [tasks.lint] +description = "Check for linting issues" run = "golangci-lint run" [tasks.format] +description = "Try to automatically fix linting issues" run = "golangci-lint run --fix" + +[tasks.migrate_diff] +description = "Use Atlas to attempt to automatically create SQL migration files (see https://atlasgo.io/versioned/diff)" +run= "mise run migrate_diff_linux" +run_windows = "mise run migrate_diff_windows" + +[tasks.migrate_new] +description = "Use Atlas to create a new manual SQL migration file (see https://atlasgo.io/versioned/new)" +run= "mise run migrate_new_linux" +run_windows = "mise run migrate_new_windows" + +[tasks.make_paseto_keys] +description = "Generates PASETO keys for initial setup, put them in your config.json" +run = "go run cmd/paseto/main.go" diff --git a/schemas/compatibility.graphql b/schemas/compatibility.graphql index bd5f6c93..ba168a4c 100644 --- a/schemas/compatibility.graphql +++ b/schemas/compatibility.graphql @@ -14,17 +14,37 @@ input CompatibilityInput { note: String } +enum ControllerCompatibilityState { + Untested + Unsupported + Partial + Implicit + Supported +} + +type ControllerCompatibility { + state: ControllerCompatibilityState! + note: String +} + +input ControllerCompatibilityInput { + state: ControllerCompatibilityState! + note: String +} + type CompatibilityInfo { EA: Compatibility! EXP: Compatibility! + Controller: ControllerCompatibility! } input CompatibilityInfoInput { EA: CompatibilityInput! EXP: CompatibilityInput! + Controller: ControllerCompatibilityInput! } extend type Mutation { updateModCompatibility(modId: ModID!, compatibility: CompatibilityInfoInput!): Boolean! @canEditModCompatibility(field: "modId") @isLoggedIn updateMultipleModCompatibilities(modIDs: [ModID!]!, compatibility: CompatibilityInfoInput!): Boolean! @canEditModCompatibility @isLoggedIn -} \ No newline at end of file +} diff --git a/schemas/mod.graphql b/schemas/mod.graphql index 3086afc2..3f80db48 100755 --- a/schemas/mod.graphql +++ b/schemas/mod.graphql @@ -15,6 +15,12 @@ enum ModFields { search } +enum AIUseDisclosureType { + no_ai_usage + ai_usage + runtime_ai_usage +} + type Mod { id: ModID! name: String! @@ -36,7 +42,8 @@ type Mod { hidden: Boolean! tags: [Tag!] compatibility: CompatibilityInfo - toggle_network_use: Boolean! + network_use_disclosure: String + ai_use_disclosure: AIUseDisclosureInfo toggle_explicit_content: Boolean! authors: [UserMod!]! @@ -61,6 +68,11 @@ type ModVersion { versions: [Version!]! } +type AIUseDisclosureInfo { + disclosure_type: AIUseDisclosureType! + message: String +} + ### Inputs input ModFilter { @@ -84,7 +96,6 @@ input NewMod { mod_reference: ModReference! hidden: Boolean tagIDs: [TagID!] - toggle_network_use: Boolean toggle_explicit_content: Boolean } @@ -99,7 +110,8 @@ input UpdateMod { hidden: Boolean tagIDs: [TagID!] compatibility: CompatibilityInfoInput - toggle_network_use: Boolean + network_use_disclosure: String + ai_use_disclosure: AIUseDisclosureInput toggle_explicit_content: Boolean } @@ -113,6 +125,11 @@ input ModVersionConstraint { version: String! } +input AIUseDisclosureInput { + disclosure_type: AIUseDisclosureType! + message: String +} + ### Queries extend type Query { diff --git a/tests/ai_use_disclosure_test.go b/tests/ai_use_disclosure_test.go new file mode 100644 index 00000000..809c87ac --- /dev/null +++ b/tests/ai_use_disclosure_test.go @@ -0,0 +1,131 @@ +package tests + +import ( + "testing" + + "github.com/MarvinJWendt/testza" + + "github.com/satisfactorymodding/smr-api/config" + "github.com/satisfactorymodding/smr-api/db" + "github.com/satisfactorymodding/smr-api/generated" +) + +func init() { + config.SetConfigDir("../") + db.EnableDebug() +} + +func TestAiDisclosure(t *testing.T) { + ctx, client, stop := setup() + defer stop() + + token, _, err := makeUser(ctx) + testza.AssertNoError(t, err) + + // Creating a mod without an AI disclosure succeeds and there is no disclosure information + createRequest := authRequest(`mutation ($mod_reference: ModReference!) { + createMod(mod: { + name: "AI Disclosure Mod", + short_description: "Testing AI disclosure functionality", + full_description: "Lorem ipsum dolor sit amet", + mod_reference: $mod_reference + }) { + id + name + mod_reference + } + }`, token) + createRequest.Var("mod_reference", "aiDisclosureMod") + + var createResponse struct { + CreateMod generated.Mod + } + testza.AssertNoError(t, client.Run(ctx, createRequest, &createResponse)) + testza.AssertNotNil(t, createResponse.CreateMod) + testza.AssertNil(t, createResponse.CreateMod.AiUseDisclosure) + modID := createResponse.CreateMod.ID + + // Empty string disclosure message is not allowed + failedUpdateEmptyString := authRequest(`mutation ($id: ModID!, $ai_use_disclosure: AIUseDisclosureInput) { + updateMod( + modId: $id + mod: { + ai_use_disclosure: $ai_use_disclosure, + } + ) { + id + ai_use_disclosure { + disclosure_type + message + } + } + }`, token) + failedUpdateEmptyString.Var("id", modID) + emptyString := "" + failedUpdateEmptyString.Var("ai_use_disclosure", generated.AIUseDisclosureInput{ + DisclosureType: generated.AIUseDisclosureTypeAiUsage, + Message: &emptyString, + }) + + var failedEmptyStringResponse struct { + UpdateMod generated.Mod + } + err = client.Run(ctx, failedUpdateEmptyString, &failedEmptyStringResponse) + testza.AssertNotNil(t, err) + testza.AssertContains(t, err.Error(), "you need to input a disclosure message when disclosing AI usage") + + // Assigning a valid AI disclosure succeeds and updates the mod's disclosure information + disclosureRequest := authRequest(`mutation ($id: ModID!, $ai_use_disclosure: AIUseDisclosureInput) { + updateMod( + modId: $id + mod: { + ai_use_disclosure: $ai_use_disclosure, + } + ) { + id + ai_use_disclosure { + disclosure_type + message + } + } + }`, token) + disclosureMessage := "This mod uses AI for testing purposes" + disclosureRequest.Var("id", modID) + disclosureRequest.Var("ai_use_disclosure", generated.AIUseDisclosureInput{ + DisclosureType: generated.AIUseDisclosureTypeAiUsage, + Message: &disclosureMessage, + }) + + var updateResponse struct { + UpdateMod generated.Mod + } + testza.AssertNoError(t, client.Run(ctx, disclosureRequest, &updateResponse)) + testza.AssertNotNil(t, updateResponse.UpdateMod.AiUseDisclosure.DisclosureType) + testza.AssertEqual(t, generated.AIUseDisclosureTypeAiUsage, updateResponse.UpdateMod.AiUseDisclosure.DisclosureType) + testza.AssertEqual(t, &disclosureMessage, updateResponse.UpdateMod.AiUseDisclosure.Message) + + // Trying to unassign the disclosure is not allowed + failedUpdateUndisclosed := authRequest(`mutation ($id: ModID!, $ai_use_disclosure: AIUseDisclosureInput) { + updateMod( + modId: $id + mod: { + ai_use_disclosure: $ai_use_disclosure, + } + ) { + id + ai_use_disclosure { + disclosure_type + message + } + } + }`, token) + failedUpdateUndisclosed.Var("id", modID) + failedUpdateUndisclosed.Var("ai_use_disclosure", nil) + + var failedUpdateUndisclosedResponse struct { + UpdateMod generated.Mod + } + err = client.Run(ctx, failedUpdateUndisclosed, &failedUpdateUndisclosedResponse) + testza.AssertNotNil(t, err) + testza.AssertContains(t, err.Error(), "this mod already has an AI use disclosure, and thus it cannot be cleared") +} diff --git a/tests/mod_test.go b/tests/mod_test.go index ce7322dd..2faa7c41 100644 --- a/tests/mod_test.go +++ b/tests/mod_test.go @@ -109,7 +109,6 @@ func TestMods(t *testing.T) { full_description: "Lorem ipsum dolor sit amet", mod_reference: $mod_reference, tagIDs: $tags, - toggle_network_use: true, toggle_explicit_content: true }) { id @@ -147,7 +146,6 @@ func TestMods(t *testing.T) { last_version_date mod_reference hidden - toggle_network_use toggle_explicit_content tags { id @@ -194,7 +192,6 @@ func TestMods(t *testing.T) { testza.AssertEqual(t, &fullDescription, queryResponse.GetMod.FullDescription) testza.AssertEqual(t, modReference, queryResponse.GetMod.ModReference) testza.AssertEqual(t, userID, queryResponse.GetMod.CreatorID) - testza.AssertTrue(t, queryResponse.GetMod.ToggleNetworkUse) testza.AssertTrue(t, queryResponse.GetMod.ToggleExplicitContent) }) @@ -260,7 +257,6 @@ func TestMods(t *testing.T) { name: "Foo Bar", tagIDs: $tags, authors: $authors, - toggle_network_use: false, toggle_explicit_content: false, compatibility: { EA: { @@ -271,6 +267,10 @@ func TestMods(t *testing.T) { note: "World", state: Works } + Controller: { + note: "Foobar" + state: Partial + } } } ) { @@ -327,7 +327,6 @@ func TestMods(t *testing.T) { testza.AssertEqual(t, &fullDescription, queryResponse.GetMods.Mods[1].FullDescription) testza.AssertEqual(t, modReference, queryResponse.GetMods.Mods[1].ModReference) testza.AssertEqual(t, userID, queryResponse.GetMods.Mods[1].CreatorID) - testza.AssertFalse(t, queryResponse.GetMods.Mods[1].ToggleNetworkUse) testza.AssertFalse(t, queryResponse.GetMods.Mods[1].ToggleExplicitContent) }) diff --git a/tests/sml_versions_test.go b/tests/sml_versions_test.go index 7a6be455..ba9c2011 100644 --- a/tests/sml_versions_test.go +++ b/tests/sml_versions_test.go @@ -73,9 +73,12 @@ func TestSMLVersions(t *testing.T) { smlModID = getResponse.GetModByReference.ID }) + t.Run("Set Disclosures", func(t *testing.T) { + setModDisclosures(ctx, t, client, smlModID, token) + }) + var versionID string var versionDate time.Time - t.Run("Create", func(t *testing.T) { t.Run("Create Version", func(t *testing.T) { createRequest := authRequest(`mutation CreateVersion($mod_id: ModID!) { diff --git a/tests/utils.go b/tests/utils.go index e16f841b..c71fd938 100644 --- a/tests/utils.go +++ b/tests/utils.go @@ -6,7 +6,10 @@ import ( "fmt" "log/slog" "sync" + "testing" + gqlgen "github.com/99designs/gqlgen/graphql" + "github.com/MarvinJWendt/testza" "github.com/Vilsol/slox" "github.com/google/uuid" "github.com/machinebox/graphql" @@ -15,6 +18,7 @@ import ( smr "github.com/satisfactorymodding/smr-api/api" "github.com/satisfactorymodding/smr-api/auth" "github.com/satisfactorymodding/smr-api/db" + "github.com/satisfactorymodding/smr-api/generated" "github.com/satisfactorymodding/smr-api/redis" "github.com/satisfactorymodding/smr-api/util" "github.com/satisfactorymodding/smr-api/validation" @@ -124,6 +128,26 @@ func makeUser(ctx context.Context) (string, string, error) { return session.Token, user.ID, nil } +func setModDisclosures(ctx context.Context, t *testing.T, client *graphql.Client, modID string, token string) { + updateDisclosure := authRequest(`mutation UpdateMod($mod_id: ModID!, $mod: UpdateMod!) { + updateMod(modId: $mod_id, mod: $mod) { + id + } + }`, token) + updateDisclosure.Var("mod_id", modID) + valueOfNoNetworkUse := "" + updateDisclosure.Var("mod", generated.UpdateMod{ + AiUseDisclosure: gqlgen.OmittableOf(&generated.AIUseDisclosureInput{ + DisclosureType: generated.AIUseDisclosureTypeNoAiUsage, + }), + NetworkUseDisclosure: gqlgen.OmittableOf(&valueOfNoNetworkUse), + }) + var updateResponse struct { + UpdateMod *generated.Mod + } + testza.AssertNoError(t, client.Run(ctx, updateDisclosure, &updateResponse)) +} + func authRequest(q string, token string) *graphql.Request { req := graphql.NewRequest(q) req.Header.Set("Authorization", token) diff --git a/tests/version_test.go b/tests/version_test.go index bef680fa..85914fdb 100644 --- a/tests/version_test.go +++ b/tests/version_test.go @@ -57,8 +57,28 @@ func TestSameVersion(t *testing.T) { ctx, client, stop := setup() defer stop() - modID := RunVersionTest(ctx, t, client, "testdata/DuplicateMod.smod", false, "DuplicateMod", "", "") - RunVersionTest(ctx, t, client, "testdata/DuplicateMod.smod", false, "DuplicateMod", modID, "this mod already has a version with this name") + modID, _, _ := RunVersionTest(ctx, t, client, "testdata/DuplicateMod.smod", false, "DuplicateMod", "", "", "") + RunVersionTest(ctx, t, client, "testdata/DuplicateMod.smod", false, "DuplicateMod", modID, "this mod already has a published version with this name", "") +} + +func TestDeletedVersionSemverReuse(t *testing.T) { + ctx, client, stop := setup() + defer stop() + + modID, versionID, token := RunVersionTest(ctx, t, client, "testdata/DuplicateMod.smod", false, "DuplicateMod", "", "", "") + + deleteRequest := authRequest(`mutation DeleteVersion($versionId: VersionID!) { + deleteVersion(versionId: $versionId) + }`, token) + deleteRequest.Var("versionId", versionID) + + var deleteResponse struct { + DeleteVersion bool + } + testza.AssertNoError(t, client.Run(ctx, deleteRequest, &deleteResponse)) + testza.AssertTrue(t, deleteResponse.DeleteVersion) + + RunVersionTest(ctx, t, client, "testdata/DuplicateMod.smod", false, "DuplicateMod", modID, "reusing the version name of a deleted mod version is not allowed", token) } func TestModWithMissingDependency(t *testing.T) { @@ -72,20 +92,24 @@ func TestModMalformedJSON(t *testing.T) { func RunVersionTestWrapper(t *testing.T, modFilePath string, executeVirusCheck bool, modReference string, expectError string) { ctx, client, stop := setup() defer stop() - RunVersionTest(ctx, t, client, modFilePath, executeVirusCheck, modReference, "", expectError) + RunVersionTest(ctx, t, client, modFilePath, executeVirusCheck, modReference, "", expectError, "") } -func RunVersionTest(ctx context.Context, t *testing.T, client *graphql.Client, modFilePath string, executeVirusCheck bool, modReference string, reuseModID string, expectError string) string { +func RunVersionTest(ctx context.Context, t *testing.T, client *graphql.Client, modFilePath string, executeVirusCheck bool, modReference string, reuseModID string, expectError string, providedToken string) (string, string, string) { if executeVirusCheck && (!viper.IsSet("virustotal.key") || viper.GetString("virustotal.key") == "") { println("missing virustotal key from config, skipping") t.SkipNow() - return "" + return "", "", "" } viper.Set("skip-virus-check", !executeVirusCheck) - token, _, err := makeUser(ctx) - testza.AssertNoError(t, err) + token := providedToken + if providedToken == "" { + var err error + token, _, err = makeUser(ctx) + testza.AssertNoError(t, err) + } modID := reuseModID if modID == "" { @@ -127,6 +151,10 @@ func RunVersionTest(ctx context.Context, t *testing.T, client *graphql.Client, m modID = createResponse.CreateMod.ID }) + + t.Run("Set Disclosures", func(t *testing.T) { + setModDisclosures(ctx, t, client, modID, token) + }) } var uploadID string @@ -394,5 +422,5 @@ func RunVersionTest(ctx context.Context, t *testing.T, client *graphql.Client, m }) } - return modID + return modID, versionID, token } diff --git a/tools.go b/tools.go index 4e46c1af..086fa2bd 100644 --- a/tools.go +++ b/tools.go @@ -11,11 +11,11 @@ import ( // go generate -tags tools -x ./... +//go:generate go run tools.go //go:generate protoc -I./proto --go_out=./proto --go_opt=paths=source_relative --go-grpc_out=./proto --go-grpc_opt=paths=source_relative proto/parser/parser.proto //go:generate go tool github.com/99designs/gqlgen generate //go:generate go tool github.com/jmattheis/goverter/cmd/goverter gen -g wrapErrors -g ignoreUnexported ./conversion //go:generate go tool github.com/swaggo/swag/cmd/swag init --generalInfo cmd/api/serve.go --output ./generated/docs -//go:generate go run tools.go func main() { generateEnt() diff --git a/util/db.go b/util/db.go index 8c24e4d2..2bde0df2 100644 --- a/util/db.go +++ b/util/db.go @@ -17,11 +17,17 @@ func (s Stability) Values() []string { } type CompatibilityInfo struct { - Ea Compatibility `gorm:"type:compatibility" json:"EA"` - Exp Compatibility `gorm:"type:compatibility" json:"EXP"` + Ea Compatibility `gorm:"type:compatibility" json:"EA"` + Exp Compatibility `gorm:"type:compatibility" json:"EXP"` + Controller Compatibility `gorm:"type:compatibility" json:"Controller"` } type Compatibility struct { State string Note string } + +type AIUseDisclosureInfo struct { + DisclosureType string `gorm:"type:string" json:"DisclosureType"` + Message string `gorm:"type:string" json:"Message"` +} diff --git a/workflows/versionupload/extract_mod_info.go b/workflows/versionupload/extract_mod_info.go index 6663fce8..1e4b6c60 100644 --- a/workflows/versionupload/extract_mod_info.go +++ b/workflows/versionupload/extract_mod_info.go @@ -11,6 +11,8 @@ import ( "go.temporal.io/sdk/temporal" "github.com/satisfactorymodding/smr-api/db" + "github.com/satisfactorymodding/smr-api/db/schema" + "github.com/satisfactorymodding/smr-api/generated/ent" version2 "github.com/satisfactorymodding/smr-api/generated/ent/version" "github.com/satisfactorymodding/smr-api/util" "github.com/satisfactorymodding/smr-api/validation" @@ -51,15 +53,21 @@ func (*A) ExtractModInfoActivity(ctx context.Context, args ExtractModInfoArgs) ( return nil, temporal.NewNonRetryableApplicationError("multi-target mods are not allowed", "fatal", nil) } - count, err := db.From(ctx).Version.Query(). - Where(version2.ModID(mod.ID), version2.Version(modInfo.Version)). - Count(ctx) + existingPotentiallySoftDeletedVersion, err := db.From(ctx).Version.Query(). + Where( + version2.ModID(mod.ID), + version2.Version(modInfo.Version), + ).Only(schema.SkipSoftDelete(ctx)) if err != nil { - return nil, temporal.NewNonRetryableApplicationError("database error", "fatal", err) - } - - if count > 0 { - return nil, temporal.NewNonRetryableApplicationError("this mod already has a version with this name", "fatal", nil) + if !ent.IsNotFound(err) { + return nil, temporal.NewNonRetryableApplicationError("database error", "fatal", err) + } + // 'Not Found' is an okay case (no version with the same version number) + } else { + if existingPotentiallySoftDeletedVersion.DeletedAt.IsZero() { + return nil, temporal.NewNonRetryableApplicationError("this mod already has a published version with this name", "fatal", nil) + } + return nil, temporal.NewNonRetryableApplicationError("reusing the version name of a deleted mod version is not allowed", "fatal", nil) } // Allow only new 5 versions per 24h