Browse Source

Created Token(s) and added missing 'Branch'. Also made updated to Lib\Client so we can do basic auth request

Joachim M. Giæver 6 years ago
parent
commit
e31346588d

File diff suppressed because it is too large
+ 469 - 208
README.md


+ 86 - 37
index.php

@@ -11,85 +11,111 @@ require "./src/gpac.php";
 
 use Gogs\Lib\Curl\Exception as ApiException;
 
+// API url
 define('API_URL', 'https://git.giaever.org/api/v1');
-//define('API_TOKEN', '142efbfd6fbdf147f03d289f8b22a438eaa1b5d1');
-define('API_TOKEN', 'e14b9eff0749b6f0c4cadf4bb72b83d44578ae28');
 
-$client =  new Gogs\API\Client(API_URL, API_TOKEN);
-
-try {
+// The token generated at Gogs
+define('API_TOKEN', '142efbfd6fbdf147f03d289f8b22a438eaa1b5d1');
 
-    $me = $client->user()->load();
+// Edit this one to your authorized accounts password to create tokens.
+define('USR_PASS', "mypassword");
 
-    $tester = "tester";
-    if (API_TOKEN == "142efbfd6fbdf147f03d289f8b22a438eaa1b5d1")
-        $tester = "joachimmg";
+// A known user (typically a test user) thats not the authorized one...
+define('KNOWN_USR', "tester");
 
-    $repos = $me->repos()->load();
+// Known word in repo to search for
+define("KNOWN_WORD", "dns");
 
-    $me->orgs()->load();
+$client =  new Gogs\API\Client(API_URL, API_TOKEN);
 
-    /*
-    $repo = $repos->get("gogs-php-api-client");
+try {
 
-    var_dump($repo->branches()->load());
+    /**
+     * TESTING
      */
 
+    $me = $client->user()->load();
+
+    echo "Authorized user: '" . $me->username . "'\n";
+
+    // Load every repo
+    $repos = $me->repos()->load(); 
+
+    // Loop through all of them in received order
     echo "\nNormal repo\n";
     foreach($repos->all() as $key => $repo)
         echo sprintf("* %s: %s\n", $key, $repo->name);
 
+    // Loop through repos sorted on created_at date
     echo "\nSorted created\n";
     foreach($repos->sort_by(Gogs\API\Request\Repos::SORT_CREATED)->all() as $key => $repo)
         echo sprintf("* %s: %s - %s\n", $repo->created_at, $key, $repo->name);
 
+    // Loop through repos sorted on created_at date, but ascending order
     echo "\nSorted created, then reversed\n";
     foreach($repos->sort_by(Gogs\API\Request\Repos::SORT_CREATED, true)->all() as $key => $repo)
         echo sprintf("* %s: %s - %s\n", $repo->created_at, $key, $repo->name);
 
+    // Loop from offset 1 (skip fist) then 10 repos (11th repos returned)
     echo "\nSorted Normal, offset 1, limit 10\n";
     foreach($repos->offset(1)->limit(10)->all() as $key => $repo)
         echo sprintf("* %s: %s\n", $key, $repo->name);
 
+    // Ensure repo order is still intact on $repos ... :)
+    // Theres returned a copy of "collection" each "sort"
     echo "\nNormal repo\n";
     foreach($repos->all() as $key => $repo)
         echo sprintf("* %s: %s\n", $key, $repo->name);
 
-    echo "\nSearch for in loaded data for 'dns', limit 10\n";
-    foreach($repos->search(array("name" => "dns", "limit" => 3))->all() as $key => $repo)
-        echo sprintf("* %s: %s\n", $key, $repo->name);
-
-    echo "\nSearch for in new data for 'dns', limit 10\n";
-    foreach($me->repos()->search(array("name" => "dns", "limit" => 3))->all() as $key => $repo)
+    // Look for a common search word, but max 10 entries
+    echo "\nSearch for in loaded data for '" . KNOWN_WORD . "', limit 10\n";
+    foreach($repos->search(array("name" => KNOWN_WORD, "limit" => 3))->all() as $key => $repo)
         echo sprintf("* %s: %s\n", $key, $repo->name);
-
-    echo "\nUsers->search name 't', offset 1:\n";
-    foreach($client->users()->search(array("name" => "to"))->offset(1)->all() as $key => $user)
+    
+
+    // Search for the two first letters of known user. 
+    // NOTE! Several users may start on these letters,
+    // and offset is 1 so another user that matches,
+    // may be returned.
+    $st = substr(KNOWN_USR, 0, 2);
+    echo "\nUsers->search name '" . $st . "', offset 1:\n";
+    foreach($client->users()->search(array("name" => $st))->offset(1)->all() as $key => $user)
        echo sprintf("* %s: %s\n", $key, $user->full_name); 
 
-    $user = $client->users()->get($tester);
+    $user = $client->users()->get(KNOWN_USR);
 
+    // Get public repos
     echo "\nUser '" . $user->username . "' public repos\n";
     foreach($user->repos()->load()->all() as $key => $repo)
         echo sprintf("* %s: %s\n", $key, $repo->name);
 
-    echo "\nUser '" . $me->username . "' public repos \n";
+    // Get authorized user's public repos; bug!
+    echo "\nUser '" . $me->username . "' public(nope, bug in Gogs....) repos \n";
     foreach($client->users()->get($me->username)->repos()->load()->all() as $key => $repo)
         echo sprintf("* %s: %s\n", $key, $repo->name);
 
-    echo "\nUsers '" . $me->username . "' organizations\n";
-    foreach($me->organizations()->load()->all() as $key => $org)
-        echo sprintf("* %s: %s\n", $key, $org->full_name);
-
+    // Get public organizations
     echo "\nUser '" . $user->username . "' public organizations\n";
     foreach($user->organizations()->load()->all() as $key => $org) {
         echo sprintf("* %s: %s\n* Repositories:\n", $key, $org->full_name);
-        
+
+        // Organization repos? Yes sir!
         foreach($org->repos()->load()->all() as $key => $repo)
             echo sprintf("#### %s: %s\n", $key, $repo->name);
     }
 
-    echo "Create data under specified user";
+    // Get authorized user's repos; BUG here too! :(
+    echo "\nUser '" . $me->username . "' public(nope, bug in Gogs....) organizations\n";
+    foreach($me->organizations()->load()->all() as $key => $org) {
+        echo sprintf("* %s: %s\n", $key, $org->full_name);
+
+        // Organization repos :)
+        foreach($org->repos()->load()->all() as $key => $repo)
+            echo sprintf("#### %s: %s\n", $key, $repo->name);
+    }
+
+    // Creating a test repo under authorized user
+    echo "Create data under specified user\n";
     $repo = $repos->create(
         "test-gogs-api-repo-" . $repos->load()->len(),
         "This is test repo #" . $repos->load()->len() . " created with Gogs PHP API Client",
@@ -98,13 +124,27 @@ try {
     );
     echo "Created repo " . $repo->name . "\n";
 
+    // Deleting this repo again.... And possibly others starting
+    // with this bogus prefix.
     echo "\nLooking up repos of test-test-test-#\n";
     foreach($repos->search(array("name" => "test-gogs-api-repo-"))->sort_by()->all() as $key => $repo)
-        echo sprintf("Deleting: '%s' %s\n", $repo->name, $repo->delete() ? "true" : "false");
+        echo sprintf("... and deleting test repo: '%s' %s\n", $repo->name, $repo->delete() ? "true" : "false");
 
+    // Load all of my organizations.
     $orgs = $me->orgs()->load();
 
+    /***
+     * NOW WE STARTS WITH METHODS THAT REQUIRES A TOKEN
+     * FOR AN AUTHORIZED USER THAT HAS ADMIN RIGHTS!
+     *
+     * Read exception carefully if you get one! ;)
+     */
+
     /*
+     * THIS IS LEFT OUT OF EVERY TEST, NO METHOD TO DELETE;
+     * ...other than manually. And its so boring to do this all
+     * the time....
+     * Uncomment to test...
     try {
         echo "\nCreate organization\n";
         $org = $orgs->create(
@@ -119,21 +159,30 @@ try {
     }
      */
 
+    // Look for a test organization
+    // NOTE! Most likely not showing up unless you
+    // uncomment stuff above.
     echo "\nLooking up organizations of test-" . $me->username . "\n";
     foreach($orgs->search(array("name" => "test-" . $me->username))->all() as $key => $org)
         echo sprintf("* '%s': %s\n", $key, $org->username);
 
-    $users = $client->users()->search(array("name" => "test-user"));
+    // Get users (without loading data!)
+    $users = $client->users();
 
-    $users->create(
-        "test-user-" . $users->len(),
-        "mytestuser" . $users->len() . "@gogitservice.joke"
+    // Create new user
+    $nuser = $users->create(
+        KNOWN_USR . "-" . $users->len(),
+        KNOWN_USR . $users->len() . "@gogitservice.joke"
     );
 
+    // Delete test users....
+    // Note! As this Users object isnt loaded (->load())
+    // the Users-Collection only contains 1 user 
+    // - the newly create one!
+    echo "Delete user '" . $nuser->username . "\n";
     foreach ($users->all() as $key => $user)
         echo sprintf("%s: delete %s\n", $key, $user->delete() ? "true" : "false");
 
-
     echo "\n\n\nLOG:\n" . join("\n", $client->get_log());
 
 } catch (ApiException\NotAuthorizedException $e) {

+ 1 - 0
src/API/Client.php

@@ -16,6 +16,7 @@ namespace Gogs\API {
 
     final class Client {
         use \Gogs\Lib\Curl\Client;
+        const VERSION = 0.1;
 
         /** 
          * @param string $api_url The base URL for the Gogs API (e.g https://git.domain.tld/api/v1) 

+ 2 - 0
src/API/Request/Base.php

@@ -13,6 +13,7 @@ namespace Gogs\API\Request {
      * @version 0.1.4
      */
     abstract class Base implements RequestInterface {
+        const VERSION = "0.1.4";
 
         private $tag;
 
@@ -241,6 +242,7 @@ namespace Gogs\API\Request {
                 else
                     echo "Unknown proerty " . $key . "\n";
             }
+
             $this->loaded = true;   
 
             return true;

+ 43 - 0
src/API/Request/Branch.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace Gogs\API\Request {
+
+    /** 
+     * A single Branch
+     *
+     * @author Joachim M. Giaever (joachim[]giaever.org)
+     * @version 0.1
+     */
+    final class Branch extends Base {
+        private $repo;
+
+        public $branch_name;
+        public $branch_commit;
+
+        /** 
+         * Initialize a branch for the given repository.
+         *
+         * @see Base
+         * @param Repo $repo 
+         */
+        public function __construct(string $api_url, string $api_token, Repo $repo) {
+            parent::__construct($api_url, $api_token);
+            $this->repo = $repo;
+        }
+
+        /**
+         * @see Base
+         */
+        protected function set_scope(string $method) {
+            switch ($method) {
+            case "load":
+                $this->scope = sprintf("/repos/%s/%s/branches/%s", $this->repo->owner, $this->repo->name, $this->name);
+                return true;
+            }
+            return false;
+        }
+    }
+
+}
+
+?>

+ 77 - 0
src/API/Request/Token.php

@@ -0,0 +1,77 @@
+<?php
+
+namespace Gogs\API\Request {
+
+    /** 
+     * A token related to a user
+     *
+     * Supports:
+     *  * POST `/users/{username}/tokens`
+     *
+     * Note! Tokens doesnt have a "GET" method. @see Tokens
+     * as this can load them.
+     * 
+     * @author Joachim M. Giaever (joachim[]giaever.org)
+     * @version 0.1.1
+     */
+    final class Token extends Base {
+        const VERSION = "0.1.1";
+        protected $owner;
+
+        public $token_name;
+        public $token_sha1;
+
+        /** 
+         * Initializes a token
+         * 
+         * @see Base
+         * @param User $user 
+         */
+        public function __construct(string $api_url, string $password, User $user) {
+            parent::__construct($api_url, $password);
+
+            if (!$user->email)
+                $user->load();
+
+            $this->basic($user->email);
+            $this->owner = $user;
+        }
+
+        /** 
+         * @see Base
+         */
+        protected function set_scope(string $method) {
+            switch ($method) {
+            case "create":
+                $this->scope = sprintf("/users/%s/tokens", $this->owner->username);
+                return true;
+            }
+
+            return false;
+        }
+
+        /** 
+         * Create a new token
+         *
+         * Valid parameters:
+         *
+         *  1. name
+         *
+         *  This reflects the API v1 documentation.
+         *
+         *  @param ...$args The parameter values
+         *  @return bool
+         */
+        public function create(...$args) {
+            $params = array(
+                "name" => isset($args[0]) && is_string($args[0]) ? $args[0] : null
+            );
+
+            $params = array_filter($params, function($val) {
+                return $val != null;
+            });
+
+            return parent::create($params);
+        }
+    }
+}

+ 159 - 0
src/API/Request/Tokens.php

@@ -0,0 +1,159 @@
+<?php
+
+namespace Gogs\API\Request {
+
+    /** 
+     * Collection of tokens for a given user.
+     *
+     * Supports:
+     *  * GET `/users/{username}/tokens`
+     * 
+     * @author Joachim M. Giaever (joachim[]giaever.org)
+     * @version 0.1.1
+     */
+    final class Tokens extends Collection {
+        const VERSION = "0.1.1";
+
+        private $owner;
+
+        /** 
+         * Initialize a token collection.
+         * 
+         * @see Base
+         * @param User $user Owner of tokens
+         */
+        public function __construct(string $api_url, string $password, User $user) {
+            parent::__construct($api_url, $password);
+
+            if (!$user->email)
+                $user->load();
+        
+            $this->basic($user->email);
+            $this->owner = $user;
+        }
+
+        /** 
+         * @see Base
+         */
+        protected function set_scope(string $method) {
+            switch ($method) {
+            case "load":
+                $this->scope = sprintf("/users/%s/tokens", $this->owner->username);
+                return true;
+            }
+
+            return false;
+        }
+
+        /** 
+         * Create a new token.
+         *
+         * Returns a new token object. If arguments is specified the "token"
+         * will be created. 
+         *
+         * Arguments can be left empty to "create" the token, leaving
+         * the programmer to call create on the token object with the arguments
+         * itself, to create it.
+         *
+         * Creating the token through this function will store the function in
+         * the collection. If not created, it wont be added, and collection
+         * must be reloaded (`->load(true)`)  to add it.
+         *
+         * @see Token
+         * @return Token
+         */
+        public function create(...$args) {
+
+            $token = new Token($this->url, $this->token, $this->owner);
+
+            if (count($args) != 0) {
+                $token->create(...$args);
+                $this->add($token, $token->name);
+            }
+
+            return $token;
+        }
+
+        /** 
+         * @see Collection
+         */
+        protected function add_object(\stdClass $obj) {
+            $token = new Token($this->url, $this->token, $this->owner);
+            $token->json_set_property($obj);
+            return $this->add($token, $token->name);
+        }
+
+        /** 
+         * Return a token by name
+         *
+         * @return Token
+         */
+        public function get(string $s) {
+            if ($token = $this->by_key($s))
+                return $token;
+
+            $token = (new Token($this->url, $this->token, $this->owner))->load();
+            
+            $this->add($token, $token->name);
+
+            return $token;
+        }
+
+        /**
+         * Search for a token.
+         *
+         * Params can be an array of 
+         * ```php
+         * $orgs->search(array(
+         *  "name"  => "name",      // alt. "q". required
+         *  "limit" => 10,          // not required, default: 10
+         * ));
+         * ```
+         * By now, this method can be intensive, as it will load
+         * every token and then do a match on each entry.
+         *
+         * @see Base
+         * @see Collection
+         * @throws Exception\SearchParamException on missing parameters
+         * @return Token
+         */
+        public function search(array $params = array(), bool $strict = false) {
+
+            if (!isset($params["name"]) && !isset($params["q"]))
+                throw new Exception\SearchParamException("Missing parameter <name|q>");
+
+            if (!isset($params["name"])) {
+                $params["name"] = $params["q"];
+                unset($params["q"]);
+            }
+
+            if (!isset($params["limit"]))
+                $params["limit"];
+
+            if (!$this->loaded)
+                $this->load();
+
+            $tokens = new Tokens($this->url, $this->token, $this->owner);
+
+            foreach ($this->all() as $key => $token) {
+
+                if ($token->search(array("name" => $params["name"]), $strict))
+                    $tokens->add($token, $token->name);
+
+                if ($tokens->len() == $params["limit"])
+                    break;
+
+            }
+
+            return $tokens;
+
+        }
+
+        /**
+         * @see Collection
+         */
+        public function sort_by(int $flag = Collection::SORT_INDEX) {
+            return $this->sort("ksort");
+        }
+    }
+}

+ 5 - 1
src/API/Request/User.php

@@ -172,7 +172,11 @@ namespace Gogs\API\Request {
                 return $val != null;
             });
 
-            parent::create($params);
+            return parent::create($params);
+        }
+
+        public function tokens(string $password) {
+            return new Tokens($this->url, $password, $this);
         }
 
     }

+ 1 - 1
src/API/Request/Users.php

@@ -38,7 +38,7 @@ namespace Gogs\API\Request {
          */
         public function create(...$args) {
 
-            $user = new User($this->url, $this->token, "-");
+            $user = new User($this->url, $this->token);
 
             if (count($args) != 0) {
                 $user->create(...$args);

+ 25 - 8
src/Lib/Curl/Client.php

@@ -7,18 +7,30 @@ namespace Gogs\Lib\Curl {
      *
      * @author Joachim M. Giaever (joachim[]giaever.org)
      * @package curl
-     * @version 0.1.2
+     * @version 0.1.3
      */
     trait Client {
+        private $_version = "0.1.3";
+
         private static $log = array();
 
         protected $url;
         protected $token;
+        protected $basic = false;
 
-        protected $user_agent = "Gogs PHP Api Curl\\Client/0.1 (compatible; LINUX)";
+        protected $user_agent = "Gogs PHP API Client/%s (%s) PHP/%s Client\\%s %s";
         protected $timeout = 30;
         protected $max_redirects = 4;
 
+        /** 
+         * Basic sets the user for basic HTTP-authentication.
+         *
+         * @param string $user 
+         */
+        public function basic(string $user) {
+            $this->basic = $user;
+        }
+
         /** 
          * array_2_params takes an array and converts it into a
          * query string (e.g param=val&param2=val2).
@@ -66,21 +78,26 @@ namespace Gogs\Lib\Curl {
                 return false;
             }
 
-            $headers = array(
-                sprintf("Authorization: token %s", $this->token),
-            );
+            $headers = array();
 
             $url = sprintf("%s%s", $this->url, $scope);
 
+            curl_setopt($c, CURLOPT_USERAGENT, $agent = sprintf($this->user_agent, $this->_version, PHP_OS, phpversion(), get_class($this), self::VERSION));
+
             self::$log[] = sprintf(
                 "%s:[%s] %s, %s, %s", 
                 date("y-m-d H:i:s"), 
                 $method, 
                 $url, 
                 !empty($p = $this->array_2_json($params)) ? $p : "none",
-                get_class($this)
+                $agent
             );
 
+            if (!$this->basic)
+                $headers[] = sprintf("Authorization: token %s", $this->token);
+            else
+                curl_setopt($c, CURLOPT_USERPWD, sprintf("%s:%s", $this->basic, $this->token));
+
             if (in_array($method, array("DELETE", "PATCH", "POST"))) {
                 $json = $this->array_2_json($params);
                 curl_setopt($c, CURLOPT_CUSTOMREQUEST, $method);
@@ -88,10 +105,10 @@ namespace Gogs\Lib\Curl {
                 array_unshift($headers, "Content-Type: application/json");
                 array_push($headers, "Content-Length: " . strlen($json));
             } else {
-                $url .= "?" . $this->array_2_params($params);
+                $url .= !empty($params = $this->array_2_params($params)) ? "?" . $params : "";
             }
 
-            curl_setopt($c, CURLOPT_USERAGENT, $this->user_agent);
+
             curl_setopt($c, CURLOPT_URL, $url);
             curl_setopt($c, CURLOPT_HTTPHEADER, $headers);
             curl_setopt($c, CURLOPT_RETURNTRANSFER, $ret);

Some files were not shown because too many files changed in this diff