mirror of
https://github.com/wizarrrr/wizarr.git
synced 2026-07-31 07:17:10 -04:00
Default wizard steps were duplicated once per server instance of the same type (e.g., 2 Plex servers → 6 steps instead of 3). Deduplicate the server type list before loading steps so each type's steps appear only once. Also add the missing wizard_bundle_id parameter to the invitation creation API, matching the existing web UI capability. Closes #1219
269 lines
8.5 KiB
Python
269 lines
8.5 KiB
Python
"""OpenAPI models for Flask-RESTX API documentation."""
|
|
|
|
from flask_restx import fields
|
|
|
|
from app.extensions import api
|
|
|
|
# Status Models
|
|
status_model = api.model(
|
|
"Status",
|
|
{
|
|
"users": fields.Integer(description="Total number of users"),
|
|
"invites": fields.Integer(description="Total number of invitations"),
|
|
"pending": fields.Integer(description="Number of pending invitations"),
|
|
"expired": fields.Integer(description="Number of expired invitations"),
|
|
},
|
|
)
|
|
|
|
# Admin Models
|
|
admin_model = api.model(
|
|
"Admin",
|
|
{
|
|
"id": fields.Integer(description="Admin ID"),
|
|
"username": fields.String(description="Admin username"),
|
|
"passkeys": fields.Integer(description="Number of passkeys for this admin"),
|
|
"created": fields.DateTime(description="Creation date (ISO format)"),
|
|
},
|
|
)
|
|
|
|
admin_list_model = api.model(
|
|
"AdminList",
|
|
{
|
|
"admins": fields.List(fields.Nested(admin_model)),
|
|
"count": fields.Integer(description="Total number of admins"),
|
|
},
|
|
)
|
|
|
|
# User Models
|
|
user_model = api.model(
|
|
"User",
|
|
{
|
|
"id": fields.Integer(description="User ID"),
|
|
"username": fields.String(description="Username"),
|
|
"email": fields.String(description="Email address"),
|
|
"server": fields.String(description="Media server name"),
|
|
"server_type": fields.String(
|
|
description="Type of media server (plex, jellyfin, etc.)"
|
|
),
|
|
"expires": fields.DateTime(description="Expiration date (ISO format)"),
|
|
"created_at": fields.DateTime(description="Creation date (ISO format)"),
|
|
},
|
|
)
|
|
|
|
user_list_model = api.model(
|
|
"UserList",
|
|
{
|
|
"users": fields.List(fields.Nested(user_model)),
|
|
"count": fields.Integer(description="Total number of users"),
|
|
},
|
|
)
|
|
|
|
user_extend_request = api.model(
|
|
"UserExtendRequest",
|
|
{
|
|
"days": fields.Integer(
|
|
description="Number of days to extend (default: 30)", default=30
|
|
),
|
|
},
|
|
)
|
|
|
|
user_extend_response = api.model(
|
|
"UserExtendResponse",
|
|
{
|
|
"message": fields.String(description="Success message"),
|
|
"new_expiry": fields.DateTime(description="New expiration date"),
|
|
},
|
|
)
|
|
|
|
user_update_expiry_request = api.model(
|
|
"UserUpdateExpiryRequest",
|
|
{
|
|
"expires": fields.DateTime(
|
|
description="New expiration date (ISO format). Use null for unlimited access.",
|
|
required=False,
|
|
allow_null=True,
|
|
),
|
|
},
|
|
)
|
|
|
|
user_update_expiry_response = api.model(
|
|
"UserUpdateExpiryResponse",
|
|
{
|
|
"message": fields.String(description="Success message"),
|
|
"new_expiry": fields.DateTime(
|
|
description="New expiration date (null for unlimited)",
|
|
allow_null=True,
|
|
),
|
|
},
|
|
)
|
|
|
|
# Invitation Models
|
|
invitation_model = api.model(
|
|
"Invitation",
|
|
{
|
|
"id": fields.Integer(description="Invitation ID"),
|
|
"code": fields.String(description="Invitation code"),
|
|
"url": fields.String(description="Ready-to-use invitation URL"),
|
|
"status": fields.String(
|
|
description="Invitation status", enum=["pending", "used", "expired"]
|
|
),
|
|
"created": fields.DateTime(description="Creation date (ISO format)"),
|
|
"expires": fields.DateTime(description="Expiration date (ISO format)"),
|
|
"used_at": fields.DateTime(description="Date when invitation was used"),
|
|
"used_by": fields.String(description="Username who used the invitation"),
|
|
"duration": fields.String(
|
|
description='User access duration in days or "unlimited"'
|
|
),
|
|
"unlimited": fields.Boolean(description="Whether user access is unlimited"),
|
|
"specific_libraries": fields.List(
|
|
fields.Integer, description="Specific library IDs if restricted"
|
|
),
|
|
"display_name": fields.String(description="Display name for the invitation"),
|
|
"server_names": fields.List(fields.String, description="List of server names"),
|
|
"uses_global_setting": fields.Boolean(
|
|
description="Whether display name comes from global setting"
|
|
),
|
|
},
|
|
)
|
|
|
|
invitation_list_model = api.model(
|
|
"InvitationList",
|
|
{
|
|
"invitations": fields.List(fields.Nested(invitation_model)),
|
|
"count": fields.Integer(description="Total number of invitations"),
|
|
},
|
|
)
|
|
|
|
invitation_create_request = api.model(
|
|
"InvitationCreateRequest",
|
|
{
|
|
"server_ids": fields.List(
|
|
fields.Integer,
|
|
required=False,
|
|
description="Array of server IDs (required, but validated by API for better error messages)",
|
|
),
|
|
"expires_in_days": fields.Integer(
|
|
description="Days until invitation expires (1, 7, 30, or null)",
|
|
enum=[1, 7, 30],
|
|
),
|
|
"duration": fields.String(
|
|
description='User access duration in days or "unlimited"',
|
|
default="unlimited",
|
|
),
|
|
"unlimited": fields.Boolean(
|
|
description="Whether user access is unlimited", default=True
|
|
),
|
|
"library_ids": fields.List(
|
|
fields.Integer, description="Array of library IDs to grant access to"
|
|
),
|
|
"allow_downloads": fields.Boolean(
|
|
description="Allow user downloads", default=False
|
|
),
|
|
"allow_live_tv": fields.Boolean(
|
|
description="Allow live TV access", default=False
|
|
),
|
|
"allow_mobile_uploads": fields.Boolean(
|
|
description="Allow mobile uploads", default=False
|
|
),
|
|
"wizard_bundle_id": fields.Integer(
|
|
required=False,
|
|
description="Wizard bundle ID to use for this invitation (omit for automatic selection)",
|
|
),
|
|
},
|
|
)
|
|
|
|
invitation_create_response = api.model(
|
|
"InvitationCreateResponse",
|
|
{
|
|
"message": fields.String(description="Success message"),
|
|
"invitation": fields.Nested(invitation_model),
|
|
},
|
|
)
|
|
|
|
# Library Models
|
|
library_model = api.model(
|
|
"Library",
|
|
{
|
|
"id": fields.Integer(description="Library ID"),
|
|
"name": fields.String(description="Library name"),
|
|
"external_id": fields.String(
|
|
description="External library ID from media server"
|
|
),
|
|
"server_id": fields.Integer(description="Server ID this library belongs to"),
|
|
"server_name": fields.String(description="Server name this library belongs to"),
|
|
"enabled": fields.Boolean(description="Whether this library is enabled"),
|
|
},
|
|
)
|
|
|
|
library_list_model = api.model(
|
|
"LibraryList",
|
|
{
|
|
"libraries": fields.List(fields.Nested(library_model)),
|
|
"count": fields.Integer(description="Total number of libraries"),
|
|
},
|
|
)
|
|
|
|
# Server Models
|
|
server_model = api.model(
|
|
"Server",
|
|
{
|
|
"id": fields.Integer(description="Server ID"),
|
|
"name": fields.String(description="Server name"),
|
|
"server_type": fields.String(
|
|
description="Server type (plex, jellyfin, emby, etc.)"
|
|
),
|
|
"server_url": fields.String(description="Internal server URL"),
|
|
"external_url": fields.String(description="External server URL"),
|
|
"verified": fields.Boolean(description="Whether server connection is verified"),
|
|
"allow_downloads": fields.Boolean(description="Whether downloads are allowed"),
|
|
"allow_live_tv": fields.Boolean(description="Whether live TV is allowed"),
|
|
"allow_mobile_uploads": fields.Boolean(
|
|
description="Whether mobile uploads are allowed"
|
|
),
|
|
"created_at": fields.DateTime(description="Server creation date"),
|
|
},
|
|
)
|
|
|
|
server_list_model = api.model(
|
|
"ServerList",
|
|
{
|
|
"servers": fields.List(fields.Nested(server_model)),
|
|
"count": fields.Integer(description="Total number of servers"),
|
|
},
|
|
)
|
|
|
|
# API Key Models
|
|
api_key_model = api.model(
|
|
"ApiKey",
|
|
{
|
|
"id": fields.Integer(description="API key ID"),
|
|
"name": fields.String(description="API key name"),
|
|
"created_at": fields.DateTime(description="Creation date"),
|
|
"last_used_at": fields.DateTime(description="Last used date"),
|
|
"created_by": fields.String(description="Username who created the key"),
|
|
},
|
|
)
|
|
|
|
api_key_list_model = api.model(
|
|
"ApiKeyList",
|
|
{
|
|
"api_keys": fields.List(fields.Nested(api_key_model)),
|
|
"count": fields.Integer(description="Total number of API keys"),
|
|
},
|
|
)
|
|
|
|
# Error Models
|
|
error_model = api.model(
|
|
"Error",
|
|
{
|
|
"error": fields.String(description="Error message"),
|
|
},
|
|
)
|
|
|
|
success_message_model = api.model(
|
|
"SuccessMessage",
|
|
{
|
|
"message": fields.String(description="Success message"),
|
|
},
|
|
)
|