Add confirm=? query-param to delete-user route and confirm dialog in flutter [skip-tests]
All checks were successful
Build Docker and Deploy / Run Unit-Tests (push) Has been skipped
Build Docker and Deploy / Build Docker Container (push) Successful in 1m7s
Build Docker and Deploy / Deploy to Server (push) Successful in 11s

This commit is contained in:
Mike Schwörer 2025-05-11 15:43:06 +02:00
parent 7bbe321d3c
commit 255fc9337c
Signed by: Mikescher
GPG Key ID: D3C7172E0A70F8CF
17 changed files with 417 additions and 437 deletions

View File

@ -190,6 +190,9 @@ class APIClient {
relURL: 'users/$uid', relURL: 'users/$uid',
fn: User.fromJson, fn: User.fromJson,
authToken: auth.getToken(), authToken: auth.getToken(),
query: {
'confirm': ['true']
},
); );
} }

View File

@ -1,5 +1,7 @@
import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:action_slider/action_slider.dart';
import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
@ -527,17 +529,30 @@ class _AccountRootPageState extends State<AccountRootPage> {
final acc = AppAuth(); final acc = AppAuth();
if (!acc.isAuth()) return; if (!acc.isAuth()) return;
try { final r1 = await UIDialogs.showConfirmDialog(context, "Delete Account?", text: "Are you sure you want to delete your account?", okText: "Delete", cancelText: "Cancel");
TODO ASK BEFORE DELETING TEH FUCKING USER !!!!!!! if (!r1) return;
final r2 = await UIDialogs.showConfirmDialog(context, "Really sure?", text: "Are you really sure you want to delete your account?.\n\nThis includes all your messages and channels etc.\nThis action cannot be undone!", okText: "Delete", cancelText: "Cancel");
if (!r2) return;
final r3 = await UIDialogs.showTextInput(context, "Please input 'Delete' to delete your Account.", "");
if (r3 == null) return;
if (r3.trim().toLowerCase() != 'delete') return;
final r4 = await this._showDeleteDialog(context);
if (!r4) return;
final r5 = await this._showDeleteAccountWaitDialog(context);
if (!r5) return;
try {
await APIClient.deleteUser(acc, acc.userID!); await APIClient.deleteUser(acc, acc.userID!);
Toaster.info('Logout', 'Successfully logged out'); Toaster.info('Logout', 'Successfully logged out');
//TODO clear messages/channels/etc in open views
acc.clear(); acc.clear();
await acc.save(); await acc.save();
//TODO clear messages/channels/etc in open views
} catch (exc, trace) { } catch (exc, trace) {
Toaster.error("Error", 'Failed to delete user'); Toaster.error("Error", 'Failed to delete user');
ApplicationLog.error('Failed to delete user: ' + exc.toString(), trace: trace); ApplicationLog.error('Failed to delete user: ' + exc.toString(), trace: trace);
@ -570,4 +585,136 @@ class _AccountRootPageState extends State<AccountRootPage> {
ApplicationLog.error('Failed to update username: ' + exc.toString(), trace: trace); ApplicationLog.error('Failed to update username: ' + exc.toString(), trace: trace);
} }
} }
Future<bool> _showDeleteDialog(BuildContext context) {
return showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: Text("Delete Account?"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
child: ActionSlider.standard(
sliderBehavior: SliderBehavior.stretch,
width: 300,
backgroundColor: Colors.white,
toggleColor: Colors.red,
action: (controller) => Navigator.of(context).pop(true),
child: const Text('Slide to delete'),
),
width: 300,
height: 65,
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: Text('Cancel'),
),
],
),
).then((value) => value ?? false);
}
Future<bool> _showDeleteAccountWaitDialog(BuildContext context) {
final completer = Completer<bool>();
bool isTimerActive = true;
const int totalSeconds = 20;
int secondsRemaining = totalSeconds;
double percentageRemaining = 1.0;
late Timer timer;
showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext dialogContext) {
void Function(void Function())? setStateInner = null;
final t0 = DateTime.now();
timer = Timer.periodic(const Duration(milliseconds: 50), (t) {
setStateInner?.call(() {
percentageRemaining = 1 - (DateTime.now().millisecondsSinceEpoch - t0.millisecondsSinceEpoch) / (totalSeconds * 1000.0);
secondsRemaining = (totalSeconds * percentageRemaining).ceil();
if (secondsRemaining <= 0) {
t.cancel();
isTimerActive = false;
// Close the dialog and return true for successful deletion
Navigator.of(dialogContext).pop();
if (!completer.isCompleted) {
completer.complete(true);
}
}
});
});
return StatefulBuilder(
builder: (context, setState) {
setStateInner = setState;
return AlertDialog(
title: const Text('Delete Account'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Your account will be deleted in $secondsRemaining seconds.',
textAlign: TextAlign.center,
),
const SizedBox(height: 20),
SizedBox(
height: 100,
width: 100,
child: CircularProgressIndicator(
value: 1 - percentageRemaining,
strokeWidth: 8.0,
valueColor: const AlwaysStoppedAnimation<Color>(Colors.red),
backgroundColor: Colors.grey[300],
),
),
],
),
actions: <Widget>[
TextButton(
onPressed: () {
// Cancel the timer
if (timer.isActive) {
timer.cancel();
}
isTimerActive = false;
// Close the dialog and return false for cancellation
Navigator.of(dialogContext).pop();
if (!completer.isCompleted) {
completer.complete(false);
}
},
child: const Text('CANCEL'),
),
],
);
},
);
},
).then((_) {
// Ensure timer is cancelled if dialog is dismissed
if (timer.isActive) {
timer.cancel();
}
// If the completer hasn't been completed yet (e.g., if the dialog is dismissed),
// complete it with false
if (!completer.isCompleted && isTimerActive) {
completer.complete(false);
}
});
return completer.future;
}
} }

View File

@ -1,6 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:simplecloudnotifier/api/api_client.dart'; import 'package:simplecloudnotifier/api/api_client.dart';
import 'package:simplecloudnotifier/models/keytoken.dart'; import 'package:simplecloudnotifier/models/keytoken.dart';

View File

@ -1,6 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart';
import 'package:simplecloudnotifier/api/api_client.dart'; import 'package:simplecloudnotifier/api/api_client.dart';
import 'package:simplecloudnotifier/components/error_display/error_display.dart'; import 'package:simplecloudnotifier/components/error_display/error_display.dart';
import 'package:simplecloudnotifier/components/layout/scaffold.dart'; import 'package:simplecloudnotifier/components/layout/scaffold.dart';

View File

@ -5,7 +5,6 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:simplecloudnotifier/models/channel.dart'; import 'package:simplecloudnotifier/models/channel.dart';
import 'package:simplecloudnotifier/models/scn_message.dart'; import 'package:simplecloudnotifier/models/scn_message.dart';
import 'package:intl/intl.dart';
import 'package:simplecloudnotifier/state/app_settings.dart'; import 'package:simplecloudnotifier/state/app_settings.dart';
import 'package:simplecloudnotifier/utils/ui.dart'; import 'package:simplecloudnotifier/utils/ui.dart';

View File

@ -1,7 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:share_plus/share_plus.dart'; import 'package:share_plus/share_plus.dart';
import 'package:simplecloudnotifier/api/api_client.dart'; import 'package:simplecloudnotifier/api/api_client.dart';

View File

@ -186,8 +186,8 @@ class _SettingsRootPageState extends State<SettingsRootPage> {
SettingsTile.navigation( SettingsTile.navigation(
leading: Icon(FontAwesomeIcons.solidBell), leading: Icon(FontAwesomeIcons.solidBell),
title: Text('FCM Token'), title: Text('FCM Token'),
value: Text(AppAuth().getToken()), value: Text(AppAuth().getTokenOrNull() ?? 'N/A'),
onPressed: (context) => _clipboardCopy(AppAuth().getToken()), onPressed: (context) => _clipboardCopy(AppAuth().getTokenOrNull() ?? ''),
), ),
], ],
), ),

View File

@ -1,6 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart';
import 'package:simplecloudnotifier/api/api_client.dart'; import 'package:simplecloudnotifier/api/api_client.dart';
import 'package:simplecloudnotifier/components/error_display/error_display.dart'; import 'package:simplecloudnotifier/components/error_display/error_display.dart';
import 'package:simplecloudnotifier/components/layout/scaffold.dart'; import 'package:simplecloudnotifier/components/layout/scaffold.dart';

View File

@ -225,6 +225,10 @@ class AppAuth extends ChangeNotifier implements TokenSource {
return _tokenAdmin!; return _tokenAdmin!;
} }
String? getTokenOrNull() {
return _tokenAdmin;
}
@override @override
String getUserID() { String getUserID() {
return _userID!; return _userID!;

View File

@ -1,4 +1,3 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:simplecloudnotifier/state/globals.dart'; import 'package:simplecloudnotifier/state/globals.dart';

View File

@ -22,6 +22,14 @@ packages:
description: dart description: dart
source: sdk source: sdk
version: "0.3.3" version: "0.3.3"
action_slider:
dependency: "direct main"
description:
name: action_slider
sha256: fad0720cde9bf06c12594c15da17dba087556a3285875a91aee3d3a64a3072e2
url: "https://pub.dev"
source: hosted
version: "0.7.0"
analyzer: analyzer:
dependency: transitive dependency: transitive
description: description:

View File

@ -2,7 +2,7 @@ name: simplecloudnotifier
description: "Receive push messages" description: "Receive push messages"
publish_to: 'none' publish_to: 'none'
version: 2.0.0+474 version: 2.0.0+479
environment: environment:
sdk: '>=3.2.6 <4.0.0' sdk: '>=3.2.6 <4.0.0'
@ -40,6 +40,7 @@ dependencies:
mobile_scanner: ^6.0.1 mobile_scanner: ^6.0.1
settings_ui: ^2.0.2 settings_ui: ^2.0.2
git_stamp: ^5.10.0 git_stamp: ^5.10.0
action_slider: ^0.7.0
dependency_overrides: dependency_overrides:
font_awesome_flutter: font_awesome_flutter:
path: deps/font_awesome_flutter path: deps/font_awesome_flutter

View File

@ -16,31 +16,31 @@ type DBLogger struct {
Ident string Ident string
} }
func (l DBLogger) PrePing(ctx context.Context) error { func (l DBLogger) PrePing(ctx context.Context, meta sq.PrePingMeta) error {
log.Debug().Msg("[SQL-PING]") log.Debug().Msg("[SQL-PING]")
return nil return nil
} }
func (l DBLogger) PreTxBegin(ctx context.Context, txid uint16) error { func (l DBLogger) PreTxBegin(ctx context.Context, txid uint16, meta sq.PreTxBeginMeta) error {
log.Debug().Msg(fmt.Sprintf("[SQL-TX<%s|%d>-START]", l.Ident, txid)) log.Debug().Msg(fmt.Sprintf("[SQL-TX<%s|%d>-START]", l.Ident, txid))
return nil return nil
} }
func (l DBLogger) PreTxCommit(txid uint16) error { func (l DBLogger) PreTxCommit(txid uint16, meta sq.PreTxCommitMeta) error {
log.Debug().Msg(fmt.Sprintf("[SQL-TX<%s|%d>-COMMIT]", l.Ident, txid)) log.Debug().Msg(fmt.Sprintf("[SQL-TX<%s|%d>-COMMIT]", l.Ident, txid))
return nil return nil
} }
func (l DBLogger) PreTxRollback(txid uint16) error { func (l DBLogger) PreTxRollback(txid uint16, meta sq.PreTxRollbackMeta) error {
log.Debug().Msg(fmt.Sprintf("[SQL-TX<%s|%d>-ROLLBACK]", l.Ident, txid)) log.Debug().Msg(fmt.Sprintf("[SQL-TX<%s|%d>-ROLLBACK]", l.Ident, txid))
return nil return nil
} }
func (l DBLogger) PreQuery(ctx context.Context, txID *uint16, sql *string, params *sq.PP) error { func (l DBLogger) PreQuery(ctx context.Context, txID *uint16, sql *string, params *sq.PP, meta sq.PreQueryMeta) error {
if txID == nil { if txID == nil {
log.Debug().Msg(fmt.Sprintf("[SQL<%s>-QUERY] %s", l.Ident, fmtSQLPrint(*sql))) log.Debug().Msg(fmt.Sprintf("[SQL<%s>-QUERY] %s", l.Ident, fmtSQLPrint(*sql)))
} else { } else {
@ -50,7 +50,7 @@ func (l DBLogger) PreQuery(ctx context.Context, txID *uint16, sql *string, param
return nil return nil
} }
func (l DBLogger) PreExec(ctx context.Context, txID *uint16, sql *string, params *sq.PP) error { func (l DBLogger) PreExec(ctx context.Context, txID *uint16, sql *string, params *sq.PP, meta sq.PreExecMeta) error {
if txID == nil { if txID == nil {
log.Debug().Msg(fmt.Sprintf("[SQL-<%s>-EXEC] %s", l.Ident, fmtSQLPrint(*sql))) log.Debug().Msg(fmt.Sprintf("[SQL-<%s>-EXEC] %s", l.Ident, fmtSQLPrint(*sql)))
} else { } else {
@ -60,27 +60,27 @@ func (l DBLogger) PreExec(ctx context.Context, txID *uint16, sql *string, params
return nil return nil
} }
func (l DBLogger) PostPing(result error) { func (l DBLogger) PostPing(result error, meta sq.PostPingMeta) {
// //
} }
func (l DBLogger) PostTxBegin(txid uint16, result error) { func (l DBLogger) PostTxBegin(txid uint16, result error, meta sq.PostTxBeginMeta) {
// //
} }
func (l DBLogger) PostTxCommit(txid uint16, result error) { func (l DBLogger) PostTxCommit(txid uint16, result error, meta sq.PostTxCommitMeta) {
// //
} }
func (l DBLogger) PostTxRollback(txid uint16, result error) { func (l DBLogger) PostTxRollback(txid uint16, result error, meta sq.PostTxRollbackMeta) {
// //
} }
func (l DBLogger) PostQuery(txID *uint16, sqlOriginal string, sqlReal string, params sq.PP) { func (l DBLogger) PostQuery(txID *uint16, sqlOriginal string, sqlReal string, params sq.PP, result error, meta sq.PostQueryMeta) {
// //
} }
func (l DBLogger) PostExec(txID *uint16, sqlOriginal string, sqlReal string, params sq.PP) { func (l DBLogger) PostExec(txID *uint16, sqlOriginal string, sqlReal string, params sq.PP, result error, meta sq.PostExecMeta) {
// //
} }

View File

@ -101,23 +101,23 @@ func (pp *DBPreprocessor) Init(ctx context.Context) error {
return nil return nil
} }
func (pp *DBPreprocessor) PrePing(ctx context.Context) error { func (pp *DBPreprocessor) PrePing(ctx context.Context, meta sq.PrePingMeta) error {
return nil return nil
} }
func (pp *DBPreprocessor) PreTxBegin(ctx context.Context, txid uint16) error { func (pp *DBPreprocessor) PreTxBegin(ctx context.Context, txid uint16, meta sq.PreTxBeginMeta) error {
return nil return nil
} }
func (pp *DBPreprocessor) PreTxCommit(txid uint16) error { func (pp *DBPreprocessor) PreTxCommit(txid uint16, meta sq.PreTxCommitMeta) error {
return nil return nil
} }
func (pp *DBPreprocessor) PreTxRollback(txid uint16) error { func (pp *DBPreprocessor) PreTxRollback(txid uint16, meta sq.PreTxRollbackMeta) error {
return nil return nil
} }
func (pp *DBPreprocessor) PreQuery(ctx context.Context, txID *uint16, sql *string, params *sq.PP) error { func (pp *DBPreprocessor) PreQuery(ctx context.Context, txID *uint16, sql *string, params *sq.PP, meta sq.PreQueryMeta) error {
sqlOriginal := *sql sqlOriginal := *sql
pp.lock.Lock() pp.lock.Lock()
@ -223,30 +223,30 @@ func (pp *DBPreprocessor) PreQuery(ctx context.Context, txID *uint16, sql *strin
return nil return nil
} }
func (pp *DBPreprocessor) PreExec(ctx context.Context, txID *uint16, sql *string, params *sq.PP) error { func (pp *DBPreprocessor) PreExec(ctx context.Context, txID *uint16, sql *string, params *sq.PP, meta sq.PreExecMeta) error {
return nil return nil
} }
func (pp *DBPreprocessor) PostPing(result error) { func (pp *DBPreprocessor) PostPing(result error, meta sq.PostPingMeta) {
// //
} }
func (pp *DBPreprocessor) PostTxBegin(txid uint16, result error) { func (pp *DBPreprocessor) PostTxBegin(txid uint16, result error, meta sq.PostTxBeginMeta) {
// //
} }
func (pp *DBPreprocessor) PostTxCommit(txid uint16, result error) { func (pp *DBPreprocessor) PostTxCommit(txid uint16, result error, meta sq.PostTxCommitMeta) {
// //
} }
func (pp *DBPreprocessor) PostTxRollback(txid uint16, result error) { func (pp *DBPreprocessor) PostTxRollback(txid uint16, result error, meta sq.PostTxRollbackMeta) {
// //
} }
func (pp *DBPreprocessor) PostQuery(txID *uint16, sqlOriginal string, sqlReal string, params sq.PP) { func (pp *DBPreprocessor) PostQuery(txID *uint16, sqlOriginal string, sqlReal string, params sq.PP, result error, meta sq.PostQueryMeta) {
// //
} }
func (pp *DBPreprocessor) PostExec(txID *uint16, sqlOriginal string, sqlReal string, params sq.PP) { func (pp *DBPreprocessor) PostExec(txID *uint16, sqlOriginal string, sqlReal string, params sq.PP, result error, meta sq.PostExecMeta) {
// //
} }

View File

@ -19,63 +19,39 @@
"parameters": [ "parameters": [
{ {
"type": "string", "type": "string",
"example": "test",
"name": "channel",
"in": "query"
},
{
"type": "string",
"example": "This is a message",
"name": "content", "name": "content",
"in": "query" "in": "query"
}, },
{ {
"type": "string", "type": "string",
"example": "P3TNH8mvv14fm",
"name": "key",
"in": "query"
},
{
"type": "string",
"example": "db8b0e6a-a08c-4646",
"name": "msg_id", "name": "msg_id",
"in": "query" "in": "query"
}, },
{ {
"enum": [
0,
1,
2
],
"type": "integer", "type": "integer",
"example": 1,
"name": "priority", "name": "priority",
"in": "query" "in": "query"
}, },
{
"type": "string",
"example": "example-server",
"name": "sender_name",
"in": "query"
},
{ {
"type": "number", "type": "number",
"example": 1669824037,
"name": "timestamp", "name": "timestamp",
"in": "query" "in": "query"
}, },
{ {
"type": "string", "type": "string",
"example": "Hello World",
"name": "title", "name": "title",
"in": "query" "in": "query"
}, },
{ {
"type": "string", "type": "integer",
"example": "7725",
"name": "user_id", "name": "user_id",
"in": "query" "in": "query"
}, },
{
"type": "string",
"name": "user_key",
"in": "query"
},
{ {
"description": " ", "description": " ",
"name": "post_body", "name": "post_body",
@ -86,62 +62,38 @@
}, },
{ {
"type": "string", "type": "string",
"example": "test",
"name": "channel",
"in": "formData"
},
{
"type": "string",
"example": "This is a message",
"name": "content", "name": "content",
"in": "formData" "in": "formData"
}, },
{ {
"type": "string", "type": "string",
"example": "P3TNH8mvv14fm",
"name": "key",
"in": "formData"
},
{
"type": "string",
"example": "db8b0e6a-a08c-4646",
"name": "msg_id", "name": "msg_id",
"in": "formData" "in": "formData"
}, },
{ {
"enum": [
0,
1,
2
],
"type": "integer", "type": "integer",
"example": 1,
"name": "priority", "name": "priority",
"in": "formData" "in": "formData"
}, },
{
"type": "string",
"example": "example-server",
"name": "sender_name",
"in": "formData"
},
{ {
"type": "number", "type": "number",
"example": 1669824037,
"name": "timestamp", "name": "timestamp",
"in": "formData" "in": "formData"
}, },
{ {
"type": "string", "type": "string",
"example": "Hello World",
"name": "title", "name": "title",
"in": "formData" "in": "formData"
}, },
{ {
"type": "string", "type": "integer",
"example": "7725",
"name": "user_id", "name": "user_id",
"in": "formData" "in": "formData"
},
{
"type": "string",
"name": "user_key",
"in": "formData"
} }
], ],
"responses": { "responses": {
@ -1372,7 +1324,7 @@
} }
} }
}, },
"patch": { "delete": {
"tags": [ "tags": [
"API-v2" "API-v2"
], ],
@ -1419,6 +1371,71 @@
} }
} }
} }
},
"patch": {
"description": "The body-values are optional, only send the ones you want to update",
"tags": [
"API-v2"
],
"summary": "(Partially) update a user",
"operationId": "api-user-update",
"parameters": [
{
"type": "string",
"description": "UserID",
"name": "uid",
"in": "path",
"required": true
},
{
"description": "Change the username (send an empty string to clear it)",
"name": "username",
"in": "body",
"schema": {
"type": "string"
}
},
{
"description": "Send a verification of premium purchase",
"name": "pro_token",
"in": "body",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/models.User"
}
},
"400": {
"description": "supplied values/parameters cannot be parsed / are invalid",
"schema": {
"$ref": "#/definitions/ginresp.apiError"
}
},
"401": {
"description": "user is not authorized / has missing permissions",
"schema": {
"$ref": "#/definitions/ginresp.apiError"
}
},
"404": {
"description": "user not found",
"schema": {
"$ref": "#/definitions/ginresp.apiError"
}
},
"500": {
"description": "internal server error",
"schema": {
"$ref": "#/definitions/ginresp.apiError"
}
}
}
} }
}, },
"/api/v2/users/{uid}/channels": { "/api/v2/users/{uid}/channels": {
@ -2795,63 +2812,39 @@
"parameters": [ "parameters": [
{ {
"type": "string", "type": "string",
"example": "test",
"name": "channel",
"in": "query"
},
{
"type": "string",
"example": "This is a message",
"name": "content", "name": "content",
"in": "query" "in": "query"
}, },
{ {
"type": "string", "type": "string",
"example": "P3TNH8mvv14fm",
"name": "key",
"in": "query"
},
{
"type": "string",
"example": "db8b0e6a-a08c-4646",
"name": "msg_id", "name": "msg_id",
"in": "query" "in": "query"
}, },
{ {
"enum": [
0,
1,
2
],
"type": "integer", "type": "integer",
"example": 1,
"name": "priority", "name": "priority",
"in": "query" "in": "query"
}, },
{
"type": "string",
"example": "example-server",
"name": "sender_name",
"in": "query"
},
{ {
"type": "number", "type": "number",
"example": 1669824037,
"name": "timestamp", "name": "timestamp",
"in": "query" "in": "query"
}, },
{ {
"type": "string", "type": "string",
"example": "Hello World",
"name": "title", "name": "title",
"in": "query" "in": "query"
}, },
{ {
"type": "string", "type": "integer",
"example": "7725",
"name": "user_id", "name": "user_id",
"in": "query" "in": "query"
}, },
{
"type": "string",
"name": "user_key",
"in": "query"
},
{ {
"description": " ", "description": " ",
"name": "post_body", "name": "post_body",
@ -2862,62 +2855,38 @@
}, },
{ {
"type": "string", "type": "string",
"example": "test",
"name": "channel",
"in": "formData"
},
{
"type": "string",
"example": "This is a message",
"name": "content", "name": "content",
"in": "formData" "in": "formData"
}, },
{ {
"type": "string", "type": "string",
"example": "P3TNH8mvv14fm",
"name": "key",
"in": "formData"
},
{
"type": "string",
"example": "db8b0e6a-a08c-4646",
"name": "msg_id", "name": "msg_id",
"in": "formData" "in": "formData"
}, },
{ {
"enum": [
0,
1,
2
],
"type": "integer", "type": "integer",
"example": 1,
"name": "priority", "name": "priority",
"in": "formData" "in": "formData"
}, },
{
"type": "string",
"example": "example-server",
"name": "sender_name",
"in": "formData"
},
{ {
"type": "number", "type": "number",
"example": 1669824037,
"name": "timestamp", "name": "timestamp",
"in": "formData" "in": "formData"
}, },
{ {
"type": "string", "type": "string",
"example": "Hello World",
"name": "title", "name": "title",
"in": "formData" "in": "formData"
}, },
{ {
"type": "string", "type": "integer",
"example": "7725",
"name": "user_id", "name": "user_id",
"in": "formData" "in": "formData"
},
{
"type": "string",
"name": "user_key",
"in": "formData"
} }
], ],
"responses": { "responses": {
@ -2965,121 +2934,73 @@
"parameters": [ "parameters": [
{ {
"type": "string", "type": "string",
"example": "test",
"name": "channel",
"in": "query"
},
{
"type": "string",
"example": "This is a message",
"name": "content", "name": "content",
"in": "query" "in": "query"
}, },
{ {
"type": "string", "type": "string",
"example": "P3TNH8mvv14fm",
"name": "key",
"in": "query"
},
{
"type": "string",
"example": "db8b0e6a-a08c-4646",
"name": "msg_id", "name": "msg_id",
"in": "query" "in": "query"
}, },
{ {
"enum": [
0,
1,
2
],
"type": "integer", "type": "integer",
"example": 1,
"name": "priority", "name": "priority",
"in": "query" "in": "query"
}, },
{
"type": "string",
"example": "example-server",
"name": "sender_name",
"in": "query"
},
{ {
"type": "number", "type": "number",
"example": 1669824037,
"name": "timestamp", "name": "timestamp",
"in": "query" "in": "query"
}, },
{ {
"type": "string", "type": "string",
"example": "Hello World",
"name": "title", "name": "title",
"in": "query" "in": "query"
}, },
{ {
"type": "string", "type": "integer",
"example": "7725",
"name": "user_id", "name": "user_id",
"in": "query" "in": "query"
}, },
{ {
"type": "string", "type": "string",
"example": "test", "name": "user_key",
"name": "channel", "in": "query"
"in": "formData"
}, },
{ {
"type": "string", "type": "string",
"example": "This is a message",
"name": "content", "name": "content",
"in": "formData" "in": "formData"
}, },
{ {
"type": "string", "type": "string",
"example": "P3TNH8mvv14fm",
"name": "key",
"in": "formData"
},
{
"type": "string",
"example": "db8b0e6a-a08c-4646",
"name": "msg_id", "name": "msg_id",
"in": "formData" "in": "formData"
}, },
{ {
"enum": [
0,
1,
2
],
"type": "integer", "type": "integer",
"example": 1,
"name": "priority", "name": "priority",
"in": "formData" "in": "formData"
}, },
{
"type": "string",
"example": "example-server",
"name": "sender_name",
"in": "formData"
},
{ {
"type": "number", "type": "number",
"example": 1669824037,
"name": "timestamp", "name": "timestamp",
"in": "formData" "in": "formData"
}, },
{ {
"type": "string", "type": "string",
"example": "Hello World",
"name": "title", "name": "title",
"in": "formData" "in": "formData"
}, },
{ {
"type": "string", "type": "integer",
"example": "7725",
"name": "user_id", "name": "user_id",
"in": "formData" "in": "formData"
},
{
"type": "string",
"name": "user_key",
"in": "formData"
} }
], ],
"responses": { "responses": {
@ -3135,6 +3056,7 @@
1153, 1153,
1152, 1152,
1161, 1161,
1162,
1171, 1171,
1201, 1201,
1202, 1202,
@ -3181,6 +3103,7 @@
"BINDFAIL_URI_PARAM", "BINDFAIL_URI_PARAM",
"BINDFAIL_HEADER_PARAM", "BINDFAIL_HEADER_PARAM",
"INVALID_BODY_PARAM", "INVALID_BODY_PARAM",
"INVALID_QUERY_PARAM",
"INVALID_ENUM_VALUE", "INVALID_ENUM_VALUE",
"NO_TITLE", "NO_TITLE",
"TITLE_TOO_LONG", "TITLE_TOO_LONG",
@ -3591,46 +3514,26 @@
"handler.SendMessage.combined": { "handler.SendMessage.combined": {
"type": "object", "type": "object",
"properties": { "properties": {
"channel": {
"type": "string",
"example": "test"
},
"content": { "content": {
"type": "string", "type": "string"
"example": "This is a message"
},
"key": {
"type": "string",
"example": "P3TNH8mvv14fm"
}, },
"msg_id": { "msg_id": {
"type": "string", "type": "string"
"example": "db8b0e6a-a08c-4646"
}, },
"priority": { "priority": {
"type": "integer", "type": "integer"
"enum": [
0,
1,
2
],
"example": 1
},
"sender_name": {
"type": "string",
"example": "example-server"
}, },
"timestamp": { "timestamp": {
"type": "number", "type": "number"
"example": 1669824037
}, },
"title": { "title": {
"type": "string", "type": "string"
"example": "Hello World"
}, },
"user_id": { "user_id": {
"type": "string", "type": "integer"
"example": "7725" },
"user_key": {
"type": "string"
} }
} }
}, },
@ -3659,7 +3562,7 @@
"type": "integer" "type": "integer"
}, },
"scn_msg_id": { "scn_msg_id": {
"type": "string" "type": "integer"
}, },
"success": { "success": {
"type": "boolean" "type": "boolean"

View File

@ -16,6 +16,7 @@ definitions:
- 1153 - 1153
- 1152 - 1152
- 1161 - 1161
- 1162
- 1171 - 1171
- 1201 - 1201
- 1202 - 1202
@ -62,6 +63,7 @@ definitions:
- BINDFAIL_URI_PARAM - BINDFAIL_URI_PARAM
- BINDFAIL_HEADER_PARAM - BINDFAIL_HEADER_PARAM
- INVALID_BODY_PARAM - INVALID_BODY_PARAM
- INVALID_QUERY_PARAM
- INVALID_ENUM_VALUE - INVALID_ENUM_VALUE
- NO_TITLE - NO_TITLE
- TITLE_TOO_LONG - TITLE_TOO_LONG
@ -338,36 +340,19 @@ definitions:
type: object type: object
handler.SendMessage.combined: handler.SendMessage.combined:
properties: properties:
channel:
example: test
type: string
content: content:
example: This is a message
type: string
key:
example: P3TNH8mvv14fm
type: string type: string
msg_id: msg_id:
example: db8b0e6a-a08c-4646
type: string type: string
priority: priority:
enum:
- 0
- 1
- 2
example: 1
type: integer type: integer
sender_name:
example: example-server
type: string
timestamp: timestamp:
example: 1669824037
type: number type: number
title: title:
example: Hello World
type: string type: string
user_id: user_id:
example: "7725" type: integer
user_key:
type: string type: string
type: object type: object
handler.SendMessage.response: handler.SendMessage.response:
@ -387,7 +372,7 @@ definitions:
quota_max: quota_max:
type: integer type: integer
scn_msg_id: scn_msg_id:
type: string type: integer
success: success:
type: boolean type: boolean
suppress_send: suppress_send:
@ -867,90 +852,52 @@ paths:
description: All parameter can be set via query-parameter or the json body. description: All parameter can be set via query-parameter or the json body.
Only UserID, UserKey and Title are required Only UserID, UserKey and Title are required
parameters: parameters:
- example: test - in: query
in: query
name: channel
type: string
- example: This is a message
in: query
name: content name: content
type: string type: string
- example: P3TNH8mvv14fm - in: query
in: query
name: key
type: string
- example: db8b0e6a-a08c-4646
in: query
name: msg_id name: msg_id
type: string type: string
- enum: - in: query
- 0
- 1
- 2
example: 1
in: query
name: priority name: priority
type: integer type: integer
- example: example-server - in: query
in: query
name: sender_name
type: string
- example: 1669824037
in: query
name: timestamp name: timestamp
type: number type: number
- example: Hello World - in: query
in: query
name: title name: title
type: string type: string
- example: "7725" - in: query
in: query
name: user_id name: user_id
type: integer
- in: query
name: user_key
type: string type: string
- description: ' ' - description: ' '
in: body in: body
name: post_body name: post_body
schema: schema:
$ref: '#/definitions/handler.SendMessage.combined' $ref: '#/definitions/handler.SendMessage.combined'
- example: test - in: formData
in: formData
name: channel
type: string
- example: This is a message
in: formData
name: content name: content
type: string type: string
- example: P3TNH8mvv14fm - in: formData
in: formData
name: key
type: string
- example: db8b0e6a-a08c-4646
in: formData
name: msg_id name: msg_id
type: string type: string
- enum: - in: formData
- 0
- 1
- 2
example: 1
in: formData
name: priority name: priority
type: integer type: integer
- example: example-server - in: formData
in: formData
name: sender_name
type: string
- example: 1669824037
in: formData
name: timestamp name: timestamp
type: number type: number
- example: Hello World - in: formData
in: formData
name: title name: title
type: string type: string
- example: "7725" - in: formData
in: formData
name: user_id name: user_id
type: integer
- in: formData
name: user_key
type: string type: string
responses: responses:
"200": "200":
@ -1760,6 +1707,39 @@ paths:
tags: tags:
- API-v2 - API-v2
/api/v2/users/{uid}: /api/v2/users/{uid}:
delete:
operationId: api-user-delete
parameters:
- description: UserID
in: path
name: uid
required: true
type: string
responses:
"200":
description: OK
schema:
$ref: '#/definitions/models.User'
"400":
description: supplied values/parameters cannot be parsed / are invalid
schema:
$ref: '#/definitions/ginresp.apiError'
"401":
description: user is not authorized / has missing permissions
schema:
$ref: '#/definitions/ginresp.apiError'
"404":
description: user not found
schema:
$ref: '#/definitions/ginresp.apiError'
"500":
description: internal server error
schema:
$ref: '#/definitions/ginresp.apiError'
summary: (Self-)Deletes a user (including all entities - all messages, channels,
clients, .....)
tags:
- API-v2
get: get:
operationId: api-user-get operationId: api-user-get
parameters: parameters:
@ -1793,13 +1773,24 @@ paths:
tags: tags:
- API-v2 - API-v2
patch: patch:
operationId: api-user-delete description: The body-values are optional, only send the ones you want to update
operationId: api-user-update
parameters: parameters:
- description: UserID - description: UserID
in: path in: path
name: uid name: uid
required: true required: true
type: string type: string
- description: Change the username (send an empty string to clear it)
in: body
name: username
schema:
type: string
- description: Send a verification of premium purchase
in: body
name: pro_token
schema:
type: string
responses: responses:
"200": "200":
description: OK description: OK
@ -1821,8 +1812,7 @@ paths:
description: internal server error description: internal server error
schema: schema:
$ref: '#/definitions/ginresp.apiError' $ref: '#/definitions/ginresp.apiError'
summary: (Self-)Deletes a user (including all entities - all messages, channels, summary: (Partially) update a user
clients, .....)
tags: tags:
- API-v2 - API-v2
/api/v2/users/{uid}/channels: /api/v2/users/{uid}/channels:
@ -2772,90 +2762,52 @@ paths:
description: All parameter can be set via query-parameter or the json body. description: All parameter can be set via query-parameter or the json body.
Only UserID, UserKey and Title are required Only UserID, UserKey and Title are required
parameters: parameters:
- example: test - in: query
in: query
name: channel
type: string
- example: This is a message
in: query
name: content name: content
type: string type: string
- example: P3TNH8mvv14fm - in: query
in: query
name: key
type: string
- example: db8b0e6a-a08c-4646
in: query
name: msg_id name: msg_id
type: string type: string
- enum: - in: query
- 0
- 1
- 2
example: 1
in: query
name: priority name: priority
type: integer type: integer
- example: example-server - in: query
in: query
name: sender_name
type: string
- example: 1669824037
in: query
name: timestamp name: timestamp
type: number type: number
- example: Hello World - in: query
in: query
name: title name: title
type: string type: string
- example: "7725" - in: query
in: query
name: user_id name: user_id
type: integer
- in: query
name: user_key
type: string type: string
- description: ' ' - description: ' '
in: body in: body
name: post_body name: post_body
schema: schema:
$ref: '#/definitions/handler.SendMessage.combined' $ref: '#/definitions/handler.SendMessage.combined'
- example: test - in: formData
in: formData
name: channel
type: string
- example: This is a message
in: formData
name: content name: content
type: string type: string
- example: P3TNH8mvv14fm - in: formData
in: formData
name: key
type: string
- example: db8b0e6a-a08c-4646
in: formData
name: msg_id name: msg_id
type: string type: string
- enum: - in: formData
- 0
- 1
- 2
example: 1
in: formData
name: priority name: priority
type: integer type: integer
- example: example-server - in: formData
in: formData
name: sender_name
type: string
- example: 1669824037
in: formData
name: timestamp name: timestamp
type: number type: number
- example: Hello World - in: formData
in: formData
name: title name: title
type: string type: string
- example: "7725" - in: formData
in: formData
name: user_id name: user_id
type: integer
- in: formData
name: user_key
type: string type: string
responses: responses:
"200": "200":
@ -2888,85 +2840,47 @@ paths:
description: All parameter can be set via query-parameter or form-data body. description: All parameter can be set via query-parameter or form-data body.
Only UserID, UserKey and Title are required Only UserID, UserKey and Title are required
parameters: parameters:
- example: test - in: query
in: query
name: channel
type: string
- example: This is a message
in: query
name: content name: content
type: string type: string
- example: P3TNH8mvv14fm - in: query
in: query
name: key
type: string
- example: db8b0e6a-a08c-4646
in: query
name: msg_id name: msg_id
type: string type: string
- enum: - in: query
- 0
- 1
- 2
example: 1
in: query
name: priority name: priority
type: integer type: integer
- example: example-server - in: query
in: query
name: sender_name
type: string
- example: 1669824037
in: query
name: timestamp name: timestamp
type: number type: number
- example: Hello World - in: query
in: query
name: title name: title
type: string type: string
- example: "7725" - in: query
in: query
name: user_id name: user_id
type: integer
- in: query
name: user_key
type: string type: string
- example: test - in: formData
in: formData
name: channel
type: string
- example: This is a message
in: formData
name: content name: content
type: string type: string
- example: P3TNH8mvv14fm - in: formData
in: formData
name: key
type: string
- example: db8b0e6a-a08c-4646
in: formData
name: msg_id name: msg_id
type: string type: string
- enum: - in: formData
- 0
- 1
- 2
example: 1
in: formData
name: priority name: priority
type: integer type: integer
- example: example-server - in: formData
in: formData
name: sender_name
type: string
- example: 1669824037
in: formData
name: timestamp name: timestamp
type: number type: number
- example: Hello World - in: formData
in: formData
name: title name: title
type: string type: string
- example: "7725" - in: formData
in: formData
name: user_id name: user_id
type: integer
- in: formData
name: user_key
type: string type: string
responses: responses:
"200": "200":

View File

@ -203,10 +203,16 @@ func TestDeleteUser(t *testing.T) {
tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/v2/users/"+uid) tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/v2/users/"+uid)
tt.RequestAuthDeleteShouldFail(t, readtok, baseUrl, "/api/v2/users/"+uid, nil, 401, apierr.USER_AUTH_FAILED) tt.RequestAuthDeleteShouldFail(t, readtok, baseUrl, "/api/v2/users/"+uid, nil, 401, apierr.USER_AUTH_FAILED)
tt.RequestAuthDeleteShouldFail(t, readtok, baseUrl, "/api/v2/users/"+uid+"?confirm=false", nil, 401, apierr.USER_AUTH_FAILED)
tt.RequestAuthDeleteShouldFail(t, readtok, baseUrl, "/api/v2/users/"+uid+"?confirm=true", nil, 401, apierr.USER_AUTH_FAILED)
tt.RequestAuthDeleteShouldFail(t, sendtok, baseUrl, "/api/v2/users/"+uid, nil, 401, apierr.USER_AUTH_FAILED) tt.RequestAuthDeleteShouldFail(t, sendtok, baseUrl, "/api/v2/users/"+uid, nil, 401, apierr.USER_AUTH_FAILED)
tt.RequestAuthDeleteShouldFail(t, sendtok, baseUrl, "/api/v2/users/"+uid+"?confirm=false", nil, 401, apierr.USER_AUTH_FAILED)
tt.RequestAuthDeleteShouldFail(t, sendtok, baseUrl, "/api/v2/users/"+uid+"?confirm=true", nil, 401, apierr.USER_AUTH_FAILED)
tt.RequestAuthDelete[tt.Void](t, admintok, baseUrl, "/api/v2/users/"+uid, nil) tt.RequestAuthDeleteShouldFail(t, admintok, baseUrl, "/api/v2/users/"+uid, nil, 400, apierr.INVALID_QUERY_PARAM)
tt.RequestAuthDeleteShouldFail(t, admintok, baseUrl, "/api/v2/users/"+uid+"?confirm=false", nil, 400, apierr.INVALID_QUERY_PARAM)
tt.RequestAuthDelete[tt.Void](t, admintok, baseUrl, "/api/v2/users/"+uid+"?confirm=true", nil)
tt.RequestAuthGetShouldFail(t, admintok, baseUrl, "/api/v2/users/"+uid, 401, apierr.USER_AUTH_FAILED) tt.RequestAuthGetShouldFail(t, admintok, baseUrl, "/api/v2/users/"+uid, 401, apierr.USER_AUTH_FAILED)
} }