mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 20:34:37 +03:00
Add stash-box credentials validation (#2173)
This commit is contained in:
@@ -11,3 +11,10 @@ query Directory($path: String) {
|
|||||||
directories
|
directories
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query ValidateStashBox($input: StashBoxInput!) {
|
||||||
|
validateStashBoxCredentials(input: $input) {
|
||||||
|
valid
|
||||||
|
status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ type Query {
|
|||||||
"Desired collation locale. Determines the order of the directory result. eg. 'en-US', 'pt-BR', ..."
|
"Desired collation locale. Determines the order of the directory result. eg. 'en-US', 'pt-BR', ..."
|
||||||
locale: String = "en"
|
locale: String = "en"
|
||||||
): Directory!
|
): Directory!
|
||||||
|
validateStashBoxCredentials(input: StashBoxInput!): StashBoxValidationResult!
|
||||||
|
|
||||||
# System status
|
# System status
|
||||||
systemStatus: SystemStatus!
|
systemStatus: SystemStatus!
|
||||||
|
|||||||
@@ -391,3 +391,8 @@ type StashConfig {
|
|||||||
input GenerateAPIKeyInput {
|
input GenerateAPIKeyInput {
|
||||||
clear: Boolean
|
clear: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StashBoxValidationResult {
|
||||||
|
valid: Boolean!
|
||||||
|
status: String!
|
||||||
|
}
|
||||||
|
|||||||
@@ -156,3 +156,9 @@ query FindSceneByID($id: ID!) {
|
|||||||
mutation SubmitFingerprint($input: FingerprintSubmission!) {
|
mutation SubmitFingerprint($input: FingerprintSubmission!) {
|
||||||
submitFingerprint(input: $input)
|
submitFingerprint(input: $input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query Me {
|
||||||
|
me {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,9 +2,12 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/stashapp/stash/pkg/manager/config"
|
"github.com/stashapp/stash/pkg/manager/config"
|
||||||
"github.com/stashapp/stash/pkg/models"
|
"github.com/stashapp/stash/pkg/models"
|
||||||
|
"github.com/stashapp/stash/pkg/scraper/stashbox"
|
||||||
"github.com/stashapp/stash/pkg/utils"
|
"github.com/stashapp/stash/pkg/utils"
|
||||||
"golang.org/x/text/collate"
|
"golang.org/x/text/collate"
|
||||||
)
|
)
|
||||||
@@ -188,3 +191,38 @@ func makeConfigDefaultsResult() *models.ConfigDefaultSettingsResult {
|
|||||||
DeleteGenerated: &deleteGeneratedDefault,
|
DeleteGenerated: &deleteGeneratedDefault,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *queryResolver) ValidateStashBoxCredentials(ctx context.Context, input models.StashBoxInput) (*models.StashBoxValidationResult, error) {
|
||||||
|
client := stashbox.NewClient(models.StashBox{Endpoint: input.Endpoint, APIKey: input.APIKey}, r.txnManager)
|
||||||
|
user, err := client.GetUser(ctx)
|
||||||
|
|
||||||
|
valid := user != nil && user.Me != nil
|
||||||
|
var status string
|
||||||
|
if valid {
|
||||||
|
status = fmt.Sprintf("Successfully authenticated as %s", user.Me.Name)
|
||||||
|
} else {
|
||||||
|
switch {
|
||||||
|
case strings.Contains(strings.ToLower(err.Error()), "doctype"):
|
||||||
|
// Index file returned rather than graphql
|
||||||
|
status = "Invalid endpoint"
|
||||||
|
case strings.Contains(err.Error(), "request failed"):
|
||||||
|
status = "No response from server"
|
||||||
|
case strings.HasPrefix(err.Error(), "invalid character") ||
|
||||||
|
strings.HasPrefix(err.Error(), "illegal base64 data") ||
|
||||||
|
err.Error() == "unexpected end of JSON input" ||
|
||||||
|
err.Error() == "token contains an invalid number of segments":
|
||||||
|
status = "Malformed API key."
|
||||||
|
case err.Error() == "" || err.Error() == "signature is invalid":
|
||||||
|
status = "Invalid or expired API key."
|
||||||
|
default:
|
||||||
|
status = fmt.Sprintf("Unknown error: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result := models.StashBoxValidationResult{
|
||||||
|
Valid: valid,
|
||||||
|
Status: status,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -180,45 +180,32 @@ type FindSceneByID struct {
|
|||||||
type SubmitFingerprintPayload struct {
|
type SubmitFingerprintPayload struct {
|
||||||
SubmitFingerprint bool "json:\"submitFingerprint\" graphql:\"submitFingerprint\""
|
SubmitFingerprint bool "json:\"submitFingerprint\" graphql:\"submitFingerprint\""
|
||||||
}
|
}
|
||||||
|
type Me struct {
|
||||||
|
Me *struct {
|
||||||
|
Name string "json:\"name\" graphql:\"name\""
|
||||||
|
} "json:\"me\" graphql:\"me\""
|
||||||
|
}
|
||||||
|
|
||||||
const FindSceneByFingerprintQuery = `query FindSceneByFingerprint ($fingerprint: FingerprintQueryInput!) {
|
const FindSceneByFingerprintQuery = `query FindSceneByFingerprint ($fingerprint: FingerprintQueryInput!) {
|
||||||
findSceneByFingerprint(fingerprint: $fingerprint) {
|
findSceneByFingerprint(fingerprint: $fingerprint) {
|
||||||
... SceneFragment
|
... SceneFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fragment FuzzyDateFragment on FuzzyDate {
|
fragment FingerprintFragment on Fingerprint {
|
||||||
date
|
algorithm
|
||||||
accuracy
|
hash
|
||||||
}
|
|
||||||
fragment SceneFragment on Scene {
|
|
||||||
id
|
|
||||||
title
|
|
||||||
details
|
|
||||||
duration
|
duration
|
||||||
date
|
|
||||||
urls {
|
|
||||||
... URLFragment
|
|
||||||
}
|
|
||||||
images {
|
|
||||||
... ImageFragment
|
|
||||||
}
|
|
||||||
studio {
|
|
||||||
... StudioFragment
|
|
||||||
}
|
|
||||||
tags {
|
|
||||||
... TagFragment
|
|
||||||
}
|
|
||||||
performers {
|
|
||||||
... PerformerAppearanceFragment
|
|
||||||
}
|
|
||||||
fingerprints {
|
|
||||||
... FingerprintFragment
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fragment URLFragment on URL {
|
fragment URLFragment on URL {
|
||||||
url
|
url
|
||||||
type
|
type
|
||||||
}
|
}
|
||||||
|
fragment ImageFragment on Image {
|
||||||
|
id
|
||||||
|
url
|
||||||
|
width
|
||||||
|
height
|
||||||
|
}
|
||||||
fragment StudioFragment on Studio {
|
fragment StudioFragment on Studio {
|
||||||
name
|
name
|
||||||
id
|
id
|
||||||
@@ -269,31 +256,49 @@ fragment PerformerFragment on Performer {
|
|||||||
... BodyModificationFragment
|
... BodyModificationFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fragment ImageFragment on Image {
|
fragment BodyModificationFragment on BodyModification {
|
||||||
|
location
|
||||||
|
description
|
||||||
|
}
|
||||||
|
fragment SceneFragment on Scene {
|
||||||
id
|
id
|
||||||
url
|
title
|
||||||
width
|
details
|
||||||
height
|
duration
|
||||||
|
date
|
||||||
|
urls {
|
||||||
|
... URLFragment
|
||||||
|
}
|
||||||
|
images {
|
||||||
|
... ImageFragment
|
||||||
|
}
|
||||||
|
studio {
|
||||||
|
... StudioFragment
|
||||||
|
}
|
||||||
|
tags {
|
||||||
|
... TagFragment
|
||||||
|
}
|
||||||
|
performers {
|
||||||
|
... PerformerAppearanceFragment
|
||||||
|
}
|
||||||
|
fingerprints {
|
||||||
|
... FingerprintFragment
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fragment TagFragment on Tag {
|
fragment TagFragment on Tag {
|
||||||
name
|
name
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
fragment FuzzyDateFragment on FuzzyDate {
|
||||||
|
date
|
||||||
|
accuracy
|
||||||
|
}
|
||||||
fragment MeasurementsFragment on Measurements {
|
fragment MeasurementsFragment on Measurements {
|
||||||
band_size
|
band_size
|
||||||
cup_size
|
cup_size
|
||||||
waist
|
waist
|
||||||
hip
|
hip
|
||||||
}
|
}
|
||||||
fragment BodyModificationFragment on BodyModification {
|
|
||||||
location
|
|
||||||
description
|
|
||||||
}
|
|
||||||
fragment FingerprintFragment on Fingerprint {
|
|
||||||
algorithm
|
|
||||||
hash
|
|
||||||
duration
|
|
||||||
}
|
|
||||||
`
|
`
|
||||||
|
|
||||||
func (c *Client) FindSceneByFingerprint(ctx context.Context, fingerprint FingerprintQueryInput, httpRequestOptions ...client.HTTPRequestOption) (*FindSceneByFingerprint, error) {
|
func (c *Client) FindSceneByFingerprint(ctx context.Context, fingerprint FingerprintQueryInput, httpRequestOptions ...client.HTTPRequestOption) (*FindSceneByFingerprint, error) {
|
||||||
@@ -314,12 +319,6 @@ const FindScenesByFullFingerprintsQuery = `query FindScenesByFullFingerprints ($
|
|||||||
... SceneFragment
|
... SceneFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fragment ImageFragment on Image {
|
|
||||||
id
|
|
||||||
url
|
|
||||||
width
|
|
||||||
height
|
|
||||||
}
|
|
||||||
fragment StudioFragment on Studio {
|
fragment StudioFragment on Studio {
|
||||||
name
|
name
|
||||||
id
|
id
|
||||||
@@ -330,10 +329,6 @@ fragment StudioFragment on Studio {
|
|||||||
... ImageFragment
|
... ImageFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fragment TagFragment on Tag {
|
|
||||||
name
|
|
||||||
id
|
|
||||||
}
|
|
||||||
fragment PerformerFragment on Performer {
|
fragment PerformerFragment on Performer {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
@@ -372,11 +367,14 @@ fragment FuzzyDateFragment on FuzzyDate {
|
|||||||
date
|
date
|
||||||
accuracy
|
accuracy
|
||||||
}
|
}
|
||||||
fragment MeasurementsFragment on Measurements {
|
fragment BodyModificationFragment on BodyModification {
|
||||||
band_size
|
location
|
||||||
cup_size
|
description
|
||||||
waist
|
}
|
||||||
hip
|
fragment FingerprintFragment on Fingerprint {
|
||||||
|
algorithm
|
||||||
|
hash
|
||||||
|
duration
|
||||||
}
|
}
|
||||||
fragment SceneFragment on Scene {
|
fragment SceneFragment on Scene {
|
||||||
id
|
id
|
||||||
@@ -403,24 +401,31 @@ fragment SceneFragment on Scene {
|
|||||||
... FingerprintFragment
|
... FingerprintFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fragment URLFragment on URL {
|
||||||
|
url
|
||||||
|
type
|
||||||
|
}
|
||||||
|
fragment ImageFragment on Image {
|
||||||
|
id
|
||||||
|
url
|
||||||
|
width
|
||||||
|
height
|
||||||
|
}
|
||||||
|
fragment TagFragment on Tag {
|
||||||
|
name
|
||||||
|
id
|
||||||
|
}
|
||||||
fragment PerformerAppearanceFragment on PerformerAppearance {
|
fragment PerformerAppearanceFragment on PerformerAppearance {
|
||||||
as
|
as
|
||||||
performer {
|
performer {
|
||||||
... PerformerFragment
|
... PerformerFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fragment BodyModificationFragment on BodyModification {
|
fragment MeasurementsFragment on Measurements {
|
||||||
location
|
band_size
|
||||||
description
|
cup_size
|
||||||
}
|
waist
|
||||||
fragment FingerprintFragment on Fingerprint {
|
hip
|
||||||
algorithm
|
|
||||||
hash
|
|
||||||
duration
|
|
||||||
}
|
|
||||||
fragment URLFragment on URL {
|
|
||||||
url
|
|
||||||
type
|
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
@@ -452,18 +457,19 @@ fragment ImageFragment on Image {
|
|||||||
width
|
width
|
||||||
height
|
height
|
||||||
}
|
}
|
||||||
fragment TagFragment on Tag {
|
|
||||||
name
|
|
||||||
id
|
|
||||||
}
|
|
||||||
fragment FuzzyDateFragment on FuzzyDate {
|
fragment FuzzyDateFragment on FuzzyDate {
|
||||||
date
|
date
|
||||||
accuracy
|
accuracy
|
||||||
}
|
}
|
||||||
fragment FingerprintFragment on Fingerprint {
|
fragment MeasurementsFragment on Measurements {
|
||||||
algorithm
|
band_size
|
||||||
hash
|
cup_size
|
||||||
duration
|
waist
|
||||||
|
hip
|
||||||
|
}
|
||||||
|
fragment BodyModificationFragment on BodyModification {
|
||||||
|
location
|
||||||
|
description
|
||||||
}
|
}
|
||||||
fragment SceneFragment on Scene {
|
fragment SceneFragment on Scene {
|
||||||
id
|
id
|
||||||
@@ -500,6 +506,10 @@ fragment StudioFragment on Studio {
|
|||||||
... ImageFragment
|
... ImageFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fragment TagFragment on Tag {
|
||||||
|
name
|
||||||
|
id
|
||||||
|
}
|
||||||
fragment PerformerAppearanceFragment on PerformerAppearance {
|
fragment PerformerAppearanceFragment on PerformerAppearance {
|
||||||
as
|
as
|
||||||
performer {
|
performer {
|
||||||
@@ -540,15 +550,10 @@ fragment PerformerFragment on Performer {
|
|||||||
... BodyModificationFragment
|
... BodyModificationFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fragment MeasurementsFragment on Measurements {
|
fragment FingerprintFragment on Fingerprint {
|
||||||
band_size
|
algorithm
|
||||||
cup_size
|
hash
|
||||||
waist
|
duration
|
||||||
hip
|
|
||||||
}
|
|
||||||
fragment BodyModificationFragment on BodyModification {
|
|
||||||
location
|
|
||||||
description
|
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
@@ -570,30 +575,6 @@ const SearchPerformerQuery = `query SearchPerformer ($term: String!) {
|
|||||||
... PerformerFragment
|
... PerformerFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fragment URLFragment on URL {
|
|
||||||
url
|
|
||||||
type
|
|
||||||
}
|
|
||||||
fragment ImageFragment on Image {
|
|
||||||
id
|
|
||||||
url
|
|
||||||
width
|
|
||||||
height
|
|
||||||
}
|
|
||||||
fragment FuzzyDateFragment on FuzzyDate {
|
|
||||||
date
|
|
||||||
accuracy
|
|
||||||
}
|
|
||||||
fragment MeasurementsFragment on Measurements {
|
|
||||||
band_size
|
|
||||||
cup_size
|
|
||||||
waist
|
|
||||||
hip
|
|
||||||
}
|
|
||||||
fragment BodyModificationFragment on BodyModification {
|
|
||||||
location
|
|
||||||
description
|
|
||||||
}
|
|
||||||
fragment PerformerFragment on Performer {
|
fragment PerformerFragment on Performer {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
@@ -628,6 +609,30 @@ fragment PerformerFragment on Performer {
|
|||||||
... BodyModificationFragment
|
... BodyModificationFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fragment URLFragment on URL {
|
||||||
|
url
|
||||||
|
type
|
||||||
|
}
|
||||||
|
fragment ImageFragment on Image {
|
||||||
|
id
|
||||||
|
url
|
||||||
|
width
|
||||||
|
height
|
||||||
|
}
|
||||||
|
fragment FuzzyDateFragment on FuzzyDate {
|
||||||
|
date
|
||||||
|
accuracy
|
||||||
|
}
|
||||||
|
fragment MeasurementsFragment on Measurements {
|
||||||
|
band_size
|
||||||
|
cup_size
|
||||||
|
waist
|
||||||
|
hip
|
||||||
|
}
|
||||||
|
fragment BodyModificationFragment on BodyModification {
|
||||||
|
location
|
||||||
|
description
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
func (c *Client) SearchPerformer(ctx context.Context, term string, httpRequestOptions ...client.HTTPRequestOption) (*SearchPerformer, error) {
|
func (c *Client) SearchPerformer(ctx context.Context, term string, httpRequestOptions ...client.HTTPRequestOption) (*SearchPerformer, error) {
|
||||||
@@ -732,6 +737,35 @@ fragment ImageFragment on Image {
|
|||||||
width
|
width
|
||||||
height
|
height
|
||||||
}
|
}
|
||||||
|
fragment TagFragment on Tag {
|
||||||
|
name
|
||||||
|
id
|
||||||
|
}
|
||||||
|
fragment PerformerAppearanceFragment on PerformerAppearance {
|
||||||
|
as
|
||||||
|
performer {
|
||||||
|
... PerformerFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment FuzzyDateFragment on FuzzyDate {
|
||||||
|
date
|
||||||
|
accuracy
|
||||||
|
}
|
||||||
|
fragment MeasurementsFragment on Measurements {
|
||||||
|
band_size
|
||||||
|
cup_size
|
||||||
|
waist
|
||||||
|
hip
|
||||||
|
}
|
||||||
|
fragment FingerprintFragment on Fingerprint {
|
||||||
|
algorithm
|
||||||
|
hash
|
||||||
|
duration
|
||||||
|
}
|
||||||
|
fragment URLFragment on URL {
|
||||||
|
url
|
||||||
|
type
|
||||||
|
}
|
||||||
fragment StudioFragment on Studio {
|
fragment StudioFragment on Studio {
|
||||||
name
|
name
|
||||||
id
|
id
|
||||||
@@ -742,10 +776,6 @@ fragment StudioFragment on Studio {
|
|||||||
... ImageFragment
|
... ImageFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fragment TagFragment on Tag {
|
|
||||||
name
|
|
||||||
id
|
|
||||||
}
|
|
||||||
fragment PerformerFragment on Performer {
|
fragment PerformerFragment on Performer {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
@@ -780,16 +810,9 @@ fragment PerformerFragment on Performer {
|
|||||||
... BodyModificationFragment
|
... BodyModificationFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fragment MeasurementsFragment on Measurements {
|
fragment BodyModificationFragment on BodyModification {
|
||||||
band_size
|
location
|
||||||
cup_size
|
description
|
||||||
waist
|
|
||||||
hip
|
|
||||||
}
|
|
||||||
fragment FingerprintFragment on Fingerprint {
|
|
||||||
algorithm
|
|
||||||
hash
|
|
||||||
duration
|
|
||||||
}
|
}
|
||||||
fragment SceneFragment on Scene {
|
fragment SceneFragment on Scene {
|
||||||
id
|
id
|
||||||
@@ -816,24 +839,6 @@ fragment SceneFragment on Scene {
|
|||||||
... FingerprintFragment
|
... FingerprintFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fragment URLFragment on URL {
|
|
||||||
url
|
|
||||||
type
|
|
||||||
}
|
|
||||||
fragment BodyModificationFragment on BodyModification {
|
|
||||||
location
|
|
||||||
description
|
|
||||||
}
|
|
||||||
fragment PerformerAppearanceFragment on PerformerAppearance {
|
|
||||||
as
|
|
||||||
performer {
|
|
||||||
... PerformerFragment
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fragment FuzzyDateFragment on FuzzyDate {
|
|
||||||
date
|
|
||||||
accuracy
|
|
||||||
}
|
|
||||||
`
|
`
|
||||||
|
|
||||||
func (c *Client) FindSceneByID(ctx context.Context, id string, httpRequestOptions ...client.HTTPRequestOption) (*FindSceneByID, error) {
|
func (c *Client) FindSceneByID(ctx context.Context, id string, httpRequestOptions ...client.HTTPRequestOption) (*FindSceneByID, error) {
|
||||||
@@ -866,3 +871,21 @@ func (c *Client) SubmitFingerprint(ctx context.Context, input FingerprintSubmiss
|
|||||||
|
|
||||||
return &res, nil
|
return &res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MeQuery = `query Me {
|
||||||
|
me {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
func (c *Client) Me(ctx context.Context, httpRequestOptions ...client.HTTPRequestOption) (*Me, error) {
|
||||||
|
vars := map[string]interface{}{}
|
||||||
|
|
||||||
|
var res Me
|
||||||
|
if err := c.Client.Post(ctx, MeQuery, &res, vars, httpRequestOptions...); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &res, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -753,3 +753,7 @@ func (c Client) FindStashBoxPerformerByName(ctx context.Context, name string) (*
|
|||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c Client) GetUser(ctx context.Context) (*graphql.Me, error) {
|
||||||
|
return c.client.Me(ctx)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
### 🎨 Improvements
|
### 🎨 Improvements
|
||||||
Show counts on list tabs in Performer, Studio and Tag pages. ([#2169](https://github.com/stashapp/stash/pull/2169))
|
* Add button to test credentials when adding/editing stash-box endpoints. ([#2173](https://github.com/stashapp/stash/pull/2173))
|
||||||
|
* Show counts on list tabs in Performer, Studio and Tag pages. ([#2169](https://github.com/stashapp/stash/pull/2169))
|
||||||
|
|
||||||
### 🐛 Bug fixes
|
### 🐛 Bug fixes
|
||||||
* Generate sprites for short video files. ([#2167](https://github.com/stashapp/stash/pull/2167))
|
* Generate sprites for short video files. ([#2167](https://github.com/stashapp/stash/pull/2167))
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useRef, useState } from "react";
|
||||||
import { Button, Form } from "react-bootstrap";
|
import { Button, Form } from "react-bootstrap";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
import { SettingSection } from "./SettingSection";
|
import { SettingSection } from "./SettingSection";
|
||||||
@@ -12,6 +12,24 @@ export interface IStashBoxModal {
|
|||||||
|
|
||||||
export const StashBoxModal: React.FC<IStashBoxModal> = ({ value, close }) => {
|
export const StashBoxModal: React.FC<IStashBoxModal> = ({ value, close }) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
const endpoint = useRef<HTMLInputElement | null>(null);
|
||||||
|
const apiKey = useRef<HTMLInputElement | null>(null);
|
||||||
|
|
||||||
|
const [validate, { data, loading }] = GQL.useValidateStashBoxLazyQuery({
|
||||||
|
fetchPolicy: "network-only",
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleValidate = () => {
|
||||||
|
validate({
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
endpoint: endpoint.current?.value ?? "",
|
||||||
|
api_key: apiKey.current?.value ?? "",
|
||||||
|
name: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingModal<GQL.StashBoxInput>
|
<SettingModal<GQL.StashBoxInput>
|
||||||
@@ -52,6 +70,7 @@ export const StashBoxModal: React.FC<IStashBoxModal> = ({ value, close }) => {
|
|||||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
setValue({ ...v!, endpoint: e.currentTarget.value.trim() })
|
setValue({ ...v!, endpoint: e.currentTarget.value.trim() })
|
||||||
}
|
}
|
||||||
|
ref={endpoint}
|
||||||
/>
|
/>
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
|
|
||||||
@@ -71,8 +90,30 @@ export const StashBoxModal: React.FC<IStashBoxModal> = ({ value, close }) => {
|
|||||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
setValue({ ...v!, api_key: e.currentTarget.value.trim() })
|
setValue({ ...v!, api_key: e.currentTarget.value.trim() })
|
||||||
}
|
}
|
||||||
|
ref={apiKey}
|
||||||
/>
|
/>
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
|
|
||||||
|
<Form.Group>
|
||||||
|
<Button
|
||||||
|
disabled={loading}
|
||||||
|
onClick={handleValidate}
|
||||||
|
className="mr-3"
|
||||||
|
>
|
||||||
|
Test Credentials
|
||||||
|
</Button>
|
||||||
|
{data && (
|
||||||
|
<b
|
||||||
|
className={
|
||||||
|
data.validateStashBoxCredentials?.valid
|
||||||
|
? "text-success"
|
||||||
|
: "text-danger"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{data.validateStashBoxCredentials?.status}
|
||||||
|
</b>
|
||||||
|
)}
|
||||||
|
</Form.Group>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
close={close}
|
close={close}
|
||||||
|
|||||||
Reference in New Issue
Block a user