migrated feedback submission from the legacy mhsl.eu endpoint to the MarianumConnect API

This commit is contained in:
2026-07-06 22:36:11 +02:00
parent ddbb3fbc19
commit c48f5ef215
5 changed files with 68 additions and 78 deletions
@@ -0,0 +1,63 @@
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:dio/dio.dart';
import 'package:package_info_plus/package_info_plus.dart';
import '../../errors/marianumconnect_error.dart';
import '../../marianumconnect_api.dart';
import '../../marianumconnect_endpoint.dart';
/// Submits user feedback to MarianumConnect (`POST me/feedback`, bearer-auth).
/// The optional screenshot is sent base64-encoded. Replaces the legacy mhsl.eu
/// `server/feedback` endpoint — the user no longer needs to be sent explicitly,
/// the bearer token identifies them.
class SubmitFeedback {
final Dio _dio;
SubmitFeedback({Dio? dio}) : _dio = dio ?? MarianumConnectApi.dio();
Future<void> run({
required String message,
Uint8List? screenshot,
String screenshotContentType = 'image/png',
}) async {
try {
final package = await PackageInfo.fromPlatform();
final screenshotBase64 = screenshot != null ? base64Encode(screenshot) : null;
await _dio.post<void>(
MarianumConnectEndpoint.resolve('me/feedback'),
data: {
'message': message,
'screenshot': ?screenshotBase64,
'screenshotContentType': screenshot != null ? screenshotContentType : null,
'platform': _platform(),
'appVersion': package.version,
'appBuild': int.tryParse(package.buildNumber),
'deviceModel': await _deviceModel(),
},
);
} on DioException catch (e) {
throw mapMarianumConnectError(e);
}
}
static String? _platform() {
if (Platform.isAndroid) return 'android';
if (Platform.isIOS) return 'ios';
return null;
}
static Future<String?> _deviceModel() async {
try {
final info = DeviceInfoPlugin();
if (Platform.isAndroid) return (await info.androidInfo).model;
if (Platform.isIOS) return (await info.iosInfo).utsname.machine;
} catch (_) {
// Device-Plugin nicht verfügbar (z.B. Tests).
}
return null;
}
}
@@ -1,19 +0,0 @@
import 'dart:convert';
import 'package:http/http.dart';
import 'package:http/http.dart' as http;
import '../../mhsl_api.dart';
import 'add_feedback_params.dart';
class AddFeedback extends MhslApi<void> {
AddFeedbackParams params;
AddFeedback(this.params) : super('server/feedback');
@override
void assemble(String raw) {}
@override
Future<Response>? request(Uri uri) =>
http.post(uri, body: jsonEncode(params.toJson()));
}
@@ -1,22 +0,0 @@
import 'package:json_annotation/json_annotation.dart';
part 'add_feedback_params.g.dart';
@JsonSerializable()
class AddFeedbackParams {
String user;
String feedback;
String? screenshot;
int appVersion;
AddFeedbackParams({
required this.user,
required this.feedback,
this.screenshot,
required this.appVersion,
});
factory AddFeedbackParams.fromJson(Map<String, dynamic> json) =>
_$AddFeedbackParamsFromJson(json);
Map<String, dynamic> toJson() => _$AddFeedbackParamsToJson(this);
}
@@ -1,23 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'add_feedback_params.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
AddFeedbackParams _$AddFeedbackParamsFromJson(Map<String, dynamic> json) =>
AddFeedbackParams(
user: json['user'] as String,
feedback: json['feedback'] as String,
screenshot: json['screenshot'] as String?,
appVersion: (json['appVersion'] as num).toInt(),
);
Map<String, dynamic> _$AddFeedbackParamsToJson(AddFeedbackParams instance) =>
<String, dynamic>{
'user': instance.user,
'feedback': instance.feedback,
'screenshot': instance.screenshot,
'appVersion': instance.appVersion,
};
@@ -1,12 +1,8 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
import '../../../../api/mhsl/server/feedback/add_feedback.dart';
import '../../../../api/mhsl/server/feedback/add_feedback_params.dart';
import '../../../../model/account_data.dart';
import '../../../../api/marianumconnect/queries/submit_feedback/submit_feedback.dart';
import '../../../../widget/async_action_button.dart';
import '../../../../widget/file_pick.dart';
import '../../../../widget/focus_behaviour.dart';
@@ -58,15 +54,10 @@ class _FeedbackDialogState extends State<FeedbackDialog> {
setState(() => _textFieldEmpty = true);
return;
}
final info = await PackageInfo.fromPlatform();
await AddFeedback(
AddFeedbackParams(
user: AccountData().getUserSecret(),
feedback: _feedbackInput.text,
screenshot: _image != null ? base64Encode(_image!) : null,
appVersion: int.parse(info.buildNumber),
),
).run();
await SubmitFeedback().run(
message: _feedbackInput.text,
screenshot: _image,
);
if (!mounted) return;
Navigator.of(context).pop();
InfoDialog.show(context, 'Danke für dein Feedback!');