mirrored_repositories/FlutterGithubClient/lib
import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:LoginUI/ui/AppConstants.dart';
import 'package:http/http.dart' as http;
import 'package:url_launcher/url_launcher.dart';

class Github {
  static var USER = "{user}";
  static var REPO = "{repo}";

  static String githubApiBaseUrl = "https://api.github.com";
  static String authorizeURL = "https://github.com/login/oauth/authorize";
  static String accessTokenURL = "https://github.com/login/oauth/access_token";
  static String authorizeBasicUrl = "$githubApiBaseUrl/authorizations";
  static String getUserGithub = "$githubApiBaseUrl/search/users";
  static String getMyUserGithub = "$githubApiBaseUrl/user";
  static String getUserProfileGithub = "$githubApiBaseUrl/users";
  static String getMyReposGithub = "$githubApiBaseUrl/user/repos";
  static String getMyOrgsGithub = "$githubApiBaseUrl/user/orgs";
  static String getUsersReposGithub = "$githubApiBaseUrl/users/:username/repos";
  static String getUserRepoGithub = "$githubApiBaseUrl/repos/$USER/$REPO";
  static String getStarredReposGithub = "$githubApiBaseUrl/users/$USER/starred";
  static String getUserNotificationsGithub = "$githubApiBaseUrl/notifications";
  static String getGistsGithub = "$githubApiBaseUrl/users/$USER/gists";

  static String clientId =
      "client_id"; //Required. The client ID you received from GitHub when you registered.
  static String clientSecret =
      "client_secret"; //Required. The client secret you received from GitHub for your GitHub App.
  static String redirectUri =
      "redirect_uri"; //The URL in your application where users will be sent after authorization. See details below about redirect urls.
  static String scope =
      "scope"; //A space-delimited list of scopes. If not provided, scope defaults to an empty list for users that have not authorized any scopes for the application. For users who have authorized scopes for the application, the user won't be shown the OAuth authorization page with the list of scopes. Instead, this step of the flow will automatically complete with the set of scopes the user has authorized for the application. For example, if a user has already performed the web flow twice and has authorized one token with user scope and another token with repo scope, a third web flow that does not provide a scope will receive a token with user and repo scope.
  static String state =
      "state"; //An unguessable random string. It is used to protect against cross-site request forgery attacks.
  static String allowSignup =
      "allow_signup"; //Whether or not unauthenticated users will be offered an option to sign up for GitHub during the OAuth flow. The default is true. Use false in the case that a policy prohibits signups.

  static String affiliationParamRepoSearch =
      "&visibility=all&affiliation=owner,collaborator,organization_member";

  static Future<http.Response> authorize(Map<String, String> requestData) {
    return http.get(authorizeURL, headers: requestData);
  }

  static Map<String, String> getGithubHeaders() {
    Map<String, String> headers = new Map();
    headers.putIfAbsent(Github.clientId, () {
      return AppConstants.GITHUB_CLIENT_ID;
    });
    headers.putIfAbsent(Github.redirectUri, () {
      return AppConstants.GITHUB_CALLBACK_URL;
    });
    headers.putIfAbsent(Github.scope, () {
      return "repo,user";
    });
    headers.putIfAbsent(Github.state, () {
      return AppConstants.GITHUB_CLIENT_ID;
    });
    headers.putIfAbsent(Github.allowSignup, () {
      return "true";
    });
    return headers;
  } //https://github.com/login/oauth/authorize?client_id=5eebe59bc6ed95a4f4b1&redirect_uri	=http://localhost:8080/&scope=repo,user&state=5eebe59bc6ed95a4f4b1&allow_signup=true&

  static Future<Stream<String>> _server() async {
    final StreamController<String> onCode = new StreamController();
    HttpServer server =
        await HttpServer.bind(InternetAddress.loopbackIPv4, 8080, shared: true);
    server.listen((HttpRequest request) async {
      final String code = request.uri.queryParameters["code"];
      request.response
        ..statusCode = 200
        ..headers.set("Content-Type", ContentType.html.mimeType)
        ..write("<html><h1>You can now close this window</h1></html>");
      await request.response.close();
      await server.close(force: true);
      onCode.add(code);
      await onCode.close();
    });
    return onCode.stream;
  }

  static String githubAuthUrl() {
    StringBuffer buffer = new StringBuffer();
    buffer.write(Github.authorizeURL);
    buffer.write("?");
    getGithubHeaders().forEach((key, value) {
      buffer.write(key);
      buffer.write("=");
      buffer.write(value);
      buffer.write("&");
    });
    return buffer.toString();
  }

  static Future<String> authenticate(Null Function(String) param0) async {
    Stream<String> onToken = await _server();

    String url = Github.githubAuthUrl().replaceAll(" ", "");
    print(url);
    if (await canLaunch(url)) {
      await launch(url);
    } else {
      param0("");
      throw 'Could not launch $url';
    }

    final String token = await onToken.first;
    print("Received token " + token);

    Github.postAccessToken(token).then((response) {
      print("Response status: ${response}");
      param0(response);
    }).catchError((error) {
      param0("Error body: $error");
    }).whenComplete(() {});

    return token;
  }

  static Future<String> postAccessToken(String code) async {
    HttpClient httpClient = new HttpClient();
    Map map = {
      clientId: AppConstants.GITHUB_CLIENT_ID,
      clientSecret: AppConstants.GITHUB_CLIENT_SECRET,
      'code': code,
    };

    HttpClientRequest request =
        await httpClient.postUrl(Uri.parse(accessTokenURL));
    request.headers.set('content-type', 'application/json');
    request.write(json.encode(map));
    print(request.headers);
    print(request.encoding.name);
    print(request.uri.toString());
    print(json.encode(map));
    HttpClientResponse response = await request.close();
    print(response.statusCode);
    String reply = await response.transform(utf8.decoder).join();
    print(reply);
    reply = reply.split("=")[1].split("&")[0];
    httpClient.close();
    return reply;
  }

  static Future<http.Response> getUsersBySearch(String accessToken, String value, int page) {
    String fullUrl = getUserGithub + "?access_token=" + accessToken + "&q=" + value+"&page=$page&per_page=10"+"&" + getClientIdSecret();
    print(fullUrl);
    return http.get(fullUrl);
  }

  static Future<http.Response> getMyUserProfile(String accessToken){
    String fullUrl = getMyUserGithub + "?access_token=" + accessToken+ "&" +getClientIdSecret();
    print(fullUrl);
    return http.get(fullUrl);
  }

  static Future<http.Response> getUserProfile(String username) {
    String fullUrl =
        getUserProfileGithub + "/$username" + "?" + "&" + getClientIdSecret();
    print(fullUrl);
    return http.get(fullUrl);
  }

  static Future<http.Response> getNotificationDetail(String url,
      String accessToken) {
    String fullUrl = url + "?access_token=" + accessToken;
    print(fullUrl);
    return http.get(fullUrl);
  }

  static Future<http.Response> getAllMyRepos(String accessToken,int max,int page) {
    String fullUrl =
        getMyReposGithub + "?access_token=" + accessToken+"&page=$page&per_page=$max" +"&" + getClientIdSecret() + affiliationParamRepoSearch;
    print(fullUrl);
    return http.get(fullUrl);
  }

  static Future<http.Response> getUserNotifications(String accessToken) {
    String fullUrl = getUserNotificationsGithub + "?access_token=" +
        accessToken;
    print(fullUrl);
    return http.get(fullUrl);
  }

  static Future<http.Response> getUserRepos(int page,int max,String accessToken,String userName) {
    String fullUrl =
        getUsersReposGithub.replaceAll(":username", userName) + "?accessToken=" + accessToken+"&page=$page&per_page=$max" +"&" + getClientIdSecret() + affiliationParamRepoSearch+"&"+"type=all";
    print(fullUrl);
    return http.get(fullUrl);
  }


  static Future<http.Response> getFromUrl(String reposUrl, String accessToken) {
    String fullUrl = reposUrl + "?access_token=" + accessToken + affiliationParamRepoSearch;
    print(fullUrl);
    return http.get(fullUrl);
  }

  static Future<http.Response> getMyOrganizations(String accessToken) {
    String fullUrl = getMyOrgsGithub + "?access_token=" + accessToken + affiliationParamRepoSearch;
    print(fullUrl);
    return http.get(fullUrl);
  }

  static Future<http.Response> getApiForUrl(String contributorsUrl, String accessToken) {
    var fullUrl = contributorsUrl + "?access_token=" + accessToken +"&"+ getClientIdSecret();
    return http.get(fullUrl);
  }

  //flutter: https://api.github.com/users/Anmol92verma/starred
  static Future<http.Response> getUserStarredRepos(
      String username, int max, int page) {
    String fullUrl = getStarredReposGithub.replaceAll(USER, username) +
        "?page=$page&per_page=$max" +
        "&" +
        getClientIdSecret();
    print(fullUrl);
    return http.get(fullUrl);
  }

  static Future<http.Response> getGistsForUser(
      String username, int max, int page) {
    String fullUrl = getGistsGithub.replaceAll(USER, username) +
        "?page=$page&per_page=$max" +
        "&" +
        getClientIdSecret();
    print(fullUrl);
    return http.get(fullUrl);
  }

  static Future<http.Response> authenticateUsernamePassword(
      String username, String password) async {
    var value = base64Encode(utf8.encode('$username:$password'));
    var authrorization = 'Basic $value';
    print(authrorization);
    print(authorizeBasicUrl);
    var list = List<String>();
    list.add("user");
    list.add("repo");
    list.add("gist");
    list.add("notifications");
    list.add("read:org");

    Map map = {
      clientId: AppConstants.GITHUB_CLIENT_ID,
      "scopes": list,
      clientSecret: AppConstants.GITHUB_CLIENT_SECRET,
    };
    print(map);
    return http.post(authorizeBasicUrl,
        headers: {'Authorization': authrorization}, body: json.encode(map));
  }

  static String getClientIdSecret() {
    return "${Github.clientId}=${AppConstants.GITHUB_CLIENT_ID}&${Github.clientSecret}=${AppConstants.GITHUB_CLIENT_SECRET}";
  }
}
