mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-07-01 12:23:44 +08:00
Add API for GitLab
It's so awesome that I don't need to store the client secret with GitLab. The GitHub APIs are so much easier to use + documentation, but at least GitLab supports more OAuth methods.
This commit is contained in:
179
lib/apis/gitlab.dart
Normal file
179
lib/apis/gitlab.dart
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
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';
|
||||||
|
|
||||||
|
String _randomString(int length) {
|
||||||
|
var rand = new Random();
|
||||||
|
var codeUnits = new List.generate(length, (index) {
|
||||||
|
return rand.nextInt(33) + 89;
|
||||||
|
});
|
||||||
|
|
||||||
|
return new String.fromCharCodes(codeUnits);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Gitlab {
|
||||||
|
static const _clientID =
|
||||||
|
"faf33c3716faf05bfb701b1b31e36c83a23c3ec2d7161f4ff00fba2275524d09";
|
||||||
|
|
||||||
|
var _platform = const MethodChannel('gitjournal.io/git');
|
||||||
|
var _accessCode = "";
|
||||||
|
var _stateOAuth = "";
|
||||||
|
|
||||||
|
void init(Function callback) {
|
||||||
|
Future _handleMessages(MethodCall call) async {
|
||||||
|
if (call.method != "onURL") {
|
||||||
|
print("GitLab Unknown Call: " + call.method);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
print("GitLab: Called onUrl with " + call.arguments.toString());
|
||||||
|
|
||||||
|
var url = call.arguments["URL"];
|
||||||
|
var uri = Uri.parse(url);
|
||||||
|
|
||||||
|
var state = uri.queryParameters['state'];
|
||||||
|
if (state != _stateOAuth) {
|
||||||
|
print("GitLab: OAuth State incorrect");
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
_accessCode = uri.queryParameters['access_token'];
|
||||||
|
if (_accessCode == null) {
|
||||||
|
print("GitLab: Missing access code. Now what?");
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
_platform.setMethodCallHandler(_handleMessages);
|
||||||
|
print("GitLab: Installed Handler");
|
||||||
|
}
|
||||||
|
|
||||||
|
Future launchOAuthScreen() async {
|
||||||
|
_stateOAuth = _randomString(10);
|
||||||
|
|
||||||
|
var url =
|
||||||
|
"https://gitlab.com/oauth/authorize?client_id=$_clientID&response_type=token&state=$_stateOAuth&redirect_uri=gitjournal://login.oauth2";
|
||||||
|
return launch(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<GitLabRepo>> listRepos() async {
|
||||||
|
if (_accessCode.isEmpty) {
|
||||||
|
throw "GitHub Access Code Missing";
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: pagination!
|
||||||
|
var url =
|
||||||
|
"https://gitlab.com/api/v4/projects?simple=true&membership=true&order_by=last_activity_at&access_token=$_accessCode";
|
||||||
|
|
||||||
|
var response = await http.get(url);
|
||||||
|
if (response.statusCode != 200) {
|
||||||
|
print("GitLab listRepos: Invalid response " +
|
||||||
|
response.statusCode.toString() +
|
||||||
|
": " +
|
||||||
|
response.body);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<dynamic> list = jsonDecode(response.body);
|
||||||
|
List<GitLabRepo> repos = new List<GitLabRepo>();
|
||||||
|
list.forEach((dynamic d) {
|
||||||
|
var map = Map<String, dynamic>.from(d);
|
||||||
|
var repo = GitLabRepo.fromJson(map);
|
||||||
|
repos.add(repo);
|
||||||
|
});
|
||||||
|
|
||||||
|
// FIXME: Sort these based on some criteria
|
||||||
|
return repos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Proper error when the repo exists!
|
||||||
|
Future<GitLabRepo> createRepo(String name) async {
|
||||||
|
if (_accessCode.isEmpty) {
|
||||||
|
throw "GitLab Access Code Missing";
|
||||||
|
}
|
||||||
|
|
||||||
|
var url = "https://gitlab.com/api/v4/projects?access_token=$_accessCode";
|
||||||
|
Map<String, dynamic> data = {
|
||||||
|
'name': name,
|
||||||
|
'visibility': 'private',
|
||||||
|
};
|
||||||
|
|
||||||
|
var headers = {
|
||||||
|
HttpHeaders.contentTypeHeader: "application/json",
|
||||||
|
};
|
||||||
|
|
||||||
|
var response =
|
||||||
|
await http.post(url, headers: headers, body: json.encode(data));
|
||||||
|
if (response.statusCode != 201) {
|
||||||
|
print("GitLab createRepo: Invalid response " +
|
||||||
|
response.statusCode.toString() +
|
||||||
|
": " +
|
||||||
|
response.body);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
print("GitLab createRepo: " + response.body);
|
||||||
|
var map = json.decode(response.body);
|
||||||
|
return GitLabRepo.fromJson(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future addDeployKey(String sshPublicKey, String repo) async {
|
||||||
|
if (_accessCode.isEmpty) {
|
||||||
|
throw "GitLab Access Code Missing";
|
||||||
|
}
|
||||||
|
|
||||||
|
repo = repo.replaceAll('/', '%2F');
|
||||||
|
var url =
|
||||||
|
"https://gitlab.com/api/v4/projects/$repo/deploy_keys?access_token=$_accessCode";
|
||||||
|
|
||||||
|
Map<String, dynamic> data = {
|
||||||
|
'title': "GitJournal",
|
||||||
|
'key': sshPublicKey,
|
||||||
|
'can_push': true,
|
||||||
|
};
|
||||||
|
|
||||||
|
var headers = {
|
||||||
|
HttpHeaders.contentTypeHeader: "application/json",
|
||||||
|
};
|
||||||
|
|
||||||
|
var response =
|
||||||
|
await http.post(url, headers: headers, body: json.encode(data));
|
||||||
|
if (response.statusCode != 201) {
|
||||||
|
print("GitLab addDeployKey: Invalid response " +
|
||||||
|
response.statusCode.toString() +
|
||||||
|
": " +
|
||||||
|
response.body);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
print("GitLab addDeployKey: " + response.body);
|
||||||
|
return json.decode(response.body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GitLabRepo {
|
||||||
|
String fullName;
|
||||||
|
String cloneUrl;
|
||||||
|
|
||||||
|
GitLabRepo({this.fullName, this.cloneUrl});
|
||||||
|
factory GitLabRepo.fromJson(Map<String, dynamic> parsedJson) {
|
||||||
|
return new GitLabRepo(
|
||||||
|
fullName: parsedJson['path_with_namespace'],
|
||||||
|
cloneUrl: parsedJson['ssh_url_to_repo'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'GitLabRepo{fulleName: $fullName, cloneUrl: $cloneUrl}';
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:journal/apis/github.dart';
|
import 'package:journal/apis/github.dart';
|
||||||
|
import 'package:journal/apis/gitlab.dart';
|
||||||
|
|
||||||
class OAuthApp extends StatefulWidget {
|
class OAuthApp extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
@ -13,8 +14,7 @@ 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 GitHub();
|
var github = new Gitlab();
|
||||||
String githubAccessCode = "";
|
|
||||||
|
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -41,9 +41,13 @@ class OAuthAppState extends State<OAuthApp> {
|
|||||||
RaisedButton(
|
RaisedButton(
|
||||||
child: Text("List Repos"),
|
child: Text("List Repos"),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
var repos = await github.listRepos();
|
try {
|
||||||
for (var repo in repos) {
|
var repos = await github.listRepos();
|
||||||
print(repo.fullName);
|
for (var repo in repos) {
|
||||||
|
print(repo);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
print("ListRepos: " + err.toString());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -51,7 +55,8 @@ class OAuthAppState extends State<OAuthApp> {
|
|||||||
child: Text("Create Repo"),
|
child: Text("Create Repo"),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
try {
|
try {
|
||||||
await github.createRepo("journal_test2");
|
var repo = await github.createRepo("journal_test2");
|
||||||
|
print(repo);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
print("Create Repo: " + err.toString());
|
print("Create Repo: " + err.toString());
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user