├── settings.gradle
├── gogs-client
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ └── values
│ │ │ │ └── strings.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── org
│ │ │ └── unfoldingword
│ │ │ └── gogsclient
│ │ │ ├── Response.java
│ │ │ ├── Util.java
│ │ │ ├── Token.java
│ │ │ ├── PublicKey.java
│ │ │ ├── Repository.java
│ │ │ ├── User.java
│ │ │ └── GogsAPI.java
│ └── androidTest
│ │ ├── java
│ │ └── org
│ │ │ └── unfoldingword
│ │ │ └── gogsclient
│ │ │ ├── TestUtil.java
│ │ │ └── ApplicationTest.java
│ │ └── assets
│ │ └── sample.config.json
├── proguard-rules.pro
└── build.gradle
├── config.json.enc
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── DEPLOYING
├── .gitignore
├── gradle.properties
├── android-gogs-client.iml
├── LICENSE
├── .travis.yml
├── README.md
├── gradlew.bat
└── gradlew
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':gogs-client'
2 |
--------------------------------------------------------------------------------
/gogs-client/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /src/androidTest/assets/config.json
--------------------------------------------------------------------------------
/config.json.enc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unfoldingWord-dev/android-gogs-client/HEAD/config.json.enc
--------------------------------------------------------------------------------
/gogs-client/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Gogs Client
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unfoldingWord-dev/android-gogs-client/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Apr 12 15:00:15 PDT 2016
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
7 |
--------------------------------------------------------------------------------
/DEPLOYING:
--------------------------------------------------------------------------------
1 | These notes are just to help me remember how to publish the package.
2 |
3 | A great tutorial on how to get set up can be found at http://inthecheesefactory.com/blog/how-to-upload-library-to-jcenter-maven-central-as-dependency/en.
4 |
5 | 1. Make sure your local.properties has been properly set up to include your bintray info
6 | 2. build the app using `gradlew install`
7 | 3. upload using `gradlew bintrayUpload`
--------------------------------------------------------------------------------
/gogs-client/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/gogs-client/src/main/java/org/unfoldingword/gogsclient/Response.java:
--------------------------------------------------------------------------------
1 | package org.unfoldingword.gogsclient;
2 |
3 | /**
4 | * Holds the response from the api
5 | */
6 | public class Response {
7 | public final int code;
8 | public final String data;
9 | public final Exception exception;
10 |
11 | public Response(int responseCode, String responseData, Exception exception) {
12 | this.code = responseCode;
13 | this.data = responseData;
14 | this.exception = exception;
15 | }
16 |
17 | @Override
18 | public String toString() {
19 | return this.data;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 |
15 | ### JetBrains ###
16 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
17 |
18 | /*.iml
19 | *.iml
20 |
21 | # Gradle files
22 | .gradle/
23 | build/
24 |
25 | # Local configuration file (sdk path, etc)
26 | local.properties
27 |
28 | # Proguard folder generated by Eclipse
29 | proguard/
30 |
31 | # Log Files
32 | *.log
33 |
34 | # Android Studio Navigation editor temp files
35 | .navigation/
36 |
37 | # Android Studio captures folder
38 | captures/
39 |
40 | .idea/
--------------------------------------------------------------------------------
/gogs-client/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\Users\joel\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/gogs-client/src/androidTest/java/org/unfoldingword/gogsclient/TestUtil.java:
--------------------------------------------------------------------------------
1 | package org.unfoldingword.gogsclient;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.io.InputStreamReader;
7 |
8 | /**
9 | * Created by joel on 3/29/2016.
10 | */
11 | public class TestUtil {
12 |
13 | /**
14 | * Converts an input stream into a string
15 | * @param is
16 | * @return
17 | * @throws Exception
18 | */
19 | public static String readStreamToString(InputStream is) throws IOException {
20 | BufferedReader reader = new BufferedReader(new InputStreamReader(is));
21 | StringBuilder sb = new StringBuilder();
22 | String line;
23 | while ((line = reader.readLine()) != null) {
24 | sb.append(line).append("\n");
25 | }
26 | return sb.toString();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | org.gradle.daemon=true
--------------------------------------------------------------------------------
/android-gogs-client.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2016 unfoldingword.org
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation
6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
7 | permit persons to whom the Software is furnished to do so, subject to the following conditions:
8 |
9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
10 | Software.
11 |
12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
13 | THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
14 | OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
15 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: android
2 | jdk: oraclejdk8
3 | cache:
4 | directories:
5 | - "$HOME/.gradle/caches"
6 | - "$HOME/.gradle/daemon"
7 | - "$HOME/.gradle/native"
8 | - "$HOME/.gradle/wrapper"
9 | before_cache:
10 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
11 | sudo: false
12 | env:
13 | global:
14 | - GRADLE_OPTS="-Xms128m"
15 | matrix:
16 | - ANDROID_TARGET=android-21 ANDROID_ABI=armeabi-v7a
17 | android:
18 | components:
19 | - platform-tools
20 | - tools
21 | - build-tools-22.0.1
22 | - android-22
23 | - sys-img-armeabi-v7a-android-19
24 | before_script:
25 | - chmod +x gradlew
26 | - echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI
27 | - emulator -avd test -no-skin -no-audio -no-window &
28 | - android-wait-for-emulator
29 | - adb devices
30 | - adb shell input keyevent 82 &
31 | script:
32 | - travis_wait ./gradlew connectedAndroidTest --continue --stacktrace
33 | before_install:
34 | - if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then openssl aes-256-cbc -K $encrypted_31315891990e_key
35 | -iv $encrypted_31315891990e_iv -in config.json.enc -out gogs-client/src/androidTest/assets/config.json
36 | -d; fi
--------------------------------------------------------------------------------
/gogs-client/src/androidTest/assets/sample.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "api": "https://try.gogs.io/api/v1",
3 | "demoUser": {
4 | "username": "demo-user-3635445323443554",
5 | "password": "demo-password",
6 | "email": "demo@example.com"
7 | },
8 | "adminUser": {
9 | "username": "a real admin user name",
10 | "password": "a real admin password"
11 | },
12 | "demoRepo": {
13 | "name": "demo-repo-36454532314334534",
14 | "description": "This is a test repository. Yay!",
15 | "private": false
16 | },
17 | "fakeRepo": {
18 | "name": "fake-repo-968433541635163r1",
19 | "description": "This is never created",
20 | "private": false
21 | },
22 | "fakeUser": {
23 | "username": "fake-user-3542343543143553446",
24 | "password": "fake-password"
25 | },
26 | "demoToken": {
27 | "name": "demo-token-6353445353443"
28 | },
29 | "demoKey": {
30 | "title": "demo-public-key-644531234t55414584",
31 | "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDUbmwBOG5vI8qNCztby5LDc9ozwTuwsqf+1fpuHjT9iQ2Lu9nlKHQJcPSgdrYAcc+88K6o74ayhTAjfajKxkIHnbzZFjidoVZSQDhX5qvl93jvY/Uz390qky0sweW+fspm8pRJL+ofE3QEN5AXAuycq1tgsRT32XC+Ta82Xyv8b3xW+pWbsZzYCzUsZXDe/xWxg1rndXh2BIrmcYf9BMiv9ZJIojJXfuLCeRXl550tDzaMFC0rQ/T5pZjs/lQemtg92MnxnEDi5nhuvDwM4Q8eqCTOXc4BCE7iyIHv+B7rx+0x99ytMh5BSIIGyWTfgTot/AjGVm5aRKJSRFgPBm9N comment with whitespace"
32 | }
33 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/unfoldingWord-dev/android-gogs-client)
2 | # android-gogs-client
3 | A client library for interacting with the [Gogs](https://gogs.io) REST api. This library is written to communicate according to the api defined in [gogits/go-gogs-client](https://github.com/gogits/go-gogs-client/wiki).
4 |
5 | ##Supported Operations
6 | * create user
7 | * edit user
8 | * search users
9 | * get user
10 | * delete user
11 | * search repositories
12 | * list user repositories
13 | * create repository
14 | * get repository
15 | * delete repository
16 | * create application token
17 | * list application tokens
18 | * create public key
19 | * get public key
20 | * list public keys
21 | * delete public key
22 |
23 | ##Installation
24 | To use this library your Android project must be configured to use the JCenter or Maven Central repositories.
25 |
26 | Add the following to your package dependencies and sync gradle.
27 | ```
28 | compile 'org.unfoldingword.tools:gogs-client:1.6.0'
29 | ```
30 |
31 | ##Usage
32 | ```
33 | GogsAPI api = new GogsAPI("https://try.gogs.io/api/v1"); // change to any gogs server
34 | List users = api.searchUsers("some-user-name", 5, null);
35 | // do something
36 | ...
37 |
38 | // inspect actual response for more details if needed
39 | Response response = api.getLastResponse();
40 | ```
41 |
--------------------------------------------------------------------------------
/gogs-client/src/main/java/org/unfoldingword/gogsclient/Util.java:
--------------------------------------------------------------------------------
1 | package org.unfoldingword.gogsclient;
2 |
3 | import org.json.JSONException;
4 | import org.json.JSONObject;
5 |
6 | /**
7 | * Created by joel on 3/29/2016.
8 | */
9 | public class Util {
10 |
11 | /**
12 | * Adds a value to the json object if the value is not null
13 | * @param json
14 | * @param field
15 | * @param value
16 | * @return
17 | */
18 | public static JSONObject addToJSON(JSONObject json, String field, Object value) {
19 | if(value != null) {
20 | try {
21 | json.put(field, value);
22 | } catch (JSONException e) {
23 | e.printStackTrace();
24 | }
25 | }
26 | return json;
27 | }
28 |
29 | /**
30 | * Retrieves a value from a json object or returns the default if it does not exist
31 | * @param json the json object to inspect
32 | * @param field the field to return
33 | * @param defaultValue the default value to return if the field does not exist
34 | * @return
35 | */
36 | public static Object getFromJSON(JSONObject json, String field, Object defaultValue) {
37 | if(json.has(field)) {
38 | try {
39 | return json.get(field);
40 | } catch (JSONException e) {
41 | e.printStackTrace();
42 | return defaultValue;
43 | }
44 | } else {
45 | return defaultValue;
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/gogs-client/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | ext {
4 | bintrayRepo = 'maven'
5 | bintrayName = 'gogs-client'
6 |
7 | publishedGroupId = 'org.unfoldingword.tools'
8 | libraryName = 'Gogs Client'
9 | artifact = 'gogs-client'
10 |
11 | libraryDescription = 'An android library for interacting with the Gogs REST api.'
12 |
13 | siteUrl = 'https://github.com/unfoldingWord-dev/android-gogs-client'
14 | gitUrl = 'https://github.com/unfoldingWord-dev/android-gogs-client.git'
15 |
16 | libraryVersion = '1.6.1'
17 |
18 | developerId = 'neutrinog'
19 | developerName = 'Joel'
20 | developerEmail = 'joel@neutrinographics.com'
21 |
22 | licenseName = 'GNU GENERAL PUBLIC LICENSE, Version 2.0'
23 | licenseUrl = 'http://www.gnu.org/licenses/gpl-2.0.en.html'
24 | allLicenses = ["GPL-2.0"]
25 | }
26 |
27 | android {
28 | compileSdkVersion 22
29 | buildToolsVersion "22.0.1"
30 |
31 | defaultConfig {
32 | minSdkVersion 15
33 | targetSdkVersion 22
34 | versionCode 7
35 | versionName "1.6.1"
36 | }
37 | buildTypes {
38 | release {
39 | minifyEnabled false
40 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
41 | }
42 | }
43 | }
44 |
45 | dependencies {
46 | compile fileTree(dir: 'libs', include: ['*.jar'])
47 | testCompile 'junit:junit:4.12'
48 | }
49 |
50 | if (System.env.TRAVIS != 'true') {
51 | apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle'
52 | apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/bintrayv1.gradle'
53 | }
54 |
--------------------------------------------------------------------------------
/gogs-client/src/main/java/org/unfoldingword/gogsclient/Token.java:
--------------------------------------------------------------------------------
1 | package org.unfoldingword.gogsclient;
2 |
3 | import org.json.JSONException;
4 | import org.json.JSONObject;
5 |
6 | /**
7 | * Represents an application authentication token
8 | */
9 | public class Token {
10 | private String name = null;
11 | private String sha1 = null;
12 |
13 | private Token() {}
14 |
15 | public Token(String name) {
16 | this.name = name;
17 | }
18 |
19 | public Token(String name, String sha1) {
20 | this.name = name;
21 | this.sha1 = sha1;
22 | }
23 |
24 | /**
25 | * Returns a token parsed from json
26 | * @param json
27 | * @return
28 | */
29 | public static Token fromJSON(JSONObject json) {
30 | if(json != null) {
31 | Token token = new Token();
32 | token.name = (String)Util.getFromJSON(json, "name", null);
33 | token.sha1 = (String)Util.getFromJSON(json, "sha1", null);
34 | return token;
35 | }
36 | return null;
37 | }
38 |
39 | /**
40 | * Returns the json form of the token
41 | * @return
42 | * @throws JSONException
43 | */
44 | public JSONObject toJSON() throws JSONException {
45 | JSONObject json = new JSONObject();
46 | json.put("name", this.name);
47 | json.put("sha1", this.sha1);
48 | return json;
49 | }
50 |
51 | @Override
52 | public String toString() {
53 | return this.sha1;
54 | }
55 |
56 | /**
57 | * Returns the name of the token
58 | * @return
59 | */
60 | public String getName() {
61 | return name;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/gogs-client/src/main/java/org/unfoldingword/gogsclient/PublicKey.java:
--------------------------------------------------------------------------------
1 | package org.unfoldingword.gogsclient;
2 |
3 | import org.json.JSONException;
4 | import org.json.JSONObject;
5 |
6 | /**
7 | * Created by joel on 2/25/2016.
8 | */
9 | public class PublicKey {
10 |
11 | private final String title;
12 | private final String key;
13 | private int id;
14 | private String url;
15 | private String createdAt;
16 |
17 | /**
18 | * Create a key that holds just the id. This allows us to look up the full key description from the api
19 | * @param id
20 | */
21 | public PublicKey(int id) {
22 | this.id = id;
23 | this.title = "";
24 | this.key = "";
25 | }
26 |
27 | public PublicKey(String title, String key) {
28 | this.title = title;
29 | this.key = key;
30 | }
31 |
32 | /**
33 | * Returns a public key parsed from json
34 | * @param json
35 | * @return
36 | */
37 | public static PublicKey fromJSON(JSONObject json) {
38 | if(json != null) {
39 | try {
40 | PublicKey key = new PublicKey(json.getString("title"), json.getString("key"));
41 | key.id = (int)Util.getFromJSON(json, "id", 0);
42 | key.url = (String)Util.getFromJSON(json, "url", null);
43 | key.createdAt = (String)Util.getFromJSON(json, "created_at", null);
44 | return key;
45 | } catch (JSONException e) {
46 | e.printStackTrace();
47 | }
48 | }
49 | return null;
50 | }
51 |
52 | public String getCreatedAt() {
53 | return createdAt;
54 | }
55 |
56 | public String getUrl() {
57 | return url;
58 | }
59 |
60 | public int getId() {
61 | return id;
62 | }
63 |
64 | public String getKey() {
65 | return key;
66 | }
67 |
68 | public String getTitle() {
69 | return title;
70 | }
71 |
72 | @Override
73 | public String toString() {
74 | return this.key;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/gogs-client/src/main/java/org/unfoldingword/gogsclient/Repository.java:
--------------------------------------------------------------------------------
1 | package org.unfoldingword.gogsclient;
2 |
3 | import org.json.JSONException;
4 | import org.json.JSONObject;
5 |
6 | /**
7 | * Represents a gogs repository
8 | */
9 | public class Repository {
10 |
11 | private String name = "";
12 | private String description = "";
13 | private boolean isPrivate;
14 | private int id = 0;
15 | private String fullName = "";
16 | private boolean isFork;
17 | private String htmlUrl = "";
18 | private String cloneUrl = "";
19 | private String sshUrl = "";
20 | private User owner;
21 |
22 | private Repository() {}
23 |
24 | public Repository(String name, String description, boolean isPrivate) {
25 | this.name = name;
26 | this.description = description;
27 | this.isPrivate = isPrivate;
28 | }
29 |
30 | /**
31 | * Returns a repository parsed from json
32 | * @param json
33 | * @return
34 | */
35 | public static Repository fromJSON(JSONObject json) {
36 | if(json != null) {
37 | Repository repo = new Repository();
38 | repo.id = (int)Util.getFromJSON(json, "id", 0);
39 | repo.name = (String)Util.getFromJSON(json, "name", null);
40 | repo.description = (String)Util.getFromJSON(json, "description", null);
41 | repo.fullName = (String)Util.getFromJSON(json, "full_name", null);
42 | repo.isPrivate = (boolean)Util.getFromJSON(json, "private", true);
43 | repo.isFork = (boolean)Util.getFromJSON(json, "fork", false);
44 | repo.htmlUrl = (String)Util.getFromJSON(json, "html_url", null);
45 | repo.cloneUrl = (String)Util.getFromJSON(json, "clone_url", null);
46 | repo.sshUrl = (String)Util.getFromJSON(json, "ssh_url", null);
47 | if(json.has("owner")) {
48 | try {
49 | repo.owner = User.fromJSON(json.getJSONObject("owner"));
50 | } catch (JSONException e) {
51 | e.printStackTrace();
52 | }
53 | }
54 | // TODO: 2/24/2016 get permissions
55 | return repo;
56 | }
57 | return null;
58 | }
59 |
60 | /**
61 | * Returns the json form of the repository
62 | * @return
63 | */
64 | public JSONObject toJSON() {
65 | JSONObject json = new JSONObject();
66 | json = Util.addToJSON(json, "id", this.id);
67 | json = Util.addToJSON(json, "name", this.name);
68 | json = Util.addToJSON(json, "description", this.description);
69 | json = Util.addToJSON(json, "full_name", this.fullName);
70 | json = Util.addToJSON(json, "private", this.isPrivate);
71 | json = Util.addToJSON(json, "fork", this.isFork);
72 | json = Util.addToJSON(json, "html_url", this.htmlUrl);
73 | json = Util.addToJSON(json, "clone_url", this.cloneUrl);
74 | json = Util.addToJSON(json, "ssh_url", this.sshUrl);
75 | if(this.owner != null) {
76 | try {
77 | json.put("owner", this.owner.toJSON());
78 | } catch (JSONException e) {
79 | e.printStackTrace();
80 | }
81 | }
82 |
83 | return json;
84 | }
85 |
86 | public String getName() {
87 | return name;
88 | }
89 |
90 | public String getDescription() {
91 | return description;
92 | }
93 |
94 | public boolean getIsPrivate() {
95 | return isPrivate;
96 | }
97 |
98 | public String getFullName() {
99 | return fullName;
100 | }
101 |
102 | public int getId() {
103 | return id;
104 | }
105 |
106 | public boolean isFork() {
107 | return isFork;
108 | }
109 |
110 | public String getHtmlUrl() {
111 | return htmlUrl;
112 | }
113 |
114 | public String getCloneUrl() {
115 | return cloneUrl;
116 | }
117 |
118 | public String getSshUrl() {
119 | return sshUrl;
120 | }
121 |
122 | public User getOwner() {
123 | return owner;
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/gogs-client/src/main/java/org/unfoldingword/gogsclient/User.java:
--------------------------------------------------------------------------------
1 | package org.unfoldingword.gogsclient;
2 |
3 | import org.json.JSONException;
4 | import org.json.JSONObject;
5 |
6 | /**
7 | * A gogs user
8 | */
9 | public class User {
10 |
11 | private String username = "";
12 | public String password = "";
13 | public String email = "";
14 | public String fullName = "";
15 | private String avatarUrl = "";
16 | public Token token = null;
17 | private String loginName = null;
18 | private String website = null;
19 | private String location = null;
20 | private boolean active = false;
21 | private boolean admin = false;
22 | private boolean allowImportLocal = false;
23 | private boolean allowGitHook = false;
24 | private int id = 0;
25 |
26 | private User() {}
27 |
28 | public User(String username, String password) {
29 | this.username = username;
30 | this.password = password;
31 | }
32 |
33 | /**
34 | * Returns a user parsed from json
35 | * @param json
36 | * @return
37 | */
38 | public static User fromJSON(JSONObject json) {
39 | if(json != null) {
40 | User user = new User();
41 | user.id = (int)Util.getFromJSON(json, "id", 0);
42 | user.username = (String)Util.getFromJSON(json, "username", null);
43 | user.password = (String)Util.getFromJSON(json, "password", null);
44 | String token = (String)Util.getFromJSON(json, "token", null);
45 | if(token != null && !token.isEmpty()) {
46 | user.token = new Token("token", token);
47 | }
48 | user.email = (String)Util.getFromJSON(json, "email", null);
49 | user.avatarUrl = (String)Util.getFromJSON(json, "avatar_url", null);
50 | user.fullName = (String)Util.getFromJSON(json, "full_name", null);
51 | user.loginName = (String)Util.getFromJSON(json, "login_name", null);
52 | user.website = (String)Util.getFromJSON(json, "website", null);
53 | user.location = (String)Util.getFromJSON(json, "location", null);
54 | user.active = (boolean)Util.getFromJSON(json, "active", true);
55 | user.admin = (boolean)Util.getFromJSON(json, "admin", false);
56 | user.allowGitHook = (boolean)Util.getFromJSON(json, "allow_git_hook", true);
57 | user.allowImportLocal = (boolean)Util.getFromJSON(json, "allow_import_local", true);
58 | return user;
59 | }
60 | return null;
61 | }
62 |
63 | /**
64 | * Returns the token.
65 | * @deprecated please used the public property `token` instead
66 | * @return
67 | */
68 | @Deprecated
69 | public Token getToken() {
70 | return token;
71 | }
72 |
73 | public String getUsername() {
74 | return username;
75 | }
76 |
77 | public String getPassword() {
78 | return password;
79 | }
80 |
81 | /**
82 | * Converts the user to a json object
83 | * @return
84 | */
85 | public JSONObject toJSON() throws JSONException {
86 | JSONObject json = new JSONObject();
87 | if(this.id > 0) {
88 | json = Util.addToJSON(json, "id", this.id);
89 | }
90 | json = Util.addToJSON(json, "full_name", this.fullName);
91 | json = Util.addToJSON(json, "email", this.email);
92 | json = Util.addToJSON(json, "username", this.username);
93 | json = Util.addToJSON(json, "password", this.password);
94 | json = Util.addToJSON(json, "login_name", this.loginName);
95 | json = Util.addToJSON(json, "website", this.website);
96 | json = Util.addToJSON(json, "location", this.location);
97 | json = Util.addToJSON(json, "avatar_url", this.avatarUrl);
98 | json = Util.addToJSON(json, "active", this.active);
99 | json = Util.addToJSON(json, "admin", this.admin);
100 | json = Util.addToJSON(json, "allow_git_hook", this.allowGitHook);
101 | json = Util.addToJSON(json, "allow_import_local", this.allowImportLocal);
102 | return json;
103 | }
104 |
105 | /**
106 | * Returns the id of the gogs user
107 | * @return
108 | */
109 | public int getId() {
110 | return id;
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gogs-client/src/androidTest/java/org/unfoldingword/gogsclient/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package org.unfoldingword.gogsclient;
2 |
3 | import android.test.InstrumentationTestCase;
4 |
5 | import org.json.JSONObject;
6 |
7 | import java.io.InputStream;
8 | import java.util.List;
9 |
10 | /**
11 | * Testing Fundamentals
12 | */
13 | public class ApplicationTest extends InstrumentationTestCase {
14 |
15 | private User adminUser;
16 | private User demoUser;
17 | private User fakeUser;
18 | private Token demoToken;
19 | private Repository demoRepo;
20 | private GogsAPI api;
21 | private PublicKey demoKey;
22 |
23 | @Override
24 | protected void setUp() throws Exception {
25 | super.setUp();
26 | // load config
27 | InputStream is = getInstrumentation().getContext().getAssets().open("config.json");
28 | String configString = TestUtil.readStreamToString(is);
29 | JSONObject config = new JSONObject(configString);
30 |
31 | // set up data
32 | this.demoUser = User.fromJSON(config.getJSONObject("demoUser"));
33 | this.fakeUser = User.fromJSON(config.getJSONObject("fakeUser"));
34 | this.demoToken = Token.fromJSON(config.getJSONObject("demoToken"));
35 | this.adminUser = User.fromJSON(config.getJSONObject("adminUser"));
36 | this.demoRepo = Repository.fromJSON(config.getJSONObject("demoRepo"));
37 | this.demoKey = PublicKey.fromJSON(config.getJSONObject("demoKey"));
38 | this.api = new GogsAPI(config.getString("api"));
39 | }
40 |
41 | public void test01CreateUser() throws Exception {
42 | User createdUser = api.createUser(demoUser, adminUser, false);
43 | assertNotNull(createdUser);
44 | assertEquals(createdUser.getUsername(), demoUser.getUsername());
45 |
46 | User anotherNewUser = new User("demo-user-that-is-not-created", "bla bla bla");
47 | User badUser = api.createUser(anotherNewUser, null, false);
48 | assertNull(badUser);
49 | }
50 |
51 | public void test02UpdateUser() throws Exception {
52 | demoUser.fullName = "My test full name";
53 | User updatedUser = api.editUser(demoUser, adminUser);
54 | assertNotNull(updatedUser);
55 | assertEquals(updatedUser.fullName, demoUser.fullName);
56 | }
57 |
58 | public void test03SearchUsers() throws Exception {
59 | List users = api.searchUsers(demoUser.getUsername(), 5, null);
60 | assertTrue(users.size() > 0);
61 | assertTrue(users.get(0).email.isEmpty());
62 |
63 | List completeUsers = api.searchUsers("d", 5, adminUser);
64 | assertTrue(completeUsers.size() > 0);
65 | assertTrue(!completeUsers.get(0).email.isEmpty());
66 | }
67 |
68 | public void test04GetUser() throws Exception {
69 | User completeUser = api.getUser(demoUser, adminUser);
70 | assertNotNull(completeUser);
71 | assertTrue(!completeUser.email.isEmpty());
72 |
73 | User foundUser = api.getUser(demoUser, null);
74 | assertNotNull(foundUser);
75 | assertTrue(foundUser.email.isEmpty());
76 |
77 | User unknownUser = api.getUser(fakeUser, adminUser);
78 | assertNull(unknownUser);
79 | }
80 |
81 | public void test05SearchRepos() throws Exception {
82 | int limit = 2;
83 | List repos = api.searchRepos("demo", 0, limit);
84 | assertTrue(repos.size() > 0);
85 | assertTrue(repos.size() <= limit);
86 | }
87 |
88 | public void test06CreateRepo() throws Exception {
89 | Repository repo = api.createRepo(demoRepo, demoUser);
90 | assertNotNull(repo);
91 | assertEquals(repo.getFullName(), demoUser.getUsername() + "/" + demoRepo.getName());
92 |
93 | Repository badRepoSpec = new Repository("repo-never-created", "This is never created", false);
94 | Repository badRepo = api.createRepo(badRepoSpec, fakeUser);
95 | assertNull(badRepo);
96 | }
97 |
98 | public void test07ListRepos() throws Exception {
99 | List repos = api.listRepos(demoUser);
100 | assertTrue(repos.size() > 0);
101 | assertEquals(repos.get(0).getFullName(), demoUser.getUsername() + "/" + demoRepo.getName());
102 |
103 | // unknown user returns empty set
104 | List emptyRepos = api.listRepos(fakeUser);
105 | assertEquals(emptyRepos.size(), 0);
106 | }
107 |
108 | public void test08GetRepo() throws Exception {
109 | int limit = 2;
110 | List repos = api.searchRepos("d", 0, limit);
111 | Repository repo = api.getRepo(repos.get(0), adminUser);
112 | assertNotNull(repo);
113 | assertFalse(repo.getHtmlUrl().equals(""));
114 | }
115 |
116 | public void test09DeleteRepo() throws Exception {
117 | assertTrue(api.deleteRepo(demoRepo, demoUser));
118 | assertEquals(api.listRepos(demoUser).size(), 0);
119 |
120 | // unknown user is an error
121 | assertFalse(api.deleteRepo(demoRepo, fakeUser));
122 | assertEquals(api.getLastResponse().code, 401);
123 |
124 | // unknown repo is an error
125 | Repository fakeRepo = new Repository("fake-repository", "", false);
126 | assertFalse(api.deleteRepo(fakeRepo, demoUser));
127 | assertEquals(api.getLastResponse().code, 404);
128 | }
129 |
130 | public void test10CreateToken() throws Exception {
131 | Token token = api.createToken(demoToken, demoUser);
132 | assertNotNull(token);
133 | assertEquals(token.getName(), demoToken.getName());
134 |
135 | Token badToken = api.createToken(demoToken, null);
136 | assertNull(badToken);
137 | }
138 |
139 | public void test11ListTokens() throws Exception {
140 | List tokens = api.listTokens(demoUser);
141 | assertTrue(tokens.size() > 0);
142 | assertEquals(tokens.get(0).getName(), demoToken.getName());
143 |
144 | List badTokens = api.listTokens(fakeUser);
145 | assertEquals(badTokens.size(), 0);
146 | }
147 |
148 | public void test12GetUserWithToken() throws Exception {
149 | List tokens = api.listTokens(demoUser);
150 | assertTrue(tokens.size() > 0);
151 | demoUser.token = tokens.get(0);
152 | demoUser.password = null;
153 |
154 | User foundUser = api.getUser(demoUser, adminUser);
155 | assertNotNull(foundUser);
156 | assertTrue(!foundUser.email.isEmpty());
157 | }
158 |
159 | public void test13CreatePublicKey() throws Exception {
160 | PublicKey key = api.createPublicKey(demoKey, demoUser);
161 | assertNotNull(key);
162 | assertEquals(key.getTitle(), demoKey.getTitle());
163 | }
164 |
165 | public void test14ListPublicKeys() throws Exception {
166 | List keys = api.listPublicKeys(demoUser);
167 | assertTrue(keys.size() > 0);
168 | assertEquals(keys.get(0).getTitle(), demoKey.getTitle());
169 | }
170 |
171 | public void test15GetPublicKey() throws Exception {
172 | // get key id first
173 | List keys = api.listPublicKeys(demoUser);
174 | PublicKey key = new PublicKey(keys.get(0).getId());
175 |
176 | PublicKey fetchedKey = api.getPublicKey(key, demoUser);
177 | assertNotNull(fetchedKey);
178 | assertEquals(fetchedKey.getTitle(), demoKey.getTitle());
179 | }
180 |
181 | public void test16DeletePublicKey() throws Exception {
182 | // get key id first
183 | List keys = api.listPublicKeys(demoUser);
184 | PublicKey key = new PublicKey(keys.get(0).getId());
185 |
186 | assertTrue(api.deletePublicKey(key, demoUser));
187 | assertEquals(api.listPublicKeys(demoUser).size(), 0);
188 | }
189 |
190 | public void test17DeleteUser() throws Exception {
191 | // users cannot delete themselves
192 | assertFalse(api.deleteUser(demoUser, demoUser));
193 |
194 | // delete user
195 | assertTrue(api.deleteUser(demoUser, adminUser));
196 | assertNull(api.getUser(demoUser, adminUser));
197 |
198 | // unknown user is an error on delete
199 | assertFalse(api.deleteUser(fakeUser, adminUser));
200 | assertEquals(api.getLastResponse().code, 404);
201 | }
202 | }
--------------------------------------------------------------------------------
/gogs-client/src/main/java/org/unfoldingword/gogsclient/GogsAPI.java:
--------------------------------------------------------------------------------
1 | package org.unfoldingword.gogsclient;
2 |
3 | import android.util.Base64;
4 |
5 | import org.json.JSONArray;
6 | import org.json.JSONException;
7 | import org.json.JSONObject;
8 |
9 | import java.io.BufferedInputStream;
10 | import java.io.ByteArrayOutputStream;
11 | import java.io.DataOutputStream;
12 | import java.io.InputStream;
13 | import java.io.UnsupportedEncodingException;
14 | import java.net.HttpURLConnection;
15 | import java.net.URL;
16 | import java.util.ArrayList;
17 | import java.util.List;
18 |
19 | import javax.net.ssl.HttpsURLConnection;
20 |
21 | public class GogsAPI {
22 |
23 | private int readTimeout = 5000;
24 | private int connectionTimeout = 5000;
25 | private final String baseUrl;
26 | private Response lastResponse = null;
27 |
28 | /**
29 | * Creates an instance of the api client
30 | * @param apiUrl the api end point e.g. "https://try.gogs.io/api/v1"
31 | */
32 | public GogsAPI(String apiUrl) {
33 | this.baseUrl = apiUrl.replaceAll("/+$", "") + "/";
34 | }
35 |
36 | /**
37 | * Returns the last reponse from the api
38 | * @return
39 | */
40 | public Response getLastResponse() {
41 | return this.lastResponse;
42 | }
43 |
44 | /**
45 | * Changes the read timeout
46 | * @param timeout
47 | */
48 | public void setReadTimeout(int timeout) {
49 | this.readTimeout = timeout;
50 | }
51 |
52 | /**
53 | * Sets the connection timeout
54 | * @param timeout
55 | */
56 | public void setConnectionTimeout(int timeout) {
57 | this.connectionTimeout = timeout;
58 | }
59 |
60 | /**
61 | * Performs a request against the api
62 | * @param partialUrl
63 | * @param user
64 | * @param postData if not null the request will POST the data otherwise it will be a GET request
65 | * @return
66 | */
67 | private Response request(String partialUrl, User user, String postData) {
68 | return request(partialUrl, user, postData, null);
69 | }
70 |
71 | /**
72 | * Performs a request against the api
73 | * @param partialUrl the api command
74 | * @param user the user authenticating this request. Requires token or username and pasword
75 | * @param postData if not null the request will POST the data otherwise it will be a GET request
76 | * @param requestMethod if null the request method will default to POST or GET
77 | * @return
78 | */
79 | private Response request(String partialUrl, User user, String postData, String requestMethod) {
80 | int responseCode = -1;
81 | String responseData = null;
82 | Exception exception = null;
83 | try {
84 | URL url = new URL(this.baseUrl + partialUrl.replaceAll("^/+", ""));
85 | HttpURLConnection conn;
86 | if(url.getProtocol().equals("https")) {
87 | conn = (HttpsURLConnection)url.openConnection();
88 | } else {
89 | conn = (HttpURLConnection)url.openConnection();
90 | }
91 | if(user != null) {
92 | String auth = encodeUserAuth(user);
93 | if(auth != null) {
94 | conn.addRequestProperty("Authorization", auth);
95 | }
96 | }
97 | conn.setRequestProperty("Content-Type", "application/json");
98 | conn.setReadTimeout(this.readTimeout);
99 | conn.setConnectTimeout(this.connectionTimeout);
100 |
101 | // custom request method
102 | if(requestMethod != null) {
103 | conn.setRequestMethod(requestMethod.toUpperCase());
104 | }
105 |
106 | if(postData != null) {
107 | // post
108 | if(requestMethod == null) {
109 | conn.setRequestMethod("POST");
110 | }
111 | conn.setDoOutput(true);
112 | DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
113 | dos.writeBytes(postData);
114 | dos.flush();
115 | dos.close();
116 | }
117 |
118 | responseCode = conn.getResponseCode();
119 |
120 | if(isRequestMethodReadable(conn.getRequestMethod())) {
121 | // read response
122 | InputStream is = conn.getInputStream();
123 | BufferedInputStream bis = new BufferedInputStream(is);
124 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
125 | int current;
126 | while ((current = bis.read()) != -1) {
127 | baos.write((byte) current);
128 | }
129 | responseData = baos.toString("UTF-8");
130 | }
131 | } catch (Exception e) {
132 | exception = e;
133 | }
134 | this.lastResponse = new Response(responseCode, responseData, exception);
135 | return this.lastResponse;
136 | }
137 |
138 | /**
139 | * Checks if the request method is one that will return content
140 | * @param method
141 | * @return
142 | */
143 | private boolean isRequestMethodReadable(String method) {
144 | switch(method.toUpperCase()) {
145 | case "DELETE":
146 | case "PUT":
147 | return false;
148 | default:
149 | return true;
150 | }
151 | }
152 |
153 | /**
154 | * Generates the authentication parameter for the user
155 | * Preference will be given to the token if it exists
156 | * @param user
157 | * @return
158 | */
159 | private String encodeUserAuth(User user) {
160 | if(user != null) {
161 | if(user.token != null) {
162 | return "token " + user.token;
163 | } else if(user.getUsername() != null && !user.getUsername().isEmpty()
164 | && user.getPassword() != null && !user.getPassword().isEmpty()) {
165 | String credentials = user.getUsername() + ":" + user.getPassword();
166 | try {
167 | return "Basic " + Base64.encodeToString(credentials.getBytes("UTF-8"), Base64.NO_WRAP);
168 | } catch (UnsupportedEncodingException e) {
169 | e.printStackTrace();
170 | }
171 | }
172 | }
173 | return null;
174 | }
175 |
176 | /**
177 | * Creates a new user account
178 | * @param user the user to be created. Requires username, email, password
179 | * @param authUser the user authenticating this request. Requires token or username and password
180 | * @param notify send notification email to user
181 | * @return the newly created user
182 | */
183 | public User createUser(User user, User authUser, boolean notify) {
184 | if(user != null) {
185 | JSONObject json = new JSONObject();
186 | try {
187 | json.put("username", user.getUsername());
188 | json.put("email", user.email);
189 | json.put("password", user.getPassword());
190 | json.put("send_notify", notify);
191 | if(user.fullName != null) {
192 | json.put("full_name", user.fullName);
193 | }
194 | Response response = request("/admin/users", authUser, json.toString());
195 | if(response.code == 201 && response.data != null) {
196 | return User.fromJSON(new JSONObject(response.data));
197 | }
198 | } catch (JSONException e) {
199 | e.printStackTrace();
200 | }
201 | }
202 | return null;
203 | }
204 |
205 | /**
206 | * Edits the details on an existing user account
207 | * @param user the user who's information will be updated. Requires username (note: the username cannot be changed)
208 | * @param authUser the user authenticating this request. Requires token or username and password
209 | * @return the updated user user
210 | */
211 | public User editUser(User user, User authUser) {
212 | if(user != null) {
213 | try {
214 | Response response = request("/admin/users/" + user.getUsername(), authUser, user.toJSON().toString(), "PATCH");
215 | if(response.code == 200 && response.data != null) {
216 | return User.fromJSON(new JSONObject(response.data));
217 | }
218 | } catch (JSONException e) {
219 | e.printStackTrace();
220 | }
221 | }
222 | return null;
223 | }
224 |
225 | /**
226 | * Deletes a user
227 | * @param user the user to delete. Requires username
228 | * @param authUser the user to authenticate as. Users cannot delete themselves. Requires token or username and password
229 | * @return true if the request did not encounter an error
230 | */
231 | public boolean deleteUser(User user, User authUser) {
232 | if(user != null && authUser != null && !user.getUsername().equals(authUser.getUsername())) {
233 | Response response = request(String.format("/admin/users/%s", user.getUsername()), authUser, null, "DELETE");
234 | if(response.code == 204) {
235 | return true;
236 | }
237 | }
238 | return false;
239 | }
240 |
241 | /**
242 | * Searches for users that match the query
243 | * @param query
244 | * @param limit the maximum number of results to return
245 | * @param authUser the user authenticating the request. If null the email fields will be empty in the result. Requires token or username and password
246 | * @return an array of users
247 | */
248 | public List searchUsers(String query, int limit, User authUser) {
249 | List users = new ArrayList<>();
250 | if(query != null && !query.trim().isEmpty()) {
251 | Response response = request(String.format("/users/search?q=%s&limit=%d", query, limit), authUser, null);
252 | if(response.code == 200 && response.data != null) {
253 | try {
254 | JSONObject json = new JSONObject(response.data);
255 | if(json.has("ok") && json.getBoolean("ok")) {
256 | JSONArray data = json.getJSONArray("data");
257 | for (int i = 0; i < data.length(); i++) {
258 | User u = User.fromJSON(data.getJSONObject(i));
259 | if (u != null) {
260 | users.add(u);
261 | }
262 | }
263 | }
264 | } catch (JSONException e) {
265 | e.printStackTrace();
266 | }
267 | }
268 | }
269 | return users;
270 | }
271 |
272 | /**
273 | * Retrieves a user
274 | * @param user the user to retrieve. Requires username
275 | * @param authUser the user to authenticate as. if null the email field in the response will be empty. Requires token or username and password
276 | * @return the found user object
277 | */
278 | public User getUser(User user, User authUser) {
279 | if(user != null) {
280 | Response response = request(String.format("/users/%s", user.getUsername()), authUser, null);
281 | if(response.code == 200 && response.data != null) {
282 | try {
283 | return User.fromJSON(new JSONObject(response.data));
284 | } catch (JSONException e) {
285 | e.printStackTrace();
286 | }
287 | }
288 | }
289 | return null;
290 | }
291 |
292 | /**
293 | * Searches for public repositories that match the query
294 | * @param query
295 | * @param uid user whose repositories will be searched. 0 will search all
296 | * @param limit limit results to this quantity.
297 | * @return
298 | */
299 | public List searchRepos(String query, int uid, int limit) {
300 | List repos = new ArrayList<>();
301 | if(query != null && !query.trim().isEmpty()) {
302 | Response response = request(String.format("/repos/search?q=%s&uid=%d&limit=%d", query.trim(), uid, limit), null, null);
303 | if(response.code == 200 && response.data != null) {
304 | try {
305 | JSONObject json = new JSONObject(response.data);
306 | if(json.has("ok") && json.getBoolean("ok")) {
307 | JSONArray data = json.getJSONArray("data");
308 | for (int i = 0; i < data.length(); i++) {
309 | Repository repo = Repository.fromJSON(data.getJSONObject(i));
310 | if (repo != null) {
311 | repos.add(repo);
312 | }
313 | }
314 | }
315 | } catch (JSONException e) {
316 | e.printStackTrace();
317 | }
318 | }
319 | }
320 | return repos;
321 | }
322 |
323 | /**
324 | * Creates a new repository for the user
325 | * @param repo the repository being created. Requires name, description, private
326 | * @param user the user creating the repository. Requires token or username and password
327 | * @return
328 | */
329 | public Repository createRepo(Repository repo, User user) {
330 | if(repo != null && user != null) {
331 | JSONObject json = new JSONObject();
332 | try {
333 | json.put("name", repo.getName());
334 | json.put("description", repo.getDescription());
335 | json.put("private", repo.getIsPrivate());
336 | Response response = request("/user/repos", user, json.toString());
337 | if(response.code == 201 && response.data != null) {
338 | return Repository.fromJSON(new JSONObject(response.data));
339 | }
340 | } catch (JSONException e) {
341 | e.printStackTrace();
342 | }
343 | }
344 | return null;
345 | }
346 |
347 | /**
348 | * Returns a single repository
349 | * @param repo the repository to retreive
350 | * @param authUser the user to authenticate as. This does not have to be the owner of the repository
351 | * @return
352 | */
353 | public Repository getRepo(Repository repo, User authUser) {
354 | if(repo != null) {
355 | Response response = request("/repos/" + repo.getFullName(), authUser, null);
356 | if(response.code == 200 && response.data != null) {
357 | try {
358 | return Repository.fromJSON(new JSONObject(response.data));
359 | } catch (JSONException e) {
360 | e.printStackTrace();
361 | }
362 | }
363 | }
364 | return null;
365 | }
366 |
367 | /**
368 | * Lists all repositories that are accessible to the user
369 | * @param user the user who's repositories will be listed. Requires token or username and password
370 | * @return
371 | */
372 | public List listRepos(User user) {
373 | List repos = new ArrayList<>();
374 | if(user != null) {
375 | Response response = request("/user/repos", user, null);
376 | if(response.code == 200 && response.data != null) {
377 | try {
378 | JSONArray data = new JSONArray(response.data);
379 | for(int i = 0; i < data.length(); i ++) {
380 | Repository repo = Repository.fromJSON(data.getJSONObject(i));
381 | if(repo != null) {
382 | repos.add(repo);
383 | }
384 | }
385 | } catch (JSONException e) {
386 | e.printStackTrace();
387 | }
388 | }
389 | }
390 | return repos;
391 | }
392 |
393 | /**
394 | * Deletes a repository from the user
395 | * @param repo the repository to delete. Requires name
396 | * @param user the user that owns the repository. Requires token or username and password
397 | * @return true if the request did not encounter an error
398 | */
399 | public boolean deleteRepo(Repository repo, User user) {
400 | if(repo != null && user != null) {
401 | Response response = request(String.format("/repos/%s/%s", user.getUsername(), repo.getName()), user, null, "DELETE");
402 | if(response.code == 204) {
403 | return true;
404 | }
405 | }
406 | return false;
407 | }
408 |
409 | /**
410 | * Creates an authentication token for the user
411 | * @param token the token to be created. Requires name
412 | * @param user the user creating the token. Requires username, token or password
413 | * @return
414 | */
415 | public Token createToken(Token token, User user) {
416 | if(token != null && user != null) {
417 | JSONObject json = new JSONObject();
418 | try {
419 | json.put("name", token.getName());
420 | Response response = request(String.format("/users/%s/tokens", user.getUsername()), user, json.toString());
421 | if(response.code == 201 && response.data != null) {
422 | return Token.fromJSON(new JSONObject(response.data));
423 | }
424 | } catch (JSONException e) {
425 | e.printStackTrace();
426 | }
427 | }
428 | return null;
429 | }
430 |
431 | /**
432 | * Returns a list of tokens the user has
433 | * @param user the user who's tokens will be listed. Requires username, password
434 | * @return
435 | */
436 | public List listTokens(User user) {
437 | List tokens = new ArrayList<>();
438 | if(user != null) {
439 | Response response = request(String.format("/users/%s/tokens", user.getUsername()), user, null);
440 | if(response.code == 200 && response.data != null) {
441 | try {
442 | JSONArray data = new JSONArray(response.data);
443 | for(int i = 0; i < data.length(); i ++) {
444 | Token token = Token.fromJSON(data.getJSONObject(i));
445 | if(token != null) {
446 | tokens.add(token);
447 | }
448 | }
449 | } catch (JSONException e) {
450 | e.printStackTrace();
451 | }
452 | }
453 | }
454 | return tokens;
455 | }
456 |
457 | /**
458 | * Creates a public key for the user
459 | * @param key the key to be created. Requires title, key
460 | * @param user the user creating the key. Requires token or username and password
461 | * @return
462 | */
463 | public PublicKey createPublicKey(PublicKey key, User user) {
464 | if(key != null && user != null) {
465 | JSONObject json = new JSONObject();
466 | try {
467 | json.put("title", key.getTitle());
468 | json.put("key", key.getKey());
469 | Response response = request("/user/keys", user, json.toString());
470 | if (response.code == 201 && response.data != null) {
471 | return PublicKey.fromJSON(new JSONObject(response.data));
472 | }
473 | } catch (JSONException e) {
474 | e.printStackTrace();
475 | }
476 | }
477 | return null;
478 | }
479 |
480 | /**
481 | * Lists the public keys the user has
482 | * @param user the user who's public keys will be listed. Requires username, token or password
483 | * @return
484 | */
485 | public List listPublicKeys(User user) {
486 | List keys = new ArrayList<>();
487 | if(user != null) {
488 | Response response = request(String.format("/users/%s/keys", user.getUsername()), user, null);
489 | if(response.code == 200 && response.data != null) {
490 | try {
491 | JSONArray data = new JSONArray(response.data);
492 | for(int i = 0; i < data.length(); i ++) {
493 | PublicKey key = PublicKey.fromJSON(data.getJSONObject(i));
494 | if(key != null) {
495 | keys.add(key);
496 | }
497 | }
498 | } catch (JSONException e) {
499 | e.printStackTrace();
500 | }
501 | }
502 | }
503 | return keys;
504 | }
505 |
506 | /**
507 | * Returns the full details for a public key
508 | * @param key the key that will be retrieved. Requires id
509 | * @param user the user who's key will be returned. Requires token or username and password
510 | * @return
511 | */
512 | public PublicKey getPublicKey(PublicKey key, User user) {
513 | if(key != null && user != null) {
514 | Response response = request(String.format("/user/keys/%d", key.getId()), user, null);
515 | if(response.code == 200 && response.data != null) {
516 | try {
517 | return PublicKey.fromJSON(new JSONObject(response.data));
518 | } catch (JSONException e) {
519 | e.printStackTrace();
520 | }
521 | }
522 | }
523 | return null;
524 | }
525 |
526 | /**
527 | * Deletes a public key from the user
528 | * @param key the key that will be deleted. Requires id
529 | * @param user the user who's key will be deleted. Requires token or username and password
530 | * @return
531 | */
532 | public boolean deletePublicKey(PublicKey key, User user) {
533 | if(key != null && user != null) {
534 | Response response = request(String.format("/user/keys/%s", key.getId()), user, null, "DELETE");
535 | if(response.code == 204) {
536 | return true;
537 | }
538 | }
539 | return false;
540 | }
541 | }
542 |
--------------------------------------------------------------------------------