Add a GitHost interface

GitLab and GitHost are two implementations of that interface.
This commit is contained in:
Vishesh Handa
2019-01-25 11:21:58 +01:00
parent c7174ab2da
commit ac5c2be05d
5 changed files with 83 additions and 64 deletions

22
lib/apis/githost.dart Normal file
View File

@ -0,0 +1,22 @@
import 'dart:async';
abstract class GitHost {
void init(Function oAuthCallback);
Future launchOAuthScreen();
Future<List<GitRepo>> listRepos();
Future<GitRepo> createRepo(String name);
Future addDeployKey(String sshPublicKey, String repo);
}
class GitRepo {
String fullName;
String cloneUrl;
GitRepo({this.fullName, this.cloneUrl});
@override
String toString() {
return 'GitRepo{fulleName: $fullName, cloneUrl: $cloneUrl}';
}
}

View File

@ -2,18 +2,20 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
class GitHub { import 'githost.dart';
class GitHub implements GitHost {
static const _clientID = "aa3072cbfb02b1db14ed"; static const _clientID = "aa3072cbfb02b1db14ed";
static const _clientSecret = "010d303ea99f82330f2b228977cef9ddbf7af2cd"; static const _clientSecret = "010d303ea99f82330f2b228977cef9ddbf7af2cd";
var _platform = const MethodChannel('gitjournal.io/git'); var _platform = const MethodChannel('gitjournal.io/git');
var _accessCode = ""; var _accessCode = "";
@override
void init(Function callback) { void init(Function callback) {
Future _handleMessages(MethodCall call) async { Future _handleMessages(MethodCall call) async {
if (call.method != "onURL") { if (call.method != "onURL") {
@ -57,6 +59,7 @@ class GitHub {
return map["access_token"]; return map["access_token"];
} }
@override
Future launchOAuthScreen() async { Future launchOAuthScreen() async {
// FIXME: Add some 'state' over here! // FIXME: Add some 'state' over here!
@ -66,7 +69,8 @@ class GitHub {
return launch(url); return launch(url);
} }
Future<List<Repo>> listRepos() async { @override
Future<List<GitRepo>> listRepos() async {
if (_accessCode.isEmpty) { if (_accessCode.isEmpty) {
throw "GitHub Access Code Missing"; throw "GitHub Access Code Missing";
} }
@ -84,10 +88,10 @@ class GitHub {
} }
List<dynamic> list = jsonDecode(response.body); List<dynamic> list = jsonDecode(response.body);
List<Repo> repos = new List<Repo>(); var repos = new List<GitRepo>();
list.forEach((dynamic d) { list.forEach((dynamic d) {
var map = Map<String, dynamic>.from(d); var map = Map<String, dynamic>.from(d);
var repo = Repo.fromJson(map); var repo = _repoFromJson(map);
repos.add(repo); repos.add(repo);
}); });
@ -95,8 +99,9 @@ class GitHub {
return repos; return repos;
} }
// FIXME: Proper error when the repo exists! @override
Future<Repo> createRepo(String name) async { Future<GitRepo> createRepo(String name) async {
// FIXME: Proper error when the repo exists!
if (_accessCode.isEmpty) { if (_accessCode.isEmpty) {
throw "GitHub Access Code Missing"; throw "GitHub Access Code Missing";
} }
@ -123,9 +128,10 @@ class GitHub {
print("GitHub createRepo: " + response.body); print("GitHub createRepo: " + response.body);
var map = json.decode(response.body); var map = json.decode(response.body);
return Repo.fromJson(map); return _repoFromJson(map);
} }
// FIXME: Proper error when the repo exists!
Future addDeployKey(String sshPublicKey, String repo) async { Future addDeployKey(String sshPublicKey, String repo) async {
if (_accessCode.isEmpty) { if (_accessCode.isEmpty) {
throw "GitHub Access Code Missing"; throw "GitHub Access Code Missing";
@ -157,22 +163,11 @@ class GitHub {
print("GitHub addDeployKey: " + response.body); print("GitHub addDeployKey: " + response.body);
return json.decode(response.body); return json.decode(response.body);
} }
}
class Repo { GitRepo _repoFromJson(Map<String, dynamic> parsedJson) {
String fullName; return new GitRepo(
String cloneUrl;
Repo({this.fullName, this.cloneUrl});
factory Repo.fromJson(Map<String, dynamic> parsedJson) {
return new Repo(
fullName: parsedJson['full_name'], fullName: parsedJson['full_name'],
cloneUrl: parsedJson['ssh_url'], cloneUrl: parsedJson['ssh_url'],
); );
} }
@override
String toString() {
return 'Repo{fulleName: $fullName}';
}
} }

View File

@ -1,24 +1,15 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:flutter/services.dart';
import 'package:url_launcher/url_launcher.dart';
import 'dart:math'; import 'dart:math';
String _randomString(int length) { import 'package:flutter/services.dart';
var rand = new Random(); import 'package:http/http.dart' as http;
var codeUnits = new List.generate(length, (index) { import 'package:url_launcher/url_launcher.dart';
return rand.nextInt(33) + 89;
});
return new String.fromCharCodes(codeUnits); import 'githost.dart';
}
class Gitlab { class GitLab implements GitHost {
static const _clientID = static const _clientID =
"faf33c3716faf05bfb701b1b31e36c83a23c3ec2d7161f4ff00fba2275524d09"; "faf33c3716faf05bfb701b1b31e36c83a23c3ec2d7161f4ff00fba2275524d09";
@ -26,6 +17,7 @@ class Gitlab {
var _accessCode = ""; var _accessCode = "";
var _stateOAuth = ""; var _stateOAuth = "";
@override
void init(Function callback) { void init(Function callback) {
Future _handleMessages(MethodCall call) async { Future _handleMessages(MethodCall call) async {
if (call.method != "onURL") { if (call.method != "onURL") {
@ -57,6 +49,7 @@ class Gitlab {
print("GitLab: Installed Handler"); print("GitLab: Installed Handler");
} }
@override
Future launchOAuthScreen() async { Future launchOAuthScreen() async {
_stateOAuth = _randomString(10); _stateOAuth = _randomString(10);
@ -65,7 +58,8 @@ class Gitlab {
return launch(url); return launch(url);
} }
Future<List<GitLabRepo>> listRepos() async { @override
Future<List<GitRepo>> listRepos() async {
if (_accessCode.isEmpty) { if (_accessCode.isEmpty) {
throw "GitHub Access Code Missing"; throw "GitHub Access Code Missing";
} }
@ -84,10 +78,10 @@ class Gitlab {
} }
List<dynamic> list = jsonDecode(response.body); List<dynamic> list = jsonDecode(response.body);
List<GitLabRepo> repos = new List<GitLabRepo>(); var repos = new List<GitRepo>();
list.forEach((dynamic d) { list.forEach((dynamic d) {
var map = Map<String, dynamic>.from(d); var map = Map<String, dynamic>.from(d);
var repo = GitLabRepo.fromJson(map); var repo = _repoFromJson(map);
repos.add(repo); repos.add(repo);
}); });
@ -95,8 +89,9 @@ class Gitlab {
return repos; return repos;
} }
// FIXME: Proper error when the repo exists! @override
Future<GitLabRepo> createRepo(String name) async { Future<GitRepo> createRepo(String name) async {
// FIXME: Proper error when the repo exists!
if (_accessCode.isEmpty) { if (_accessCode.isEmpty) {
throw "GitLab Access Code Missing"; throw "GitLab Access Code Missing";
} }
@ -123,9 +118,10 @@ class Gitlab {
print("GitLab createRepo: " + response.body); print("GitLab createRepo: " + response.body);
var map = json.decode(response.body); var map = json.decode(response.body);
return GitLabRepo.fromJson(map); return _repoFromJson(map);
} }
@override
Future addDeployKey(String sshPublicKey, String repo) async { Future addDeployKey(String sshPublicKey, String repo) async {
if (_accessCode.isEmpty) { if (_accessCode.isEmpty) {
throw "GitLab Access Code Missing"; throw "GitLab Access Code Missing";
@ -158,22 +154,20 @@ class Gitlab {
print("GitLab addDeployKey: " + response.body); print("GitLab addDeployKey: " + response.body);
return json.decode(response.body); return json.decode(response.body);
} }
}
class GitLabRepo { GitRepo _repoFromJson(Map<String, dynamic> parsedJson) {
String fullName; return new GitRepo(
String cloneUrl;
GitLabRepo({this.fullName, this.cloneUrl});
factory GitLabRepo.fromJson(Map<String, dynamic> parsedJson) {
return new GitLabRepo(
fullName: parsedJson['path_with_namespace'], fullName: parsedJson['path_with_namespace'],
cloneUrl: parsedJson['ssh_url_to_repo'], cloneUrl: parsedJson['ssh_url_to_repo'],
); );
} }
}
@override
String toString() { String _randomString(int length) {
return 'GitLabRepo{fulleName: $fullName, cloneUrl: $cloneUrl}'; var rand = new Random();
} var codeUnits = new List.generate(length, (index) {
return rand.nextInt(33) + 89;
});
return new String.fromCharCodes(codeUnits);
} }

View File

@ -1,7 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:journal/apis/github.dart'; import 'apis/githost.dart';
import 'package:journal/apis/gitlab.dart'; import 'apis/github.dart';
import 'apis/gitlab.dart';
class OAuthApp extends StatefulWidget { class OAuthApp extends StatefulWidget {
@override @override
@ -14,11 +15,18 @@ var key =
'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+VAh8r+vn0c+M+DacOo/szXcdMpxO1kIO3USkzgE5XdO83kQdDwh4Xc4P3dcc+FFSfVcEl3mSXGKbYC3G0ZoVcWd4ed40Gt3sLHSfNRQlRv+obnqKbzDLuOGfq65EkaJ90vrWBo/k7K8tBC2j1FZ/PUYy3DxeQkPEZXCMZDSG5P/+XoHn5IPcaxDpvlZjtOrx4H3pQ/YVI+XmyFAsZe+/Shy5sg4ilsdo4BQN2nODuBLwmgYu/hHmCcd8t4OxgBANVN8TMqHnZfRLixRSuXn0DbV4YOa/b2lBFQNvjkoBF6KhXOxZ+awyjyTpNp4AgF5c+3xptkNwUlwiQDCzcUmH your_email@example.com'; 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+VAh8r+vn0c+M+DacOo/szXcdMpxO1kIO3USkzgE5XdO83kQdDwh4Xc4P3dcc+FFSfVcEl3mSXGKbYC3G0ZoVcWd4ed40Gt3sLHSfNRQlRv+obnqKbzDLuOGfq65EkaJ90vrWBo/k7K8tBC2j1FZ/PUYy3DxeQkPEZXCMZDSG5P/+XoHn5IPcaxDpvlZjtOrx4H3pQ/YVI+XmyFAsZe+/Shy5sg4ilsdo4BQN2nODuBLwmgYu/hHmCcd8t4OxgBANVN8TMqHnZfRLixRSuXn0DbV4YOa/b2lBFQNvjkoBF6KhXOxZ+awyjyTpNp4AgF5c+3xptkNwUlwiQDCzcUmH your_email@example.com';
class OAuthAppState extends State<OAuthApp> { class OAuthAppState extends State<OAuthApp> {
var github = new Gitlab(); GitHost githost;
void initState() { void initState() {
super.initState(); super.initState();
github.init(() {
if (true) {
githost = new GitHub();
} else {
githost = new GitLab();
}
githost.init(() {
print("GitHub initialized and has access code"); print("GitHub initialized and has access code");
}); });
} }
@ -35,14 +43,14 @@ class OAuthAppState extends State<OAuthApp> {
RaisedButton( RaisedButton(
child: Text("Open OAuth URL"), child: Text("Open OAuth URL"),
onPressed: () { onPressed: () {
github.launchOAuthScreen(); githost.launchOAuthScreen();
}, },
), ),
RaisedButton( RaisedButton(
child: Text("List Repos"), child: Text("List Repos"),
onPressed: () async { onPressed: () async {
try { try {
var repos = await github.listRepos(); var repos = await githost.listRepos();
for (var repo in repos) { for (var repo in repos) {
print(repo); print(repo);
} }
@ -55,7 +63,7 @@ class OAuthAppState extends State<OAuthApp> {
child: Text("Create Repo"), child: Text("Create Repo"),
onPressed: () async { onPressed: () async {
try { try {
var repo = await github.createRepo("journal_test2"); var repo = await githost.createRepo("journal_test2");
print(repo); print(repo);
} catch (err) { } catch (err) {
print("Create Repo: " + err.toString()); print("Create Repo: " + err.toString());
@ -66,7 +74,7 @@ class OAuthAppState extends State<OAuthApp> {
child: Text("Add Deploy Key"), child: Text("Add Deploy Key"),
onPressed: () async { onPressed: () async {
try { try {
await github.addDeployKey(key, "vhanda/journal_test2"); await githost.addDeployKey(key, "vhanda/journal_test2");
} catch (err) { } catch (err) {
print("Deploy Key: " + err.toString()); print("Deploy Key: " + err.toString());
} }

View File

@ -1,6 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/foundation.dart';
import 'package:journal/note.dart'; import 'package:journal/note.dart';
class NoteRepoResult { class NoteRepoResult {