API authentication
All checks were successful
ci/woodpecker/push/flutterBuild Pipeline was successful
All checks were successful
ci/woodpecker/push/flutterBuild Pipeline was successful
This commit is contained in:
parent
4cd006be85
commit
ec02aaa406
7 changed files with 320 additions and 19 deletions
|
@ -1,6 +1,10 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:gitea_client/model/user.dart';
|
||||
import 'package:gitea_client/service/AuthenticationChecker.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
import 'model/ApiAccess.dart';
|
||||
|
||||
void main() {
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
@ -17,6 +21,22 @@ class MyApp extends StatelessWidget {
|
|||
primarySwatch: Colors.lightGreen,
|
||||
),
|
||||
home: const LoginPage(title: 'Gitea client'),
|
||||
routes: {
|
||||
|
||||
},
|
||||
onGenerateRoute: (route) {
|
||||
switch (route.name) { // <- here
|
||||
case "/loginstatus":
|
||||
return MaterialPageRoute(
|
||||
settings: const RouteSettings(name: "/parameterpage"),
|
||||
builder: (context) => StatefulLoginStatus(
|
||||
apiAccess: route.arguments as ApiAccess,
|
||||
),
|
||||
);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +80,8 @@ class StatefulLoginForm extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _LoginForm extends State<StatefulLoginForm> {
|
||||
final Uri getTokenUri = Uri.parse("https://www.jetbrains.com/help/youtrack/incloud/integration-with-gitea.html#enable-youtrack-integration-gitea");
|
||||
final Uri getTokenUri = Uri.parse(
|
||||
"https://www.jetbrains.com/help/youtrack/incloud/integration-with-gitea.html#enable-youtrack-integration-gitea");
|
||||
final tokenController = TextEditingController();
|
||||
final instanceController = TextEditingController();
|
||||
String instance = "gitea.com";
|
||||
|
@ -76,7 +97,7 @@ class _LoginForm extends State<StatefulLoginForm> {
|
|||
children: [
|
||||
DropdownButton(
|
||||
value: instance,
|
||||
items: <String>['gitea.com', 'codeberg.com', 'Other']
|
||||
items: <String>['gitea.com', 'codeberg.org', 'Other']
|
||||
.map<DropdownMenuItem<String>>((String value) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: value,
|
||||
|
@ -105,26 +126,89 @@ class _LoginForm extends State<StatefulLoginForm> {
|
|||
obscureText: true,
|
||||
),
|
||||
SizedBox(
|
||||
width: (media.width > 600) ? media.width * 0.25 : media.width * 0.5,
|
||||
width:
|
||||
(media.width > 600) ? media.width * 0.25 : media.width * 0.5,
|
||||
child: Container(
|
||||
padding: EdgeInsetsDirectional.all(15),
|
||||
child: ElevatedButton(
|
||||
child: const Text("Login"),
|
||||
onPressed: () => {
|
||||
|
||||
Navigator.pushNamed(context, "/loginstatus",
|
||||
arguments: ApiAccess(
|
||||
(instance == "Other")
|
||||
? instanceController.text
|
||||
: instance,
|
||||
tokenController.text))
|
||||
},
|
||||
),
|
||||
)),
|
||||
//
|
||||
TextButton(onPressed: () => {
|
||||
_launchUrl(getTokenUri)
|
||||
}, child: Text("Need a Token? Find out how to generate one!"))
|
||||
TextButton(
|
||||
onPressed: () => {_launchUrl(getTokenUri)},
|
||||
child: Text("Need a Token? Find out how to generate one!"))
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class StatefulLoginStatus extends StatefulWidget {
|
||||
final ApiAccess apiAccess;
|
||||
const StatefulLoginStatus({Key? key, required this.apiAccess}) : super(key: key);
|
||||
|
||||
@override
|
||||
_StatefulLoginStatus createState() => _StatefulLoginStatus();
|
||||
}
|
||||
|
||||
class _StatefulLoginStatus extends State<StatefulLoginStatus> {
|
||||
|
||||
|
||||
Future<AuthenticatedUser>? userRequest;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
userRequest = AuthenticationChecker(widget.apiAccess).getAuthenticatedUserOrError();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text("Login status"),
|
||||
),
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
FutureBuilder<AuthenticatedUser>(
|
||||
future: userRequest,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError){
|
||||
return Center(
|
||||
child: Text(
|
||||
"Hiba történt: ${snapshot.error}"
|
||||
),
|
||||
);
|
||||
} else if (snapshot.hasData){
|
||||
var user = snapshot.data!;
|
||||
final username = user.username;
|
||||
return Text("Logged in as $username");
|
||||
|
||||
} else {
|
||||
return Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
}
|
||||
)
|
||||
],
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void _launchUrl(Uri url) async {
|
||||
if (!await launchUrl(url)) throw 'Could not launch $url';
|
||||
}
|
||||
|
|
6
lib/model/ApiAccess.dart
Normal file
6
lib/model/ApiAccess.dart
Normal file
|
@ -0,0 +1,6 @@
|
|||
class ApiAccess{
|
||||
final String instance;
|
||||
final String token;
|
||||
|
||||
const ApiAccess(this.instance, this.token);
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:convert';
|
||||
|
||||
class AuthenticatedUser {
|
||||
int? id;
|
||||
String? login;
|
||||
|
|
21
lib/service/AuthenticationChecker.dart
Normal file
21
lib/service/AuthenticationChecker.dart
Normal file
|
@ -0,0 +1,21 @@
|
|||
import 'package:gitea_client/model/ApiAccess.dart';
|
||||
import 'package:gitea_client/service/gitea_service.dart';
|
||||
|
||||
import '../model/user.dart';
|
||||
|
||||
class AuthenticationChecker {
|
||||
final ApiAccess apiAccess;
|
||||
late GiteaServie service;
|
||||
AuthenticationChecker(this.apiAccess) {
|
||||
service = GiteaServie(apiAccess.instance, apiAccess.token);
|
||||
}
|
||||
|
||||
Future<AuthenticatedUser> getAuthenticatedUserOrError() async{
|
||||
final user = await service.getAuthenticatedUser();
|
||||
if(user.username != null) {
|
||||
return user;
|
||||
}
|
||||
throw Exception("Authentication failed");
|
||||
}
|
||||
|
||||
}
|
25
lib/service/gitea_service.dart
Normal file
25
lib/service/gitea_service.dart
Normal file
|
@ -0,0 +1,25 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:gitea_client/model/user.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
AuthenticatedUser _parseAuthenticatedUserResponse(String message){
|
||||
return AuthenticatedUser.fromJson(jsonDecode(message));
|
||||
}
|
||||
|
||||
class GiteaServie {
|
||||
final String apiUrl;
|
||||
final String _token;
|
||||
|
||||
const GiteaServie(this.apiUrl, this._token);
|
||||
|
||||
Future<AuthenticatedUser> getAuthenticatedUser() async {
|
||||
var response = await http.get(
|
||||
Uri.https(apiUrl, "api/v1/user", {
|
||||
"token": _token,
|
||||
}),
|
||||
);
|
||||
return compute(_parseAuthenticatedUserResponse, response.body);
|
||||
}
|
||||
}
|
163
pubspec.lock
163
pubspec.lock
|
@ -1,6 +1,27 @@
|
|||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
_fe_analyzer_shared:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "39.0.0"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -15,6 +36,20 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
build:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
build_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_config
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -29,6 +64,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
checked_yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: checked_yaml
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -43,6 +85,20 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.15.0"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: convert
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: crypto
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
cupertino_icons:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -50,6 +106,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
dart_style:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dart_style
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.2.3"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -57,6 +120,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.1.2"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
|
@ -84,6 +154,27 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
glob:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: glob
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
http:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: http
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.13.4"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_parser
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
intl:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -98,6 +189,20 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.6.3"
|
||||
json_annotation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: json_annotation
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.5.0"
|
||||
json_serializable:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: json_serializable
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.2.0"
|
||||
lints:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -105,6 +210,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: logging
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -126,6 +238,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.7.0"
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_config
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -140,11 +259,39 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pub_semver
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
pubspec_parse:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pubspec_parse
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_gen
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.2"
|
||||
source_helper:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_helper
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.2"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -195,7 +342,7 @@ packages:
|
|||
source: hosted
|
||||
version: "1.3.0"
|
||||
url_launcher:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: url_launcher
|
||||
url: "https://pub.dartlang.org"
|
||||
|
@ -257,6 +404,20 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: watcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: yaml
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
sdks:
|
||||
dart: ">=2.16.2 <3.0.0"
|
||||
flutter: ">=2.10.0"
|
||||
|
|
10
pubspec.yaml
10
pubspec.yaml
|
@ -32,8 +32,10 @@ dependencies:
|
|||
flutter_localizations:
|
||||
sdk: flutter
|
||||
intl: ^0.17.0
|
||||
|
||||
|
||||
# For opening links in the browser
|
||||
url_launcher: ^6.1.0
|
||||
# For http communication
|
||||
http: ^0.13.4
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
cupertino_icons: ^1.0.2
|
||||
|
@ -41,14 +43,14 @@ dependencies:
|
|||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
json_serializable: ^6.2.0
|
||||
# The "flutter_lints" package below contains a set of recommended lints to
|
||||
# encourage good coding practices. The lint set provided by the package is
|
||||
# activated in the `analysis_options.yaml` file located at the root of your
|
||||
# package. See that file for information about deactivating specific lint
|
||||
# rules and activating additional ones.
|
||||
flutter_lints: ^1.0.0
|
||||
url_launcher: ^6.1.0
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
||||
|
|
Loading…
Reference in a new issue