mirror of
https://github.com/idanoo/autobrr
synced 2025-07-23 08:49:13 +00:00
Fix: update download client (#23)
* feat: use password fields * fix: update download client and better logs
This commit is contained in:
parent
d4aa2027c0
commit
f78ca85df2
4 changed files with 91 additions and 64 deletions
|
@ -21,7 +21,8 @@ func (r *DownloadClientRepo) List() ([]domain.DownloadClient, error) {
|
||||||
|
|
||||||
rows, err := r.db.Query("SELECT id, name, type, enabled, host, port, ssl, username, password, settings FROM client")
|
rows, err := r.db.Query("SELECT id, name, type, enabled, host, port, ssl, username, password, settings FROM client")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal().Err(err)
|
log.Error().Stack().Err(err).Msg("could not query download client rows")
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
@ -33,14 +34,13 @@ func (r *DownloadClientRepo) List() ([]domain.DownloadClient, error) {
|
||||||
var settingsJsonStr string
|
var settingsJsonStr string
|
||||||
|
|
||||||
if err := rows.Scan(&f.ID, &f.Name, &f.Type, &f.Enabled, &f.Host, &f.Port, &f.SSL, &f.Username, &f.Password, &settingsJsonStr); err != nil {
|
if err := rows.Scan(&f.ID, &f.Name, &f.Type, &f.Enabled, &f.Host, &f.Port, &f.SSL, &f.Username, &f.Password, &settingsJsonStr); err != nil {
|
||||||
log.Error().Err(err)
|
log.Error().Stack().Err(err).Msg("could not scan download client to struct")
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if settingsJsonStr != "" {
|
if settingsJsonStr != "" {
|
||||||
if err := json.Unmarshal([]byte(settingsJsonStr), &f.Settings); err != nil {
|
if err := json.Unmarshal([]byte(settingsJsonStr), &f.Settings); err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msgf("could not marshal download client settings %v", settingsJsonStr)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@ func (r *DownloadClientRepo) List() ([]domain.DownloadClient, error) {
|
||||||
clients = append(clients, f)
|
clients = append(clients, f)
|
||||||
}
|
}
|
||||||
if err := rows.Err(); err != nil {
|
if err := rows.Err(); err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("could not query download client rows")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +63,7 @@ func (r *DownloadClientRepo) FindByID(id int32) (*domain.DownloadClient, error)
|
||||||
|
|
||||||
row := r.db.QueryRow(query, id)
|
row := r.db.QueryRow(query, id)
|
||||||
if err := row.Err(); err != nil {
|
if err := row.Err(); err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("could not query download client rows")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,12 +71,13 @@ func (r *DownloadClientRepo) FindByID(id int32) (*domain.DownloadClient, error)
|
||||||
var settingsJsonStr string
|
var settingsJsonStr string
|
||||||
|
|
||||||
if err := row.Scan(&client.ID, &client.Name, &client.Type, &client.Enabled, &client.Host, &client.Port, &client.SSL, &client.Username, &client.Password, &settingsJsonStr); err != nil {
|
if err := row.Scan(&client.ID, &client.Name, &client.Type, &client.Enabled, &client.Host, &client.Port, &client.SSL, &client.Username, &client.Password, &settingsJsonStr); err != nil {
|
||||||
log.Error().Err(err).Msg("could not scan download client to struct")
|
log.Error().Stack().Err(err).Msg("could not scan download client to struct")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if settingsJsonStr != "" {
|
if settingsJsonStr != "" {
|
||||||
if err := json.Unmarshal([]byte(settingsJsonStr), &client.Settings); err != nil {
|
if err := json.Unmarshal([]byte(settingsJsonStr), &client.Settings); err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msgf("could not marshal download client settings %v", settingsJsonStr)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,42 +85,6 @@ func (r *DownloadClientRepo) FindByID(id int32) (*domain.DownloadClient, error)
|
||||||
return &client, nil
|
return &client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DownloadClientRepo) FindByActionID(actionID int) ([]domain.DownloadClient, error) {
|
|
||||||
|
|
||||||
rows, err := r.db.Query("SELECT id, name, type, enabled, host, port, ssl, username, password, settings FROM client, action_client WHERE client.id = action_client.client_id AND action_client.action_id = ?", actionID)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal().Err(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer rows.Close()
|
|
||||||
|
|
||||||
var clients []domain.DownloadClient
|
|
||||||
for rows.Next() {
|
|
||||||
var f domain.DownloadClient
|
|
||||||
var settingsJsonStr string
|
|
||||||
|
|
||||||
if err := rows.Scan(&f.ID, &f.Name, &f.Type, &f.Enabled, &f.Host, &f.Port, &f.SSL, &f.Username, &f.Password, &settingsJsonStr); err != nil {
|
|
||||||
log.Error().Err(err)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if settingsJsonStr != "" {
|
|
||||||
if err := json.Unmarshal([]byte(settingsJsonStr), &f.Settings); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clients = append(clients, f)
|
|
||||||
}
|
|
||||||
if err := rows.Err(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return clients, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *DownloadClientRepo) Store(client domain.DownloadClient) (*domain.DownloadClient, error) {
|
func (r *DownloadClientRepo) Store(client domain.DownloadClient) (*domain.DownloadClient, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -128,40 +95,95 @@ func (r *DownloadClientRepo) Store(client domain.DownloadClient) (*domain.Downlo
|
||||||
|
|
||||||
settingsJson, err := json.Marshal(&settings)
|
settingsJson, err := json.Marshal(&settings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("could not marshal download client settings %v", settings)
|
log.Error().Stack().Err(err).Msgf("could not marshal download client settings %v", settings)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if client.ID != 0 {
|
if client.ID != 0 {
|
||||||
log.Info().Msg("UPDATE existing record")
|
_, err = r.db.Exec(`
|
||||||
_, err = r.db.Exec(`UPDATE client SET name = ?, type = ?, enabled = ?, host = ?, port = ?, ssl = ?, username = ?, password = ?, settings = json_set(?) WHERE id = ?`, client.Name, client.Type, client.Enabled, client.Host, client.Port, client.SSL, client.Username, client.Password, client.ID, settingsJson)
|
UPDATE
|
||||||
|
client
|
||||||
|
SET
|
||||||
|
name = ?,
|
||||||
|
type = ?,
|
||||||
|
enabled = ?,
|
||||||
|
host = ?,
|
||||||
|
port = ?,
|
||||||
|
ssl = ?,
|
||||||
|
username = ?,
|
||||||
|
password = ?,
|
||||||
|
settings = json_set(?)
|
||||||
|
WHERE
|
||||||
|
id = ?`,
|
||||||
|
client.Name,
|
||||||
|
client.Type,
|
||||||
|
client.Enabled,
|
||||||
|
client.Host,
|
||||||
|
client.Port,
|
||||||
|
client.SSL,
|
||||||
|
client.Username,
|
||||||
|
client.Password,
|
||||||
|
settingsJson,
|
||||||
|
client.ID,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msgf("could not update download client: %v", client)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
var res sql.Result
|
var res sql.Result
|
||||||
|
|
||||||
res, err = r.db.Exec(`INSERT INTO client(name, type, enabled, host, port, ssl, username, password, settings)
|
res, err = r.db.Exec(`INSERT INTO
|
||||||
VALUES (?, ?, ?, ?, ?, ? , ?, ?, json_set(?)) ON CONFLICT DO NOTHING`, client.Name, client.Type, client.Enabled, client.Host, client.Port, client.SSL, client.Username, client.Password, settingsJson)
|
client(
|
||||||
|
name,
|
||||||
|
type,
|
||||||
|
enabled,
|
||||||
|
host,
|
||||||
|
port,
|
||||||
|
ssl,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
settings)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ? , ?, ?, json_set(?)) ON CONFLICT DO NOTHING`,
|
||||||
|
client.Name,
|
||||||
|
client.Type,
|
||||||
|
client.Enabled,
|
||||||
|
client.Host,
|
||||||
|
client.Port,
|
||||||
|
client.SSL,
|
||||||
|
client.Username,
|
||||||
|
client.Password,
|
||||||
|
settingsJson,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err)
|
log.Error().Stack().Err(err).Msgf("could not store new download client: %v", client)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
resId, _ := res.LastInsertId()
|
resId, _ := res.LastInsertId()
|
||||||
log.Info().Msgf("LAST INSERT ID %v", resId)
|
|
||||||
client.ID = int(resId)
|
client.ID = int(resId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Info().Msgf("store download client: %v", client.Name)
|
||||||
|
log.Trace().Msgf("store download client: %+v", client)
|
||||||
|
|
||||||
return &client, nil
|
return &client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DownloadClientRepo) Delete(clientID int) error {
|
func (r *DownloadClientRepo) Delete(clientID int) error {
|
||||||
res, err := r.db.Exec(`DELETE FROM client WHERE client.id = ?`, clientID)
|
res, err := r.db.Exec(`DELETE FROM client WHERE client.id = ?`, clientID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msgf("could not delete download client: %d", clientID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, _ := res.RowsAffected()
|
rows, _ := res.RowsAffected()
|
||||||
|
|
||||||
log.Info().Msgf("rows affected %v", rows)
|
if rows == 0 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info().Msgf("delete download client: %d", clientID)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,9 +117,14 @@ export enum DOWNLOAD_CLIENT_TYPES {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DownloadClient {
|
export interface DownloadClient {
|
||||||
id: number;
|
id?: number;
|
||||||
name: string;
|
name: string;
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
|
host: string;
|
||||||
|
port: number;
|
||||||
|
ssl: boolean;
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
type: DownloadClientType;
|
type: DownloadClientType;
|
||||||
settings: object;
|
settings: object;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { Fragment } from "react";
|
import { Fragment } from "react";
|
||||||
import { SwitchGroup, TextFieldWide } from "../../../components/inputs";
|
import { SwitchGroup, TextFieldWide } from "../../../components/inputs";
|
||||||
import { NumberFieldWide } from "../../../components/inputs/wide";
|
import { NumberFieldWide, PasswordFieldWide } from "../../../components/inputs/wide";
|
||||||
import { useField } from "react-final-form";
|
import { useField } from "react-final-form";
|
||||||
|
|
||||||
function FormFieldsDefault() {
|
function FormFieldsDefault() {
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<TextFieldWide name="host" label="Host" />
|
<TextFieldWide name="host" label="Host" help="Url domain.ltd/client" />
|
||||||
|
|
||||||
<NumberFieldWide name="port" label="Port" />
|
<NumberFieldWide name="port" label="Port" />
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ function FormFieldsDefault() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TextFieldWide name="username" label="Username" />
|
<TextFieldWide name="username" label="Username" />
|
||||||
<TextFieldWide name="password" label="Password" />
|
<PasswordFieldWide name="password" label="Password" />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,9 @@ function FormFieldsArr() {
|
||||||
const { input } = useField("settings.basic.auth");
|
const { input } = useField("settings.basic.auth");
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<TextFieldWide name="host" label="Host" />
|
<TextFieldWide name="host" label="Host" help="Full url like http(s)://domain.ltd/" />
|
||||||
|
|
||||||
<TextFieldWide name="settings.apikey" label="API key" />
|
<PasswordFieldWide name="settings.apikey" label="API key" />
|
||||||
|
|
||||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
||||||
<SwitchGroup name="settings.basic.auth" label="Basic auth" />
|
<SwitchGroup name="settings.basic.auth" label="Basic auth" />
|
||||||
|
@ -35,7 +35,7 @@ function FormFieldsArr() {
|
||||||
{input.value === true && (
|
{input.value === true && (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<TextFieldWide name="settings.basic.username" label="Username" />
|
<TextFieldWide name="settings.basic.username" label="Username" />
|
||||||
<TextFieldWide name="settings.basic.password" label="Password" />
|
<PasswordFieldWide name="settings.basic.password" label="Password" />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
|
|
|
@ -15,15 +15,8 @@ interface DownloadLClientSettingsListItemProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
function DownloadClientSettingsListItem({ client, idx }: DownloadLClientSettingsListItemProps) {
|
function DownloadClientSettingsListItem({ client, idx }: DownloadLClientSettingsListItemProps) {
|
||||||
const [enabled, setEnabled] = useState(client.enabled)
|
|
||||||
const [updateClientIsOpen, toggleUpdateClient] = useToggle(false)
|
const [updateClientIsOpen, toggleUpdateClient] = useToggle(false)
|
||||||
|
|
||||||
const toggleActive = (status: boolean) => {
|
|
||||||
console.log(status)
|
|
||||||
setEnabled(status)
|
|
||||||
// call api
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr key={client.name} className={idx % 2 === 0 ? 'bg-white' : 'bg-gray-50'}>
|
<tr key={client.name} className={idx % 2 === 0 ? 'bg-white' : 'bg-gray-50'}>
|
||||||
{updateClientIsOpen &&
|
{updateClientIsOpen &&
|
||||||
|
@ -32,7 +25,7 @@ function DownloadClientSettingsListItem({ client, idx }: DownloadLClientSettings
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||||
<Switch
|
<Switch
|
||||||
checked={client.enabled}
|
checked={client.enabled}
|
||||||
onChange={toggleActive}
|
onChange={toggleUpdateClient}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
client.enabled ? 'bg-teal-500' : 'bg-gray-200',
|
client.enabled ? 'bg-teal-500' : 'bg-gray-200',
|
||||||
'relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-light-blue-500'
|
'relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-light-blue-500'
|
||||||
|
@ -49,6 +42,7 @@ function DownloadClientSettingsListItem({ client, idx }: DownloadLClientSettings
|
||||||
</Switch>
|
</Switch>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{client.name}</td>
|
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{client.name}</td>
|
||||||
|
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{client.host}</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{DownloadClientTypeNameMap[client.type]}</td>
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{DownloadClientTypeNameMap[client.type]}</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
||||||
<span className="text-indigo-600 hover:text-indigo-900 cursor-pointer" onClick={toggleUpdateClient}>
|
<span className="text-indigo-600 hover:text-indigo-900 cursor-pointer" onClick={toggleUpdateClient}>
|
||||||
|
@ -115,6 +109,12 @@ function DownloadClientSettings() {
|
||||||
>
|
>
|
||||||
Name
|
Name
|
||||||
</th>
|
</th>
|
||||||
|
<th
|
||||||
|
scope="col"
|
||||||
|
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||||
|
>
|
||||||
|
Host
|
||||||
|
</th>
|
||||||
<th
|
<th
|
||||||
scope="col"
|
scope="col"
|
||||||
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue